配置自动更新证书流程


场景与目标

  • 服务器:京东云 ECS(Ubuntu 22.04)
  • DNS:域名在腾讯云解析
  • 证书:Let’s Encrypt
  • 架构:所有外网 80/443 入口由 Docker 容器 nginx-proxy 统一接入与反向代理(HTTPS 终止在网关层)
  • 目标:
  • 自动签发:主域名 + 泛域名 (*.主域名)
  • 自动续期:到期前自动完成 DNS-01 验证并续签
  • 自动部署:续期后自动将新证书部署到 nginx-proxy 并 reload 生效

一、准备条件

1) 域名必须处于正常可用状态(及时续费,避免过期导致续签失败)。

2) 腾讯云侧准备 DNS API 密钥(CAM):

  • 生成 SecretId / SecretKey
  • 授权至少包含修改 DNS 记录(添加/删除 TXT)的权限

3) 服务器侧准备基础依赖:

  • curltarca-certificatessocatcron(DNS-01 + acme.sh 常用依赖)
  • 服务器能访问 Let’s Encrypt 的 ACME 接口
  • 若 GitHub 访问不稳定,可用国内镜像源(如 Gitee)拉取 acme.sh

二、安装 acme.sh(解决 GitHub 下载不稳定)

在大陆网络环境里,GitHub 下载常超时。可以改用 Gitee 镜像安装:

apt update
apt install -y git ca-certificates socat cron
update-ca-certificates

cd /root
git clone --depth 1 https://gitee.com/neilpang/acme.sh.git /root/acme.sh-src
cd /root/acme.sh-src
./acme.sh --install \
  --home /root/acme.sh \
  --config-home /root/.acme.sh \
  --accountemail <你的邮箱>

验证安装:

/root/acme.sh/acme.sh --version

三、配置 Let’s Encrypt 为默认 CA

acme.sh 可能默认使用其他 CA(如 ZeroSSL)。显式切到 Let’s Encrypt:

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

四、配置腾讯云 DNS API(敏感信息不要写进命令历史)

将密钥写入仅 root 可读文件(占位符替换):

cat > /root/.tencent_dns_api <<'EOF'
export Tencent_SecretId="<SECRET_ID>"
export Tencent_SecretKey="<SECRET_KEY>"
EOF
chmod 600 /root/.tencent_dns_api

五、签发泛域名证书(DNS-01)

加载密钥环境变量并签发:

source /root/.tencent_dns_api

/root/acme.sh/acme.sh --issue --server letsencrypt \
  --dns dns_tencent \
  -d <主域名> -d '*.<主域名>' \
  --dnssleep 120

说明:

  • -d <主域名> 用于根域(例如 example.com
  • -d '*.<主域名>' 用于所有子域(例如 api.example.comwww.example.com
  • --dnssleep 用于等待 TXT 记录生效,DNS 慢可改成 300/600

签发成功后,证书文件会在类似路径中生成:

  • /root/.acme.sh/<主域名>_ecc/fullchain.cer
  • /root/.acme.sh/<主域名>_ecc/<主域名>.key

六、将证书自动部署到 Docker 网关 nginx-proxy(关键:统一入口)

本方案的核心是:只让 nginx-proxy 使用证书,其他服务容器走内网 HTTP,由 nginx-proxy 统一提供 HTTPS。

1)确认 nginx-proxy 的证书目录挂载

通过 Docker inspect 可看到类似映射:

  • 宿主机:/home/<用户>/my-server/nginx-proxy/ssl
  • 容器内:/etc/nginx/ssl

且 Nginx 配置使用:

  • ssl_certificate /etc/nginx/ssl/cert.pem;
  • ssl_certificate_key /etc/nginx/ssl/key.pem;

2)用 acme.sh 安装证书到 nginx-proxy 对应宿主机目录,并设置自动 reload

mkdir -p /home/<用户>/my-server/nginx-proxy/ssl
chmod 700 /home/<用户>/my-server/nginx-proxy/ssl

/root/acme.sh/acme.sh --install-cert -d <主域名> \
  --key-file /home/<用户>/my-server/nginx-proxy/ssl/key.pem \
  --fullchain-file /home/<用户>/my-server/nginx-proxy/ssl/cert.pem \
  --reloadcmd "docker exec nginx-proxy nginx -s reload"

chmod 600 /home/<用户>/my-server/nginx-proxy/ssl/key.pem \
          /home/<用户>/my-server/nginx-proxy/ssl/cert.pem

要点:

  • fullchain-file 必须是 fullchain(含中间证书),兼容性最好
  • --reloadcmd 是“自动生效”的关键:续期成功后自动热加载 nginx-proxy

3)手动验证 nginx 配置并 reload

docker exec nginx-proxy nginx -t
docker exec nginx-proxy nginx -s reload

七、自动续期是如何发生的(cron)

安装 acme.sh 时会自动为 root 写入 crontab 定时任务,例如:

  • 每天固定时间运行 acme.sh --cron
  • 它会检查证书是否进入续期窗口(一般到期前约 30 天)
  • 若需要续期,会自动执行:
  • 调用腾讯云 DNS API 添加/验证/删除 TXT 记录
  • 向 Let’s Encrypt 申请新证书
  • 写入你在 --install-cert 指定的证书路径
  • 执行 --reloadcmd(例如 reload nginx-proxy)

检查定时任务与证书状态:

crontab -l | grep acme
/root/acme.sh/acme.sh --list

列表中会显示下一次进入续期窗口的时间(Renew Time)。


八、验证线上证书有效期(无需依赖腾讯云控制台)

服务器本机验证(查看签发者/有效期):

echo | openssl s_client -servername <主域名> -connect 127.0.0.1:443 2>/dev/null \
  | openssl x509 -noout -issuer -subject -dates

也可以浏览器访问站点,点击锁标志查看证书到期时间。


九、扩展:以后新增更多 Docker 服务怎么做?

因为使用的是“统一入口网关 + 泛域名证书”:

  • 新增服务只需:
  • 新增一个 DNS 解析记录(如 api.<主域名> 指向服务器)
  • 在 nginx-proxy 的 conf.d 增加一个 server_name api.<主域名> 的反代配置
  • 不需要为每个服务容器单独挂载证书,也不需要每个服务单独续期。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注