多台负载均衡服务器如何共享同一份 Let's Encrypt 续签证书文件?

文章导读
多台负载均衡服务器共享 Let's Encrypt 证书,最稳妥的做法是在单一控制节点完成续签,再通过安全通道分发到各节点,配合 DNS 挑战模式避免 HTTP 验证冲突。
📋 目录
  1. 核心风险与原理
  2. 前置准备:DNS 挑战配置
  3. 自动化同步与部署脚本
  4. 配置定时任务
  5. 验证与监控
  6. 常见坑与排查
  7. 参考来源
A A

多台负载均衡服务器共享 Let's Encrypt 证书,最稳妥的做法是在单一控制节点完成续签,再通过安全通道分发到各节点,配合 DNS 挑战模式避免 HTTP 验证冲突。

先说结论:避免每台机器独立续签,防止速率限制和文件不一致。

  • 适合:拥有多台后端或边缘节点的生产环境
  • 先准备:确定一台主续签机器和免密同步通道
  • 验收:所有节点证书日期一致且服务无中断

核心风险与原理

Let's Encrypt 默认每 90 天过期,续签频率高。如果每台负载均衡器都独立运行续签脚本,容易触发 API 速率限制(Rate Limits),导致续签失败。此外,HTTP 挑战要求请求必须落到运行续签脚本的那台机器,在多节点负载均衡环境下,请求可能被分发到其他节点,导致验证失败。

关键技术风险:

  • 软链接失效:Let's Encrypt 的 live 目录是软链接,指向 archive 目录。仅同步 live 会导致目标机器证书文件缺失,服务无法启动。
  • 权限错误:私钥文件(privkey.pem)权限若过于开放(如 644),Nginx 等服务会拒绝加载。
  • 服务中断:同步过程中若直接覆盖正在读取的文件,可能导致服务重载失败或短暂中断。

前置准备:DNS 挑战配置

在主续签节点上,建议使用 DNS-01 挑战模式,无需开放 80 端口。以下以 Cloudflare 为例:

1. 安装 DNS 插件

多台负载均衡服务器如何共享同一份 Let's Encrypt 续签证书文件?
# Ubuntu/Debian
apt install python3-certbot-dns-cloudflare

# 或使用 pip
pip install certbot-dns-cloudflare

2. 配置 API 凭证

创建凭证文件 ~/.cloudflare.ini,权限设为 600:

cat > ~/.cloudflare.ini <<EOF
dns_cloudflare_email = your_email@example.com
dns_cloudflare_api_key = YOUR_API_KEY
EOF
chmod 600 ~/.cloudflare.ini

3. 执行首次续签

certbot certonly `--dns-cloudflare` \
  `--dns-cloudflare-credentials` ~/.cloudflare.ini \
  -d your_domain.com -d *.your_domain.com \
  `--agree-tos` `--non-interactive`

自动化同步与部署脚本

在主节点创建部署脚本 /usr/local/bin/sync_cert.sh,该脚本包含备份、原子替换、权限修正及服务重载检查。

#!/bin/bash
set -e

DOMAIN="your_domain.com"
NODES=("user@lb-node-01" "user@lb-node-02")
LETSENCRYPT_PATH="/etc/letsencrypt"

echo "开始同步证书到节点..."

for NODE in "${NODES[@]}"; do
    echo "处理节点:$NODE"
    
    # 1. 同步整个 letsencrypt 目录,确保 archive 和 live 软链接完整
    rsync -avz `--delete` "$LETSENCRYPT_PATH/" "$NODE:$LETSENCRYPT_PATH/"
    
    # 2. 远程修正私钥权限,防止权限过大导致服务拒绝启动
    ssh "$NODE" "chmod 600 $LETSENCRYPT_PATH/live/$DOMAIN/privkey.pem"
    
    # 3. 远程检查配置并重载服务 (以 Nginx 为例)
    ssh "$NODE" "nginx -t && systemctl reload nginx"
    
    if [ $? -ne 0 ]; then
        echo "错误:节点 $NODE 重载失败,请检查日志!"
        exit 1
    fi
done

echo "所有节点证书同步并重载完成。"

脚本关键点说明:

多台负载均衡服务器如何共享同一份 Let's Encrypt 续签证书文件?
  • rsync `--delete`:确保旧证书文件也被清理,避免磁盘占用过高。
  • chmod 600:强制修正私钥权限,消除安全隐患。
  • nginx -t:重载前先测试配置,防止因配置文件错误导致服务宕机。

配置定时任务

在主节点配置 Cron 任务,让 Certbot 自动续签并触发同步脚本。

# 编辑 crontab
crontab -e

# 添加以下内容(每月 1 号凌晨 2 点执行)
0 2 1 * * /usr/bin/certbot renew `--quiet` `--post-hook` "/usr/local/bin/sync_cert.sh"

或者使用 Systemd Timer 获得更详细的日志记录。

验证与监控

1. 检查证书日期
在各负载均衡节点执行以下命令,确保证书到期日一致且已更新:

openssl x509 -in /etc/letsencrypt/live/your_domain/fullchain.pem -noout -enddate

2. 验证服务状态
检查 Web 服务或负载均衡进程是否正常运行,无报错:

多台负载均衡服务器如何共享同一份 Let's Encrypt 续签证书文件?
systemctl status nginx
journalctl -u nginx -n 20

3. 在线工具检测
使用浏览器访问域名查看锁图标,或使用 SSL 检测工具确认证书链完整,无过期警告。

常见坑与排查

1. 软链接断裂
若同步后服务启动报错 "file not found",检查 live 目录下的软链接是否指向了正确的 archive 版本。务必同步整个 /etc/letsencrypt 目录而非仅 live

2. 私钥权限错误
同步后私钥权限若变为可读,某些服务(如 Nginx)会拒绝启动。脚本中已包含 chmod 600,若手动同步请务必执行。

3. 重载未生效
证书文件更新了,但进程仍占用旧文件句柄。必须执行 reloadrestart,且要确认 reload 成功,否则流量仍走旧证书。

4. DNS 传播延迟
使用 DNS 挑战时,若 API 更新记录后立刻验证,可能因 DNS 缓存导致失败。客户端通常会自动等待,但需确保 API 权限正确。

参考来源

  • Let's Encrypt - Rate Limits: https://letsencrypt.org/docs/rate-limits/
  • Certbot Documentation - DNS Challenge: https://certbot.eff.org/docs/using.html#dns-plugins
  • Nginx - Reloading Configuration: https://nginx.org/en/docs/control.html