用 acme.sh + Let's Encrypt 给 Nginx 站点换上自动续期的免费 HTTPS 证书
之前站点一直用百度云签发的 TrustAsia DV 免费证书,3 个月一到期就得去控制台手动续费、下载、替换、重载 Nginx,实在麻烦。更关键的是,这类证书不支持 ACME 协议,没法做自动化续期。
于是干脆换成了 Let's Encrypt,用 acme.sh 配合百度云 DNS API 验证,实现了从签发到续期的全自动。这篇记录一下完整过程,给同样被手动续期折磨的朋友参考。
为什么换 Let's Encrypt
- 完全免费:非营利组织 ISRG 运营,不收费。
- 原生支持 ACME:可以用
acme.sh、Certbot 等工具自动签发和续期,这是解决手动续期痛点的关键。 - 浏览器信任:和商业 DV 证书在信任级别上没有实质差别,普通网站加密完全够用。
- 有效期 90 天:看起来短,但配合自动化工具反而更安全,续期完全无感。
原来那张 TrustAsia 证书的问题不在于“不安全”,而在于不支持 ACME,自动化无从谈起。
环境说明
- 服务器:Nginx
- 域名:
www.hxy.bj.cn - 站点根目录:
/typecho_www/www/html/typecho - DNS 托管:百度云
- 验证方式:DNS API(
dns_baidu),不依赖 80 端口,不受 301 跳转和防火墙影响
选 DNS 验证是因为 HTTP 验证容易踩坑:80 端口如果配了 301 跳 HTTPS,Let's Encrypt 验证请求可能被跳走;部分云厂商的墙也可能拦截验证 IP。DNS 验证直接加一条 TXT 记录,稳得多。
第一步:安装 acme.sh
cd /root
curl -O https://get.acme.sh
sh get.acme.sh email=你的邮箱@example.com
source /root/.bashrc验证安装:
/root/.acme.sh/acme.sh --version如果提示 command not found,别慌,直接用绝对路径 /root/.acme.sh/acme.sh 执行后续命令即可,alias 没生效不影响使用。
第二步:切换默认 CA
acme.sh 默认 CA 是 ZeroSSL,需要手动切到 Let's Encrypt:
/root/.acme.sh/acme.sh --set-default-ca --server letsencrypt第三步:准备百度云 DNS 凭据
去百度云控制台创建 Access Key,拿到 Access Key ID 和 Secret Access Key,然后导出环境变量:
export Baidu_AK="你的AccessKeyID"
export Baidu_SK="你的SecretAccessKey"前提是域名 hxy.bj.cn 的 DNS 解析确实托管在百度云,否则 dns_baidu 模式会失败。
第四步:签发证书
/root/.acme.sh/acme.sh --issue -d www.hxy.bj.cn --dns dns_baiduacme.sh 会自动调百度云 API 添加 _acme-challenge TXT 记录,验证通过后自动删除。看到日志里出现 Cert success. 就成功了,证书文件在:
/root/.acme.sh/www.hxy.bj.cn_ecc/
├── www.hxy.bj.cn.cer
├── www.hxy.bj.cn.key
├── ca.cer
└── fullchain.cer日志里还会有一行 Next renewal time picked from ARI window,显示下次自动续期时间,我这次是 2027 年 1 月 7 日左右。
第五步:安装证书并绑定自动重载
这一步很关键,--install-cert 会把证书复制到 Nginx 目录,并记住续期后要执行的命令:
mkdir -p /etc/nginx/ssl
/root/.acme.sh/acme.sh --install-cert -d www.hxy.bj.cn --ecc \
--key-file /etc/nginx/ssl/www.hxy.bj.cn.key \
--fullchain-file /etc/nginx/ssl/www.hxy.bj.cn.pem \
--reloadcmd "systemctl reload nginx"注意 --ecc 不能漏,因为签发的是 ECC 证书。--reloadcmd 会在每次自动续期成功后自动执行,这样新证书生效后 Nginx 立刻加载,不用人工干预。
第六步:修改 Nginx 配置
原来配置里引用的是 /root/ssl/ 下的旧证书,替换成新路径:
ssl_certificate /etc/nginx/ssl/www.hxy.bj.cn.pem;
ssl_certificate_key /etc/nginx/ssl/www.hxy.bj.cn.key;
# 删掉 ssl_trusted_certificate 那行,fullchain 已包含中间证书测试并重载:
nginx -t && systemctl reload nginx第七步:验证
用 openssl 看 Nginx 实际加载的证书:
echo | openssl s_client -connect www.hxy.bj.cn:443 -servername www.hxy.bj.cn 2>/dev/null | openssl x509 -noout -issuer -dates正确输出应该是:
issuer=C = US, O = Let's Encrypt, CN = YE1
notBefore=Nov 9 12:21:17 2026 GMT
notAfter=Feb 7 12:21:16 2027 GMT如果 issuer 还是 TrustAsia,说明配置没生效或 Nginx 没重载,检查一下 grep ssl_certificate 的输出。
再确认自动续期的 cron 任务存在:
crontab -l | grep acme正常会看到类似:
45 5,11,17,23 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null每天检查 4 次,到期前约 30 天自动续签并重载 Nginx,之后基本不用再管了。
几个踩过的坑
1. acme.sh 不支持 --dry-run
那是 Certbot 的参数。想测试签发链路又不影响生产证书,用 staging 环境:
/root/.acme.sh/acme.sh --issue -d www.hxy.bj.cn --dns dns_baidu --staging2. curl -O 报错 Failed writing received data
这是本地写入失败,不是网络问题,先查 df -h 看磁盘空间。如果 curl -O 不行,改用管道方式 curl https://get.acme.sh | sh -s email=...。
3. HTTP 验证被 301 跳转拦截
如果坚持用 webroot 验证,80 端口配置里要让 .well-known/acme-challenge/ 路径不走跳转,直接返回静态文件,否则验证请求会被 301 到 HTTPS,而那时证书可能还没生效,陷入鸡生蛋问题。DNS 验证可以完全绕开这个坑。
4. 证书切换后 openssl 还显示旧证书
--install-cert 只是把文件复制过去,Nginx 还得 reload 才会重新读取。改完配置一定要 nginx -t && systemctl reload nginx,再用 openssl 验证。
小结
整套流程跑下来,核心就三件事:DNS API 签发 → --install-cert 绑定 reloadcmd → Nginx 指向新证书。配好之后,90 天有效期不再是负担,cron 会自动在到期前续签并重载 Nginx,真正实现“一次配置,长期不管”。
如果你也在用百度云的免费证书被手动续期困扰,不妨试试这条路。