CertIntel for acme.sh¶
dns_certintel.sh publishes and removes DNS-01 TXT challenge values through
CertIntel. acme.sh handles certificate orders, keys, certificate files and
renewal. This plugin does not install certificates or enroll a CertIntel agent.
Requires acme.sh 3.x (tested with 3.1.6) on Linux, BSD or macOS with a POSIX
sh, curl or wget, and openssl, the same tools acme.sh itself needs.
The plugin is a single file in acme.sh's native DNS API script format and uses
acme.sh DNS alias mode: CertIntel delegated DNS-01 works through a permanent
CNAME from _acme-challenge.<domain> to the delegation's target, and
--domain-alias tells acme.sh to publish and check the TXT record at that
target instead of in your own zone.
Setup is four steps: create a delegation in CertIntel, download the script into
the acme.sh home, export five variables, and run acme.sh --issue.
1. Create the delegation and CNAME¶
In CertIntel, open Delegated DNS-01 and create a delegation for the certificate name. Save three values from the result:
| Value | Used as |
|---|---|
| Delegation UUID | CERTINTEL_DELEGATION_ID |
| Update secret | CERTINTEL_API_KEY |
Full CNAME target, e.g. abc123.dns01.certin.tel |
CERTINTEL_CNAME_TARGET and --domain-alias |
At your DNS provider, add the permanent CNAME that CertIntel shows you:
Wait until the CNAME resolves publicly before issuing. With Cloudflare, use
DNS only (no proxy). example.com and *.example.com share one delegation.
Other names such as www.example.com need their own delegation and CNAME.
2. Install the plugin¶
Download the latest script into the acme.sh home directory, where acme.sh looks
for custom DNS API scripts. The release record at
https://api.certin.tel/api/v1/releases/plugin-acme-sh/latest.json points at the
current version and carries its SHA-256, so nothing below hardcodes a version:
RELEASE_JSON=$(curl -fsSL https://api.certin.tel/api/v1/releases/plugin-acme-sh/latest.json)
SCRIPT_URL=$(printf '%s' "$RELEASE_JSON" | grep -o '"url":"[^"]*"' | head -1 | cut -d'"' -f4)
SCRIPT_SHA256=$(printf '%s' "$RELEASE_JSON" | grep -o '"sha256":"[^"]*"' | head -1 | cut -d'"' -f4)
curl -fsSL "$SCRIPT_URL" -o "$HOME/.acme.sh/dns_certintel.sh"
echo "$SCRIPT_SHA256 $HOME/.acme.sh/dns_certintel.sh" | sha256sum -c -
chmod 600 "$HOME/.acme.sh/dns_certintel.sh"
sha256sum must print OK. If it does not, delete the file and download again.
On macOS use shasum -a 256 -c - in place of sha256sum -c -.
Use the actual acme.sh home if it was installed with --home. Keeping the
script outside dnsapi/ prevents acme.sh --upgrade from touching it. The
script is sourced by acme.sh, so it does not need to be executable. To upgrade
later, run the same block again. See Downloads for the record format.
3. Configure the first delegation¶
Settings are environment variables on the first issuance. acme.sh then saves them in its account configuration (mode 600) and reuses them for renewals, so no environment is needed later. Values must not contain whitespace or line breaks.
export CERTINTEL_DOMAIN='example.com'
export CERTINTEL_DELEGATION_ID='11111111-1111-1111-1111-111111111111'
export CERTINTEL_CNAME_TARGET='YOUR-LABEL.dns01.certin.tel'
export CERTINTEL_API_KEY='YOUR-DELEGATION-UPDATE-SECRET'
export CERTINTEL_API_BASE='https://api.certin.tel/api/v1'
| Variable | Meaning |
|---|---|
CERTINTEL_DOMAIN |
Certificate domain without *. or _acme-challenge. |
CERTINTEL_DELEGATION_ID |
Delegation UUID |
CERTINTEL_CNAME_TARGET |
Full CNAME target shown by CertIntel |
CERTINTEL_API_KEY |
Delegation update secret |
CERTINTEL_API_BASE |
Optional. HTTPS endpoint including /api/v1; default https://api.certin.tel/api/v1. For a dedicated tenant use https://YOUR-TENANT.app.certin.tel/api/v1 |
CERTINTEL_LOCK_DIR |
Optional absolute lock directory; default .certintel-locks in the acme.sh home |
4. Issue the certificate¶
--domain-alias must be the CNAME target exactly, without _acme-challenge.
(--challenge-alias would add that prefix and does not match a CertIntel
delegation). One alias given once applies to every -d on the command line.
For an apex/wildcard pair add -d '*.example.com' (quoted, to prevent shell
expansion). acme.sh verifies the TXT values publicly before asking the CA;
--dnssleep 60 replaces that check with a fixed wait. To rehearse first, add
--staging; a staging certificate is not publicly trusted.
acme.sh stores the certificate under its home directory and remembers the
DNS API and alias for renewal. Use --install-cert or a --reloadcmd to deploy
it; certificate deployment is a separate task. Unset the variables afterwards;
the saved account configuration carries them. A shell that still exports them
simply overrides the saved values for that run.
Multiple delegations¶
Give every list the same number of entries in the same order. The API key and endpoint may be a single shared value or one per domain:
export CERTINTEL_DOMAIN='example.com www.example.com'
export CERTINTEL_DELEGATION_ID='11111111-1111-1111-1111-111111111111 22222222-2222-2222-2222-222222222222'
export CERTINTEL_CNAME_TARGET='FIRST-LABEL.dns01.certin.tel SECOND-LABEL.dns01.certin.tel'
export CERTINTEL_API_KEY='FIRST-SECRET SECOND-SECRET'
acme.sh --issue --dns dns_certintel \
-d example.com --domain-alias FIRST-LABEL.dns01.certin.tel \
-d '*.example.com' --domain-alias FIRST-LABEL.dns01.certin.tel \
-d www.example.com --domain-alias SECOND-LABEL.dns01.certin.tel
acme.sh pairs each --domain-alias with the -d at the same position. Mappings
are exact: the plugin matches the record name acme.sh passes against each
configured CNAME target (or _acme-challenge.<domain>), and a parent domain
never covers a child.
Renewal¶
acme.sh renews from its cron job using the saved settings. To exercise the saved configuration without touching the production certificate:
A CA may reuse valid authorizations, so a renewal does not always publish a new
TXT challenge. To rotate a key, export the new CERTINTEL_API_KEY (and every
other list, if you use per-domain keys) and run one issuance or forced renewal;
the plugin saves the new values on that run.
Locks and limits¶
The plugin holds one lock per delegation while it reads and rewrites the TXT
set, in .certintel-locks under the acme.sh home or CERTINTEL_LOCK_DIR.
A lock left behind by a crashed run is reclaimed once that process has exited.
Use one issuing client/host per delegation: the lock cannot serialize another
host, the dedicated CertIntel agent, or dashboard edits, and CertIntel replaces
the whole TXT set with at most two values.
The plugin accepts only DNS-01 digests. It refuses API redirects, sends the key
only as the X-Api-Key header to the configured HTTPS endpoint, and reports
HTTP status without echoing response bodies or keys. TXT values that are not
plain printable ASCII (never the case for ACME digests) are rejected rather
than rewritten. IDNs must be written in punycode.
Troubleshooting¶
Run with --debug for the plugin's diagnostics; the key is masked unless
--output-insecure is given.
| Symptom | Check |
|---|---|
sha256sum reports FAILED |
The download is corrupt or incomplete; delete the script and download again. Do not use it. |
| No exact delegation mapping | --domain-alias must equal CERTINTEL_CNAME_TARGET; add the exact certificate name to CERTINTEL_DOMAIN. |
| supply matching CERTINTEL_DOMAIN... | Every list needs one entry per domain in the same order. |
| API 401/403 | Check the update secret, delegation status and endpoint. |
| API 404 or CNAME mismatch | Check the delegation UUID, endpoint and full CNAME target. |
| answered with a redirect | The endpoint is wrong; the plugin never follows redirects with the key. |
| Delegation already has two TXT values | Another issuer or stale values; do not clear another active challenge. |
| DNS check never succeeds | Check the permanent CNAME and public propagation; try --dnssleep. |
| timed out acquiring delegation lock | Another acme.sh run holds the delegation; wait, or remove the named lock directory if no run is active. |
After a crash or cleanup failure, confirm that no issuance is active, then remove stale values in CertIntel before retrying.
See also the acme.sh DNS alias mode and DNS API guides.