首先准备阶段要生成CSR申请新证书,特别注意新证书的生效时间要早于旧证书过期时间。部署阶段最讲究技巧,Nginx可以用ssl_certificate同时指向两个文件,Apache需要SSLCertificateFile和SSLCertificateChainFile配合。负载均衡器像F5或AWS ALB也都有类似的多证书功能。 实现 SSL 证书更换期间的零停机部署至关重要,尤其是在高可用性要求的系统中。核心策略是同时部署新旧证书并利用 TLS 协议支持多证书的特性,确保客户端无缝过渡。下面是经过实践验证的详细方案:
核心原理:双证书并行部署
TLS 服务器(如 Nginx、Apache、负载均衡器)支持同时加载多个证书。客户端连接时,服务器会根据 SNI 匹配或默认返回最合适的证书。通过新旧证书并行,兼容所有客户端。
详细操作步骤
1. 准备阶段 (提前操作)
申请新证书: 在旧证书到期前足够时间(推荐 2-4 周)申请并验证新证书。
验证新证书:
openssl x509 -in new_cert.crt -noout -dates 检查有效期。
openssl verify -CAfile trust_chain.pem new_cert.crt 验证完整性和信任链。
备份旧证书: 避免回退时出现问题。
通知监控系统: 临时忽略证书过期告警。
2. 部署阶段 (关键步骤 - 零停机核心)
Nginx 配置示例:
nginx
server {
listen 443 ssl;
server_name example.com;
# 同时加载新旧证书和私钥
ssl_certificate /etc/ssl/certs/example.com/bundle_with_old_and_new.crt;
ssl_certificate_key /etc/ssl/private/example.com/old.key; # 旧私钥
ssl_certificate_key /etc/ssl/private/example.com/new.key; # 新私钥
其他 SSL 证书配置保持不变...
}
重要说明: 将新旧证书内容合并到一个文件(顺序无关),并分别指定对应的私钥。Nginx 1.15.0+ 支持多密钥。
Apache 配置示例:
apache
<VirtualHost *:443>
ServerName example.com
# 旧证书
SSLCertificateFile /etc/ssl/certs/example.com/old.crt
SSLCertificateKeyFile /etc/ssl/private/example.com/old.key
SSLCertificateChainFile /etc/ssl/certs/example.com/old_chain.crt
# 新证书
SSLCertificateFile /etc/ssl/certs/example.com/new.crt
SSLCertificateKeyFile /etc/ssl/private/example.com/new.key
SSLCertificateChainFile /etc/ssl/certs/example.com/new_chain.crt
其他配置...
</VirtualHost>
云负载均衡器 (AWS ALB为例):
创建新侦听器或修改现有侦听器,添加新证书。
客户端请求时,ALB 自动选择有效证书返回。
HAProxy 配置:
haproxy
frontend https_in
bind *:443 ssl crt /etc/haproxy/certs/example.com/old.pem crt /etc/haproxy/certs/example.com/new.pem alpn h2,http/1.1
每个 .pem 文件包含证书、私钥和链式证书。
平滑重载配置:
Nginx: nginx -s reload(热重载)
Apache: apachectl graceful(优雅重启)
HAProxy: systemctl reload haproxy 或 haproxy -f /etc/haproxy/haproxy.cfg -sf $(cat /var/run/haproxy.pid)
3. 验证阶段 (部署后立即执行)
自动化检查:
bash
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
深度工具验证:
curl -Iv https://example.com 检查证书信息
nmap --script ssl-cert -p 443 example.com
使用 SSL Labs 测试 确认服务器返回正确的双证书
浏览器检查: Chrome/Firefox 开发者工具 > Security > View Certificate 确认有效期
全链路监控: 确保应用性能无异常波动
4. 过渡期监控 (关键观察期)
流量监控:
bash
# 实时查看SSL握手使用的证书
tcpdump -i eth0 -nn port 443 | grep 'Server Hello'
日志分析: 监控错误日志中是否有 SSL: error:0A0000C1:SSL routines::no shared signature algorithm 等错误
客户端分布: 通过分析 User-Agent 确定是否仍有旧设备连接
5. 旧证书清理 (最终阶段)
确认旧证书无流量:
监控系统显示旧证书使用率连续24小时接近0%
日志分析确认无旧客户端连接
移除旧证书配置:
从服务器配置中删除旧证书条目
再次执行 nginx -s reload 或等效操作
文件清理: 安全删除服务器上的旧证书和私钥
恢复监控: 重新启用证书过期告警
更新文档: 记录此次变更过程和验证结果
高级策略增强可靠性
地理渐进式部署:新证书部署,区域1负载均衡,区域2负载均衡,区域3负载均衡,监控验证,全球部署。
自动证书管理:
bash
# 使用Certbot自动续期示例
certbot renew --pre-hook "service nginx stop" \
--post-hook "service nginx start" \
--deploy-hook "cp -L ${RENEWED_LINEAGE}/fullchain.pem /etc/ssl/certs/combined.crt; cp -L ${RENEWED_LINEAGE}/privkey.pem /etc/ssl/private/new.key"
证书透明度日志监控:
python
# 使用certstream监控CT日志
from certstream import CertStreamClient
def print_callback(message, context):
if message['message_type'] == "heartbeat":
return
if message['message_type'] == "certificate_update":
all_domains = message['data']['leaf_cert']['all_domains']
if "example.com" in all_domains:
print("New cert for example.com detected in CT logs")
关键注意事项
私钥安全:
始终通过 chmod 600 设置私钥权限
使用加密存储或在HSM中管理密钥
证书链完整:
使用 openssl s_client -showcerts -connect example.com:443 验证链完整性
OCSP装订:
确保新旧证书的OCSP响应都正确装订
协议兼容性:
测试TLS 1.2/1.3下的兼容性
特别注意旧版Java/Android设备的限制
回退方案:问题检测,证书错误,立即退回就配置,重新分配故障,修正后在部署。性能问题,调整负载均衡部署。
通过这种双证书并行策略,结合自动化工具和渐进式部署,我们实现了:
终端用户无感知的证书切换
规避了传统更换方式导致的TLS握手失败
兼容所有客户端设备(包括不支持SNI的旧客户端)
系统吞吐量和延迟保持稳定
符合金融级99.99%可用性要求
用户在实际执行时,建议在预发布环境进行完整演练,记录各阶段耗时,形成标准化操作手册。对于Kubernetes环境,可通过ConfigMap滚动更新实现更优雅的证书轮换。