Skip to content

Certbot has a ReadTimeout error if finalization takes >45 seconds with Sectigo's ACME #22

@markjonestx

Description

@markjonestx

Hello! I deployed your acme-proxy in our DC to experiment and see if it would allow me to issue trusted certs to our semi-air-gapped network, but our Certbot-based clients are unfortunately timing out waiting for a response. Our acme.sh clients do not have the issue.

The Testing Environment:

  • acme-proxy directly from the main branch, commit 7f7f416
  • certbot 3.1.0 on an EL9.7 box
  • ACME Proxy running on a EL10.1 box
  • InCommon's "Universal ACME" provider

The command I used was on the EL9.7 box is:

certbot certonly -d <domain_scrubbed> --webroot -w /var/lib/acme-challenge/ --cert-name incommon --server https://<acme_proxy>/acme/acme/directory --agree-tos --email <email_scrubbed> --non-interactive

When the error first occurred, I tried to add --issuance-timeout 10000 to Certbot, but it doesn't seem to affect the socket timeout.

Here's the logs on the ACME Proxy

2026/04/03 00:45:03 [INFO] acme: Registering account for <email_scrubbed>
2026/04/03 00:45:03 INFO processing certificate request domains=[<domain_scrubbed>]
2026/04/03 00:45:03 [INFO] [<domain_scrubbed>] acme: Obtaining bundled SAN certificate given a CSR
2026/04/03 00:45:18 [INFO] [<domain_scrubbed>] AuthURL: https://acme.enterprise.sectigo.com/authorization/<scrubbed>/0/always-valid
2026/04/03 00:45:18 [INFO] [<domain_scrubbed>] acme: authorization already valid; skipping challenge
2026/04/03 00:45:18 [INFO] [<domain_scrubbed>] acme: Validations succeeded; requesting certificates
2026/04/03 00:45:30 [INFO] Wait for certificate [timeout: 30s, interval: 500ms]

# <- Here is where Certbot times out

2026/04/03 00:46:07 [INFO] [<domain_scrubbed>] Server responded with a certificate.
2026/04/03 00:46:07 INFO obtained certificate from external CA domains=[<domain_scrubbed>]

The error from Certbot's log:

Traceback (most recent call last):
  File "/bin/certbot", line 8, in <module>
    sys.exit(main())
  File "/usr/lib/python3.9/site-packages/certbot/main.py", line 19, in main
    return internal_main.main(cli_args)
  File "/usr/lib/python3.9/site-packages/certbot/_internal/main.py", line 1873, in main
    return config.func(config, plugins)
  File "/usr/lib/python3.9/site-packages/certbot/_internal/main.py", line 1579, in certonly
    lineage = _get_and_save_cert(le_client, config, domains, certname, lineage)
  File "/usr/lib/python3.9/site-packages/certbot/_internal/main.py", line 142, in _get_and_save_cert
    lineage = le_client.obtain_and_enroll_certificate(domains, certname)
  File "/usr/lib/python3.9/site-packages/certbot/_internal/client.py", line 518, in obtain_and_enroll_certificate
    cert, chain, key, _ = self.obtain_certificate(domains)
  File "/usr/lib/python3.9/site-packages/certbot/_internal/client.py", line 452, in obtain_certificate
    cert, chain = self.obtain_certificate_from_csr(csr, orderr)
  File "/usr/lib/python3.9/site-packages/certbot/_internal/client.py", line 342, in obtain_certificate_from_csr
    orderr = self.acme.finalize_order(
  File "/usr/lib/python3.9/site-packages/acme/client.py", line 279, in finalize_order
    self.begin_finalization(orderr)
  File "/usr/lib/python3.9/site-packages/acme/client.py", line 230, in begin_finalization
    res = self._post(orderr.body.finalize, wrapped_csr)
  File "/usr/lib/python3.9/site-packages/acme/client.py", line 370, in _post
    return self.net.post(*args, **kwargs)
  File "/usr/lib/python3.9/site-packages/acme/client.py", line 743, in post
    return self._post_once(*args, **kwargs)
  File "/usr/lib/python3.9/site-packages/acme/client.py", line 755, in _post_once
    response = self._send_request('POST', url, data=data, **kwargs)
  File "/usr/lib/python3.9/site-packages/acme/client.py", line 652, in _send_request
    response = self.session.request(method, url, *args, **kwargs)
  File "/usr/lib/python3.9/site-packages/requests/sessions.py", line 544, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python3.9/site-packages/requests/sessions.py", line 657, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python3.9/site-packages/requests/adapters.py", line 702, in send
    raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='<acme_proxy>', port=443): Read timed out. (read timeout=45)
2026-04-03 00:45:33,204:ERROR:certbot._internal.log:An unexpected error occurred:
2026-04-03 00:45:33,204:ERROR:certbot._internal.log:requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='<acme_proxy>', port=443): Read timed out. (read timeout=45)

After rg-ing my way through Certbot's code and skimming the RFC, I think what is happening is that Certbot expects a { "status": "processing" } response with an optional Retry-After header set to some amount of time while the server waits for a certificate to generate.

I think the specific function is poll_finalization in Certbot's acme/src/acme/client.py:

277             elif body.status == messages.STATUS_PROCESSING:
278                 # "processing": The certificate is being issued.  Send a POST-as-GET request after
279                 # the time given in the Retry-After header field of the response, if any.
280                 retry_after = self.retry_after(response, 1)
281                 # Whatever Retry-After the ACME server requests, the polling must not take
282                 # longer than the overall deadline
283                 retry_after = min(retry_after, deadline)
284                 sleep_seconds = (retry_after - datetime.datetime.now()).total_seconds()

If you need any additional information, just let know! Thank you for putting this project together!

Metadata

Metadata

Assignees

Labels

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions