用 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_baidu

acme.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 --staging

2. 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,真正实现“一次配置,长期不管”。

如果你也在用百度云的免费证书被手动续期困扰,不妨试试这条路。

正文到此结束
  • 本文作者:xinyu.he
  • 文章标题:给 WEB 站点换上自动续期的免费 HTTPS 证书
  • 本文地址:https://www.hxy.bj.cn/archives/835/
  • 版权说明:若无注明,本文皆Xinyu.he blog原创,转载请保留文章出处。
最后修改:2026 年 11 月 09 日
如果觉得我的文章对你有用,请随意赞赏