项目/网络基础设施
网络基础设施 · 运行中

全站 HTTPS 与证书自动续期

NPM + certbot 自动签发/续期泛域名证书,所有自建服务统一 HTTPS。

Let's EncryptNPMcertbotHTTPS

它是什么

这是我 Homelab 的证书与 HTTPS 统一层:NPM(Nginx Proxy Manager)做反代入口,certbot 负责签发和续期,所有自建服务的对外域名共用同一张 Let's Encrypt 证书。

为什么做

体检时发现原来两张证书的续期流程都已失效:一张用 manual + 手工加 TXT,certbot renew 直接 exit 1;另一张用 standalone,但 80/443 全被 NPM 容器占着,必然失败。也就是说 12-31 一过,全站 HTTPS 就会开始报证书错误。域名是在 e8hk 买的,手上没有 Cloudflare 面板的 API Token,通配符必须的 DNS-01 无人值守这条路走不通。

怎么解决

改成 HTTP-01 文件验证 + webroot:在 NPM 的 80 端口 server 块里加 /.well-known/acme-challenge/ 挑战目录(共 7 处),证书只覆盖目前真正有公网 A 记录的 6 个域名,证书名保持 xiejun-server.top 不变,NPM 配置一行都没改。新证书签到 2027-01-11,certbot renew --dry-run 演练通过,certbot.timer 每天自动跑。

现状

运行中。唯一的代价是丢了通配符,只影响外网没解析的内部名字,而这些服务本来就是路径式访问,实际无感;以后加子域名,DNS 补好 A 记录后跑一条命令就能扩容证书。

功能

  • 13 个主页入口 + 6 个公网域名走真实公网链路做全量体检,逐项核对状态码、TLS 与 HSTS
  • 把失效的 manual/standalone 续期方式改为 HTTP-01 webroot 文件验证,续期重新可无人值守
  • 在 NPM 的 80 端口 server 块内加 ACME 挑战目录,证书名不变、反代配置零改动
  • certbot.timer 每天自动续期,并用 --dry-run 演练验证整条链路
  • 顺带定位并修掉 .223 走 8.8.8.8 导致的偶发十秒级卡顿,改用本机 unbound 分流
  • 留了完整的备份与回退路径:nginx 配置、certbot renewal 配置、resolv.conf 快照

技术栈

Let's EncryptNginx Proxy ManagercertbotHTTP-01 / webrootsystemd timerunboundDocker

使用 / 部署教程

前置条件

  • 域名已添加公网 A 记录并指向入口 IP(HTTP-01 验证只能签发有 A 记录的域名,通配符做不到)。
  • 80 端口由 NPM 占用,所以不能走 standalone,必须走 webroot。

步骤

1. 建挑战目录并挂进 NPM 容器

mkdir -p /data/acme-webroot/.well-known/acme-challenge

确认这个路径已挂载到 NPM 容器内同一位置,并确保容器内可读。

2. 在 NPM 的 80 端口 server 块加挑战 location

每个需要签发的站点(含 1.conf、9-shared-hosts.conf 等共享配置)都要加上:

location ^~ /.well-known/acme-challenge/ {
    root /data/acme-webroot;
    default_type text/plain;
}

改完 reload NPM,先用 curl http://<域名>/.well-known/acme-challenge/test 确认能读到文件。

3. 签发证书

证书名沿用旧的那张,这样 NPM 里的引用一行都不用动:

certbot certonly --webroot -w /data/acme-webroot \
  --cert-name xiejun-server.top \
  -d xiejun-server.top -d memory.xiejun-server.top -d photo.xiejun-server.top \
  -d dsh.xiejun-server.top -d ledger.xiejun-server.top -d video.xiejun-server.top

只把真正有公网 A 记录的域名写进来,多余的域名会导致验证失败。

4. 演练与自动续期

certbot renew --dry-run
systemctl enable --now certbot.timer
systemctl list-timers | grep certbot

演练全部通过再收工,别只看到“签发成功”就完事。

5. 新增子域名扩容

DNS 补好 A 记录后,在入口机上跑:

bash /root/add-subdomain-cert.sh newsite.xiejun-server.top

6. 回退

nginx 配置备份在 /root/cert-http01-bak-*,certbot renewal 配置备份在 /root/renewal-xiejun-server.top.conf.bak-*,覆盖回去并 reload 即可恢复原状。

注意

  • 为了能让 HTTP-01 无人值守续期,这张证书不再包含通配符,只覆盖有公网 A 记录的名字;新增子域名必须先补 DNS A 记录再扩容证书。
  • 入口机的系统盘写入速度已降到 5.9 MB/s(此前宕机就是它),证书和配置都在上面,换盘前建议随时保持可回退的备份。
  • .223 的 DNS 已改走本机 unbound 并用 NetworkManager 配置锁定,升级或改网络时要确认没被改回 8.8.8.8,否则十秒级卡顿会重现。