场景与目标
- 服务器:京东云 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) 服务器侧准备基础依赖:
curl、tar、ca-certificates、socat、cron(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.com、www.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.<主域名>的反代配置 - 不需要为每个服务容器单独挂载证书,也不需要每个服务单独续期。
