ACME clients and automation
acme.sh wildcard certificates with the Alibaba Cloud DNS or DNSPod API
acme.sh issues a Let's Encrypt wildcard certificate for example.com and *.example.com by writing DNS-01 TXT records through the Alibaba Cloud DNS or DNSPod API, so no inbound port has to be open. It then installs the certificate for Nginx and renews and reloads it on its own.
The steps apply to acme.sh 3.1.4 and later on any Linux server, including BT Panel hosts, NAS boxes and internal machines.
Which hook to use
Pick the hook by where the domain's DNS is hosted, not by where the server runs.
- Alibaba Cloud DNS (China site or international account):
dns_ali. The hook calls thealidns.aliyuncs.comAPI; acme.sh's wiki does not separate the two account types, so make your first run with--staging. - DNSPod through Tencent Cloud:
dns_tencentwith Tencent Cloud API keys. This is the recommended option because CAM can limit the keys to DNSPod. - DNSPod.cn with an old DNSPod token:
dns_dp, kept for existing setups. - DNSPod.com, the international DNSPod service:
dns_dpi.
Prerequisites
The only external requirement is API access to the domain's DNS.
- The domain's DNS hosted at Alibaba Cloud DNS, Tencent Cloud DNSPod (dnspod.cn) or DNSPod.com, with the domain's NS records pointing there.
- A Linux server with outbound internet access, and root or a user that can reload the web server.
- Alibaba Cloud: in RAM, create a RAM user with OpenAPI access, attach the
AliyunDNSFullAccesspolicy (full access to Alibaba Cloud DNS and nothing else), and create an AccessKey. - Tencent Cloud: in Cloud Access Management (CAM), create a sub-user with DNSPod permissions only, and create a SecretId/SecretKey pair.
- DNSPod.com: the API ID and token from your DNSPod.com account.
- Never use the root account's keys.
- If the certificate is for a website hosted in the Chinese mainland: DNS-01 issuance itself needs no ICP filing, but serving the site from the mainland still does, and providers there block or take down websites on unfiled domains.
Step 1: Install acme.sh
Install acme.sh with the official script, then switch its default CA to Let's Encrypt. On most servers:
curl https://get.acme.sh | sh -s email=admin@example.com
On servers in mainland China where GitHub downloads are slow, the acme.sh wiki documents installing from its Gitee mirror:
git clone https://gitee.com/neilpang/acme.sh.git
cd acme.sh
./acme.sh --install -m admin@example.com
Log in again or run source ~/.bashrc, then switch the default CA from ZeroSSL (the default since acme.sh v3.0) to Let's Encrypt:
acme.sh --set-default-ca --server letsencrypt
Step 2: Export the DNS API keys
acme.sh reads the API keys from environment variables whose names depend on the provider. Alibaba Cloud DNS:
export Ali_Key="your-access-key-id"
export Ali_Secret="your-access-key-secret"
Tencent Cloud DNSPod:
export Tencent_SecretId="your-secret-id"
export Tencent_SecretKey="your-secret-key"
DNSPod.com (international):
export DPI_Id="your-api-id"
export DPI_Key="your-api-token"
After the first successful issuance acme.sh saves the keys in ~/.acme.sh/account.conf and reuses them for renewals.
Step 3: Issue the wildcard certificate
Run --issue with the hook for your DNS provider and both names, the apex and the wildcard:
acme.sh --issue --dns dns_ali -d example.com -d '*.example.com' # Alibaba Cloud DNS
acme.sh --issue --dns dns_tencent -d example.com -d '*.example.com' # Tencent Cloud DNSPod
acme.sh --issue --dns dns_dpi -d example.com -d '*.example.com' # DNSPod.com
acme.sh adds the _acme-challenge TXT records, waits, completes validation and deletes the records. If validation fails because the records have not reached every authoritative server yet, add --dnssleep 120 to wait longer. For a first test, add --staging so failed attempts do not count against Let's Encrypt's production limits. To get Let's Encrypt's 45-day tlsserver certificates, add --cert-profile tlsserver; see Let's Encrypt certificate profiles.
Step 4: Install the certificate and set the reload command
--install-cert copies the certificate to a stable path and stores the reload command that acme.sh runs after every renewal:
mkdir -p /etc/nginx/ssl
acme.sh --install-cert -d example.com --ecc \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.fullchain.pem \
--reloadcmd "systemctl reload nginx"
Point Nginx at the two files:
ssl_certificate /etc/nginx/ssl/example.com.fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
On BT Panel, point --key-file and --fullchain-file at the site's certificate directory, set --reloadcmd to the panel's Nginx reload command (for example /etc/init.d/nginx reload, depending on the installation), and turn off the panel's own renewal for that site; see BT Panel SSL.
Verify
The apex and any subdomain should present the same certificate, with example.com and *.example.com in its SAN list. Check them with the SSL checker, or from any terminal:
curl ssl.sh/example.com
curl ssl.sh/www.example.com
Locally:
acme.sh --list
openssl x509 -in /etc/nginx/ssl/example.com.fullchain.pem -noout -ext subjectAltName -enddate
Automatic renewal
The installer adds a cron job that runs acme.sh --cron. Since release 3.1.4 it runs every 6 hours and renews within the window published through ACME Renewal Information (ARI, RFC 9773); set NO_ARI=1 to disable that. Since 3.1.5 an explicit --days or --valid-to takes precedence over the ARI window. After each renewal acme.sh repeats the install step and runs --reloadcmd. To check or trigger it:
crontab -l | grep acme.sh
acme.sh --cron --home ~/.acme.sh
acme.sh --upgrade --auto-upgrade
Let's Encrypt's default certificates change to 64 days on February 10, 2027 and 45 days on February 16, 2028; because acme.sh follows ARI, no configuration change is needed. Renewal fails if the RAM or CAM keys are disabled or deleted, and Let's Encrypt no longer sends expiry emails, so add the domain to ssl.sh monitoring (in development).
Troubleshooting
- InvalidAccessKeyId / Forbidden.RAM (Alibaba Cloud): wrong AccessKey, or the RAM user lacks DNS permissions; check the attached policy.
- AuthFailure / UnauthorizedOperation (Tencent Cloud): wrong SecretId/SecretKey, or the sub-user lacks DNSPod permissions.
- Verify error: no TXT record found: the record has not reached all authoritative servers (use
--dnssleep 120), or the domain's NS records point to a different provider than the hook you used. See acme.sh verify error. - CAA record prevents issuance: CAA must allow
letsencrypt.org; see CAA record prevents issuance. - Rate limit reached: repeated test issuances; use
--staging, see Let's Encrypt rate limits. - acme.sh asks you to register an email with ZeroSSL: the default CA was not switched; run the
--set-default-ca --server letsencryptcommand from Step 1.
FAQ
DNSPod: dns_tencent, dns_dp or dns_dpi?
dns_tencent uses Tencent Cloud API keys (SecretId/SecretKey), whose permissions you can restrict in CAM; it is the recommended choice for DNSPod domains managed through Tencent Cloud. dns_dp uses the older DNSPod token from dnspod.cn (DP_Id, DP_Key). dns_dpi is for the international DNSPod.com service (DPI_Id, DPI_Key).
What if my DNS provider has no API?
Use acme.sh's DNS alias mode: add a CNAME from _acme-challenge.example.com to a validation-only domain hosted on Alibaba Cloud DNS or DNSPod, and issue with --challenge-alias <validation-domain>. The main domain's DNS never needs an API key.
Can the certificate be deployed to Alibaba Cloud CDN automatically?
Yes. acme.sh's ali_cdn deploy hook reuses Ali_Key/Ali_Secret and takes the CDN domain from DEPLOY_ALI_CDN_DOMAIN; after the first run it deploys on every renewal. See Alibaba Cloud CDN HTTPS.
Does dns_ali work with an Alibaba Cloud international account?
The hook calls the Alibaba Cloud DNS API endpoint alidns.aliyuncs.com, and acme.sh's wiki does not distinguish between China-site and international accounts. Test your keys once with --staging before relying on it in production.