Connect ACME clients to your HTTP APIs.
Core 0.2.1 · Certbot adapter 0.0.24 · Certbot and Dehydrated support.
Previously named certbot-httpreq. The repository builds two packages:
acme-http-connector is the client-independent core; certbot-httpreq is the
Certbot adapter and installs the core as a dependency. Certbot plugin names
remain unchanged. The core includes the Dehydrated HTTP-01 hook and can be
installed without Certbot. See ROADMAP.md.
The authenticator publishes and removes HTTP-01 challenges through a custom HTTP endpoint. The installer sends a certificate, private key and chain to an API on issuance and renewal. Certbot or Dehydrated performs ACME issuance; this connector does not run an ACME server or HTTP challenge server.
Python 3.10+ and Certbot 2.11–5.x are the supported target range. CI checks Certbot 2.11 and the latest available 5.x. Install the plugin in the same Python environment as Certbot; a separate pip environment does not extend a snap.
python -m pip install certbot-httpreq
certbot pluginsPyPI installation uses the last published release. To install from a source checkout:
python -m pip install -e packages/core -e .The core can be installed independently of Certbot:
python -m pip install acme-http-connectorIt exposes HTTPConnector.publish, cleanup, deploy and deploy_files.
See the core API example. The core also installs
acme-http-dehydrated, a hook for Dehydrated; Certbot is not required for it.
Installing the core alone does not issue certificates.
Copy certbot-httpreq.yml to
/etc/letsencrypt/certbot-httpreq.yml and configure your API endpoints.
certbot run \
--agree-tos --text --email admin@example.com \
-a certbot-httpreq:auth \
-i certbot-httpreq:installer \
-d example.comA different config file can be selected with
--certbot-httpreq:auth-config and --certbot-httpreq:installer-config, or
CBT_HTTPREQ_AUTH_CONFIG and CBT_HTTPREQ_INST_CONFIG.
The receiving service must expose the published challenge at
http://example.com/.well-known/acme-challenge/<token> for ACME validation.
The plugin also checks the challenge against the configured perform.uri
host and its explicit port (otherwise Certbot's HTTP-01 port), so that route
must serve the challenge too. The API write route and challenge read route
need not be the same.
The installed acme-http-dehydrated command supports Dehydrated 0.7.2 with
HTTP-01. It publishes and cleans challenges, including HOOK_CHAIN=yes
batches, and sends the issued leaf certificate, private key and chain to the
same deployment API. It does not implement DNS-01 or TLS-ALPN-01.
Install the core in its own environment (no Certbot dependency):
python3 -m venv /opt/acme-connector
/opt/acme-connector/bin/python -m pip install acme-http-connectorInstall Dehydrated separately. Copy certbot-httpreq.yml
to /etc/acme-http-connector.yml and configure your API endpoints. Restrict
access to configuration and certificate files to the account running the client.
The API must expose each challenge on the requested domain's HTTP-01 URL.
Add these settings to your Dehydrated configuration:
CHALLENGETYPE="http-01"
HOOK="/opt/acme-connector/bin/acme-http-dehydrated"
HOOK_CHAIN="yes"
WELLKNOWN="/var/lib/dehydrated/challenges"Create WELLKNOWN as a directory writable by the Dehydrated account: the client
still writes its local token files even though the hook publishes them remotely.
Keep your usual BASEDIR, DOMAINS_TXT, account and CA settings. Put the desired
certificate names in Dehydrated's domains.txt, then register and issue:
dehydrated --register --accept-terms
dehydrated --cronSubsequent --cron runs renew certificates when due. Test with a staging CA
and test API before production: staging certificates are also sent to the API.
A custom YAML path can be selected with ACME_HTTP_CONNECTOR_CONFIG; include
that environment variable in cron/service configuration too. The default is
/etc/acme-http-connector.yml. Existing CBT_HTTPREQ_<PHASE>_<OPTION> scalar
overrides also apply.
deploy_cert maps Dehydrated's key/cert/fullchain/chain arguments to the core's
cert/key/chain order. unchanged_cert does not deploy again. Unknown lifecycle
hooks succeed without action, as required by Dehydrated. Action hooks return
nonzero on invalid arguments, configuration, file or HTTP failures. Diagnostics
omit exception details because they can contain credentials. Check the affected
API and local configuration when a hook fails. A failed batch stops at the first
HTTP error; there is no automatic retry or rollback. An interrupted client or
partial API failure can leave published tokens requiring cleanup.
Each phase (perform, cleanup, deploy) has its own uri, path, method,
headers, format, timeout and verify options.
| Phase | Methods | Payload |
|---|---|---|
perform |
PUT, POST | Challenge validation, optionally under param_validation |
cleanup |
DELETE, PUT, POST | Challenge path in URL; no request body |
deploy |
POST, PUT, PATCH | domain, cert, key, chain |
format:jsonorform-urlencoded.param_challenge: optional query parameter name receiving the full challenge path, including/.well-known/acme-challenge/. Otherwise that path is appended to the configured API path.param_validation: optional body field name; without it JSON sends a string and form mode sends raw validation text.body_paramsindeploy: overrides the four deployment field names.headers: custom headers, including API authentication headers if needed.timeout: positive finite seconds, default 30. This is Requests' socket timeout, not a total operation deadline.verify: default true; a CA bundle path is also supported. Explicitfalsedisables TLS certificate verification.
Scalar settings can be supplied using CBT_HTTPREQ_<PHASE>_<OPTION>, for example
CBT_HTTPREQ_DEPLOY_TIMEOUT=15. Explicit nonempty YAML values take precedence;
missing/null values use environment values, then defaults. Environment timeout
values are parsed as numbers; verification accepts true/false, yes/no, on/off,
1/0 or a CA bundle path. Headers and body mappings are configured in YAML.
Use HTTPS for remote APIs, particularly deployment: the payload contains the private key. Protect the YAML file if it contains authentication headers.
certbot renew --dry-run
certbot renewRun dry runs against a test API first: challenge publication and cleanup are
real API calls. Deployment uses the first certificate name as domain, with
the complete certificate (including any SANs). HTTP errors propagate to Certbot.
Existing package/plugin names, paths, environment variables and deployment fields are retained. Python 2 and old Certbot interfaces are retired. Unset HTTP timeouts now default to 30 seconds; cleanup honors its own settings; invalid HTTP methods raise an error. See CHANGELOG.
Copyright © 2019–2026 Adrien Delle Cave. GPL-3.0-or-later.
HTTP redirects are refused for publish, cleanup and deployment. Configure the final API URL directly; redirects do not trigger another request or count as success.
- Users: installation, configuration, operation and API usage in this README and the user guide.
- Contributors: architecture, tests and development.