起因

一个测试用的域名,底下要挂一堆子域名:每个项目一个,随开随关。原来的做法是每建一个站就签一张单域名证书,很快就不可持续了——签发要人工点、续期要人工管,忘一个就是线上 HTTPS 失效。

通配证书 *.example.cn 能一次解决:签一张,所有子域名复用同一份证书文件,新建站点只要在 nginx 里指过去就行。

绕不开的前提:必须 DNS-01

Let’s Encrypt 的域名验证有三种方式,能签通配的只有一种:

验证方式怎么证明能签通配吗
HTTP-01http://域名/.well-known/acme-challenge/<token> 放一个文件不能
TLS-ALPN-01在 443 端口用特殊 ALPN 协议响应不能
DNS-01_acme-challenge.域名 加一条 TXT 记录

原因不难理解。HTTP-01 是「我能控制这个域名指向的那台服务器」——但 *.example.cn 代表无穷多个子域名,你没法对每一个都放文件,CA 也没法挑一个来验。DNS-01 验的是「我能改这个域名的 DNS 记录」,这才是对整个域名(含所有子域名)控制权的证明。

所以:想要通配证书,就必须能改 DNS。没有别的路。

两种改 DNS 的方式

acme.sh 支持这两种,区别只在续期:

手动模式——它打印出要加的 TXT 记录,你去 DNS 控制台加,回来继续:

acme.sh --issue --dns -d example.cn -d '*.example.cn' \
  --yes-I-know-dns-manual-mode-enough-go-ahead-please

那个又臭又长的参数名是故意的,它在提醒你:手动模式不能自动续期。60~90 天后到期,整套流程要人工重来一遍。

API 模式——把 DNS 服务商的 API 凭据给 acme.sh,它自己加记录、自己删:

export DP_Id="..." DP_Key="..."         # DNSPod 的示例,各家变量名不同
acme.sh --issue --dns dns_dp -d example.cn -d '*.example.cn'

凭据会存进 ~/.acme.sh/account.conf,之后全自动续期。

如果这是个要长期活着的站,直接上 API 模式。 手动模式适合「先验证流程能跑通」,但别指望三个月后的自己记得这回事。

两个实操细节

同名 TXT 记录是两条,不是一条。example.cn + *.example.cn 时,CA 会下发两个不同的 challenge,但主机记录名字都是 _acme-challenge。DNS 允许同名多条 TXT,你必须两条都加、并存。很多人加了第二条时把第一条覆盖掉了,然后验证失败。

提交前自己先查一遍。 Let’s Encrypt 对验证失败有频率限制,撞上了要等。加完记录别急着点继续,先确认权威 NS 上真的有了:

dig +short TXT _acme-challenge.example.cn @<权威NS>
dig +short TXT _acme-challenge.example.cn @8.8.8.8

两条值都出现,再去提交。多花二十秒,省掉被限流的风险。

acme.sh 默认 CA 不是 Let’s Encrypt

acme.sh 3.x 起默认 CA 是 ZeroSSL,不是 Let’s Encrypt。ZeroSSL 也能用,但它要 EAB 凭据、多一次账户注册,多一个续期时可能出问题的环节。如果你其它证书都是 LE,保持一致更省心:

acme.sh --set-default-ca --server letsencrypt

要换就在签之前换。 换 CA 会重新生成 challenge,签完再换等于前面加的 TXT 记录白加了。

装到位,顺便把续期钩子挂上

别手动拷贝 pem 文件。用 --install-cert,它会记住部署位置,续期后自动更新并执行 reload:

acme.sh --install-cert -d example.cn --ecc \
  --key-file       /path/to/cert/privkey.pem \
  --fullchain-file /path/to/cert/fullchain.pem \
  --reloadcmd      "nginx -s reload"

签完之后

确认一下拿到的确实是通配:

openssl x509 -in fullchain.pem -noout -subject -dates -ext subjectAltName

要看到 DNS:*.example.cn, DNS:example.cn 两个都在。

之后新增子域名就只剩一件事——写个 nginx server 块指向这份证书,reload。不用签发、不用等审核、不用点任何界面。

备份的时候记得校验配对

证书是签给域名的,跟服务器无关。换机器直接把 fullchain.pem + privkey.pem 拷过去就能继续用,不用重签。

但备份最怕的是存了一份对不上的证书和私钥,等到换机器那天才发现。校验很简单——两条命令的输出必须一致:

openssl x509 -in fullchain.pem -noout -pubkey | openssl md5
openssl pkey  -in privkey.pem  -pubout       | openssl md5

顺便把 ~/.acme.sh/ 里的账户密钥也一起备份,这样在新机器上能接着自动续期,不用重新注册 ACME 账户。