更换服务器后迁移 SSL 证书,正确做法是把整份证书材料连同自动续期配置一起打包搬过去,而不是只把 .crt 和 .key 两个文件上传到新机器;迁完必须做三件事才算完成:用 openssl 校验证书与私钥匹配、用 certbot renew --dry-run 验证续期链路、用在线工具或 s_client 确认新服务器下发的证书链完整。
换服务器后 SSL 证书怎么迁移最省事?
结论:迁移的最小单位是「目录」,不是「文件」。把 /etc/letsencrypt 和站点配置文件整体打包,比逐个文件拷贝快得多,也不会漏掉续期状态。
推荐的搬运顺序:
- 旧服务器上打包:
tar czf ssl-backup.tar.gz /etc/letsencrypt /etc/nginx/conf.d(Nginx 换 /etc/apache2/sites-available)。
- 通过
scp ssl-backup.tar.gz root@新IP:/root/ 传输,全程走 SSH 加密通道,不要用微信、网盘、邮件传私钥。
- 新服务器上解包到同一路径,保持
/etc/letsencrypt/live/域名/ 的目录结构不变——live 目录下全是软链接,指向 ../../archive/域名/,路径变了必然断链。
- 修权限:
chmod 600 privkey.pem,属主 chown root:root,/etc/letsencrypt/accounts 目录权限 700。
- 改 Nginx 里的
ssl_certificate 指向 fullchain.pem,ssl_certificate_key 指向 privkey.pem。
如果是商业证书(单域名 DV/OV),没有续期目录,那就只需要 .crt+中间证书链+.key 三份文件,但证书链必须合并成 fullchain.pem 一起下发。
为什么不能只拷 .crt 和 .key?
结论:只拷两个文件,90% 的故障出在「证书链缺失」和「续期任务丢失」这两处。
浏览器能打开不代表没问题。缺中间证书时,桌面 Chrome 往往宽容处理,但 Android 7 以下、部分 Java 客户端、微信内置浏览器会直接报「证书无效」。判断方法很简单:openssl s_client -connect 域名:443 -servername 域名 -showcerts 看输出里有几个证书,正常应该有 2-3 个(叶证书 + 中间证书)。
续期任务同样容易被忽略。Let's Encrypt 证书有效期 90 天,新服务器上如果没把 certbot 的 systemd timer 或 cron 一起迁过来,证书到期当天站点会直接挂掉,而且往往没人第一时间发现。检查命令:systemctl list-timers | grep certbot。
迁移后必须做哪几项验证?
结论:四步验证全部通过,才算迁移完成。
- 核对有效期与域名:
openssl x509 -in fullchain.pem -noout -dates -subject,确认 notAfter 与旧服务器一致、CN/SAN 包含当前域名。
- 验证私钥匹配:
openssl x509 -noout -modulus -in fullchain.pem | openssl md5 与 openssl rsa -noout -modulus -in privkey.pem | openssl md5 输出的哈希必须完全相同,不同就是拿错了 key。
- 验证线上握手:
curl -Iv https://域名 2>&1 | grep -E "expire|SSL",或直接跑 SSL Labs 拿到 A 级以上评分。
- 验证续期:
certbot renew --dry-run,跑通说明 ACME 挑战路径没问题。
另外确认系统时间:timedatectl 看 NTP 是否同步。服务器时间偏差超过证书有效期区间,会直接报 certificate is not yet valid。
Let's Encrypt 自动续期为什么会失败,怎么修?
结论:续期失败最常见的原因是 80 端口不可达,或 webroot 路径与 Nginx 配置不一致。
ACME 的 HTTP-01 验证要求外网能访问 http://域名/.well-known/acme-challenge/xxx。迁移后如果新服务器安全组没放开 80、或 Nginx 里没配这个 location、或用了 CDN 且回源没指到新 IP,续期必然失败。
- webroot 模式:确认
location ^~ /.well-known/acme-challenge/ { root /var/www/html; } 存在且目录可读。
- standalone 模式:续期前必须停掉 Nginx,建议加 hook:
--pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"。
- 通配符证书(
*.域名)只能用 DNS-01,迁移时要同步迁移 DNS API 凭据文件,否则续期报「无有效验证方式」。
- 续期成功后加
--deploy-hook "systemctl reload nginx",否则新证书落地了但 Nginx 还在用旧的。
迁移过程中最容易踩的坑有哪些?
结论:DNS 切换的时序和旧证书的保留,是两个最容易出事的地方。
第一,别急着删旧服务器。切 DNS 前把 TTL 从 3600 调到 300,等 24 小时后再切,切换后保留旧机至少 48 小时。期间新旧两台都持有证书,避免解析缓存导致部分用户打到旧 IP 时无证书可用。
第二,Nginx 配置里别把 ssl_certificate 写成相对路径。Nginx 以自己编译的 prefix 为基准解析相对路径,nginx -t 通过、nginx -s reload 后报错的情况很常见,一律写绝对路径。
第三,ssl_protocols 记得同步。旧服务器若只开了 TLSv1.2,新服务器默认可能带 TLSv1.3,一般没问题;但反向情况——新环境编译时 OpenSSL 版本低于 1.1.1 却不支持 TLSv1.3——重启会直接报错,用 nginx -V 看编译参数确认。
第四,HSTS 头不要在新机没验证通过前就带上 preload。Strict-Transport-Security 一旦被浏览器记住 max-age,回退期间用户会无法用 HTTP 访问,调试成本极高。
总的路径就是:整目录打包迁移 → 修权限 → 改绝对路径 → 四步验证 → dry-run 续期 → 观察 48 小时再下线旧机。这套流程在 GJ 站长论坛的站长交流帖里也反复被提到,本质是「证书不是文件,而是一整套会过期的配置」。把它当配置管理,而不是当附件上传,迁移就不会出问题。