首先准备阶段要生成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滚动更新实现更优雅的证书轮换。