上周五下午我正在改客户的 Nginx 配置邮箱突然弹出一封证书到期提醒。点开一看一台测试服务器上的证书只剩 12 天。这种场景我已经很熟了毕竟这两年 SSL 证书有效期一缩再缩早年免费证书还能给一年后来苹果和谷歌一起施压商业证书普遍被压到 398 天以内再后来 Lets Encrypt、ZeroSSL 这些主流免费 CA 直接干到 90 天市面上还冒出不少 200 天左右的过渡产品。每次到期都要人工去云控制台点一下续期再上传、部署、改配置这种日子真的没法过了。所以今天把话说透证书有效期缩短是大势所趋但免费证书并没有绝迹。与其到处问“哪里还有免费证书”不如先把方案盘清楚再花十几分钟把签发、部署、续期全部自动化。这篇东西写给个人站长、小公司运维以及正在做 HTTPS 改造的同学。内容不绕弯子直接讲方案、讲命令、讲我踩过的坑。1. 证书有效期缩短到200天背后到底发生了什么1.1 从“年限证书”到“短命证书”有效期收紧的三个节点SSL 证书有效期不是某家公司拍脑袋定的而是由 CA/Browser ForumCA/B 论坛这个行业组织推动变化的。这个组织里既有全球各大证书颁发机构也有 Google、Apple、Mozilla 这些浏览器/系统厂商。任何一方推动的规则变化最终都会传导到每一个网站主手里。第一个重要节点是 2020 年 9 月苹果 Safari 率先开始拒绝接受有效期超过 398 天的 TLS 证书。398 天这个数字不是随便定的因为一年 365 天容易因为时区、闰年、签发和到期时间计算产生误差398 天相当于“一年期证书 约 33 天的宽限期”确保证书在任何时区、任何算法下都不会超过一年。当时几乎所有商业证书都从 1 年甚至 2 年统一压到 398 天以内。第二个节点是 2021 年之后Lets Encrypt、ZeroSSL、Google Trust Services 这些面向大众的免费 CA 开始全面推行 90 天有效期。它们本来就是自动化签发模式的拥护者90 天对它们来说是常规操作。于是全球大量个人博客、中小企业网站、开发测试环境都成了“短命证书”的第一批体验者。第三个节点就是现在行业里关于“把最长有效期压到 45 天甚至更短”的讨论一直没停过。虽然还没强制执行但 90 天已经是大量业务线的默认配置。你看到的“200 天”更像是商业证书在 398 天和 90 天之间被反复拉扯时出现的过渡值。对普通用户来说感知到的结果就是证书到期越来越快稍不留神就过期。1.2 短周期证书为什么更安全很多人一听说证书有效期缩到 200 天、90 天第一反应是“这是不是浏览器厂商联合 CA 想多赚钱”。从商业证书角度看确实有这种嫌疑但从技术安全角度说短周期证书是有明确收益的。核心原因在于证书吊销环节。目前浏览器对证书吊销状态的处理主要依赖 CRL证书吊销列表和 OCSP在线证书状态查询协议。这两套机制都有明显的短板CRL 列表可能很长浏览器出于性能考虑经常不查OCSP 存在隐私和可用性问题有些网络环境下甚至配置了 OCSP Stapling 才能正常工作。简而言之一张证书如果因为私钥泄露被吊销很难保证所有浏览器立刻发现并拒绝它。缩短有效期等于不给问题留窗口期。哪怕中间层 CA 被攻破、私钥泄露一张证书最多也就危害 90 天或 200 天之后自动作废。用一句大白话说以前一张证书能管一年出问题要担惊受怕 365 天现在缩短到 90 天就算真出事影响面也被时间死死框住。还有一个隐性好处短周期强制运维自动化。以前一次性申请一年期证书很多站点用的是“到期前手动换一次”的流程结果永远有人忘记续期导致网站突然弹出大红叉。有效期缩短之后手工续期的成本急剧上升大家被迫转向 ACME 协议、acme.sh、Certbot 这些工具反而把证书管理拉回了正轨。1.3 200天时代对站长运维的真实冲击证书有效期缩短影响最直接的还不是“用户访问网站会不会报错”而是存量设备的更新效率。你的 Nginx 可以秒级加载新证书但是邮件服务器、FTP 服务比如 vsftpd、内网 WiFi 认证门户、NAS、监控摄像头这些设备很多并不支持 ACME 协议。以前一年换一次证书手动也就忍了现在 90 天就要换一次但凡有一台设备忘记更新就会出现服务中断。我前两天还给一台跑 vsftpd 的机器折腾证书。FTP 服务其实对证书的要求不高只要证书有效、私钥匹配、权限正确就能建立 TLS 加密通道。但问题是 vsftpd 默认不去读取系统证书目录你要手动把证书文件路径写进 vsftpd.conf而且证书续期之后还得重启 vsftpd否则老证书还在内存里被用着。这就是短有效期时代最典型的坑不只是 Web 服务器所有用到证书的服务都要纳入同一个自动化体系。另一个冲击是排障成本变高。以前证书一年到期问题定位很直观现在 90 天一个周期可能你刚部署完三个月不到又收到报警。如果不把“查看证书过期时间”“检查证书链是否完整”“确认续期任务是否执行”这些基础操作练熟后面会疲于奔命。2. 2025年还能用的免费证书方案横向对比2.1 Lets Encrypt自动化程度最高的大众方案Lets Encrypt 是目前全球使用量最大的免费证书 CA由 Linux 基金会等非营利组织背书服务免费证书有效期固定 90 天。它的最大优势是生态成熟几乎所有云服务器、CDN、负载均衡、GitHub Pages、Netlify 都支持它。签发方式走 ACME v2 协议可以配合 Certbot、acme.sh、Caddy 等工具实现全自动续期。支持两种验证方式HTTP-01 验证在网站根目录放一个随机文件CA 通过 HTTP 访问来确认域名所有权。适合 80 端口对外开放的服务器。DNS-01 验证通过域名解析服务商 API 添加一条 TXT 记录来确认所有权。适合通配符证书、没有公网 80 端口的服务器。实际使用中我推荐 acme.sh因为它是纯 Shell 脚本依赖少而且内置了几十种 DNS 服务商的 API 模块阿里云、腾讯云、Cloudflare 都有。Lets Encrypt 有申请额度限制同一个主域名下每周能签发的证书数量有限但正常使用完全够。以前有每周 5 张的限制现在放宽了不少不过没必要追求极限按需求签就行。2.2 ZeroSSL、Google Trust Services值得留作备胎的CAZeroSSL 和 Lets Encrypt 一样提供 90 天免费证书而且它是 acme.sh 默认使用的 CA。很多同学运行 acme.sh 时如果不指定 --server 参数实际就是在和 ZeroSSL 打交道。它与 Lets Encrypt 的区别主要有三点有图形化管理后台能直观看到证书列表、有效期、续期状态对新手更友好支持通过邮箱注册账户初次使用要完成邮件确认acme.sh 会自动弹出链接让你去激活免费证书的签发表格和 API 接口都支持 90 天续期但部分老版本脚本可能默认不触发续期需要手动加参数。Google Trust Services 是谷歌推出的公共 CA证书有效期同样是 90 天主要优势是根证书信任度高兼容性极强。Cloudflare 的某些证书服务也使用 GTS 作为签发后端。不过它的 ACME 入口在某些旧客户端里支持不太好你要是习惯用 Certbot 老版本可能需要升级后才能签发。我个人建议主用 Lets EncryptZeroSSL 当备胎。万一 LE 那边域名申请额度用完了或者某个 DNS 服务商模块出问题切到 ZeroSSL 还能继续跑。切换命令只是加一个 --server zerossl不用改任何部署逻辑。2.3 阿里云、腾讯云等云厂商的免费证书还能领吗国内云厂商的免费证书政策这几年变了好几次。阿里云、腾讯云、华为云都提供过免费的数字证书早期确实有一年期单域名 DV 证书申请成功后可以在控制台下载也可以一键部署到对应的 CDN、SLB 等产品上。但是近两年政策越来越不确定。有些账号还能领到 1 年有效期免费单域名证书有些账号则只能领到 90 天版本而且免费额度经常变。甚至同一个平台不同时间点的规则都不一样。我之前有个阿里云账号免费证书证书数量额度从最初的 20 张一路变成个位数再到后来一年只能领 1 张变化非常快。我的态度很明确云厂商免费证书可以领但不要单独依赖它。原因有三个。第一它的申请流程虽然简单但本质上还是“控制台手动申请 手动部署”90 天一个周期谁也扛不住。第二免费版通常只支持单域名不支持通配符也不支持多域名 SAN对稍微复杂一点的站点就没法用。第三政策一旦变化免费额度取消你临时再迁移到别家 CA中间的空窗期很容易出事。它最好的定位是“兜底方案”比如阿里云官网自己的产品页需要快速上一张免费证书控制台点两下就有这比自己去配 ACME 快得多。但生产环境的长期证书管理还是建议用 acme.sh 这类自动化工具接 Lets Encrypt 或 ZeroSSL。2.4 特殊场景Plan BCloudflare源站证书与自签证书如果你的网站套了 Cloudflare CDN那么有一个特殊福利经常被忽略Cloudflare 源站证书Origin Certificate。它可以直接在 Cloudflare 控制台生成有效期最长 15 年而且完全免费。注意它的作用范围不是直接面向访客而是用于“Cloudflare 边缘节点到你的源站服务器”这条回源链路。访客访问 Cloudflare 节点时用的是 CF 边缘证书源站收到请求时验证的是这张 15 年的源站证书。这套方案的好处是有效期内几乎不用管证书续期适合把访客流量全部交给 Cloudflare 的场景。坏处是源站必须只接收 Cloudflare 的回源请求否则用户直接访问源站 IP 会报警。如果你自己冷启动一个小站点又不想弄 ACME套一层 CF 然后用源站证书是真的省心。自签证书则适合内网环境。公司内部系统、NAS、测试环境、设备管理后台如果用公网 CA 签的证书还要配域名、做验证非常麻烦。你可以自己建一个内网 CA分发证书到各台设备再把根证书加到公司电脑、手机、服务器的信任库里。有效期可以设成 3 年甚至更长。它解决的只是“传输加密和身份识别”不能像公网可信证书那样被外部客户端信任这是要知道边界的地方。2.5 免费证书选型建议与场景组合把市面上主流的免费证书方案放在一起看会更清晰方案有效期成本适合场景自动续期难度Lets Encrypt90天0Web、API、FTP、邮件服务器低acme.sh一键ZeroSSL90天0需要图形管理界面、备胎CA低acme.sh支持Google Trust Services90天0对CA兼容性要求高的站点中等阿里云/腾讯云免费证书90天~1年政策不定0快速签发、云产品一键部署高手动为主Cloudflare源站证书15年0套CF CDN的源站极低自签证书自定义0内网系统、测试环境中我的推荐组合是这样的公网 Web/API/邮件服务优先 Lets Encrypt acme.sh按域名分开管理服务器在国内且 DNS 服务商是阿里云/腾讯云acme.sh 内置 dns_ali、dns_tencent 模块自动化没问题如果业务套了 CDN回源链路用 Cloudflare 源站证书付费用 CDN 的边缘证书内网设备、测试机建个自签 CA一次性投入长期使用真到了需要 OV/EV 证书做企业身份验证的场景才考虑商业证书那不在免费范围的讨论内。3. 15分钟搞定自动化用acme.sh完成签发、部署、续期3.1 安装acme.sh与前置环境检查acme.sh 是我目前最推荐的证书客户端没有之一。它不用装 Python 环境不依赖 Node只要系统里有 curl 和 openssl 就能跑对低配 VPS 特别友好。安装命令只有一行curl https://get.acme.sh | sh -s emailadminexample.com安装完成后脚本会释放到当前用户的 ~/.acme.sh 目录并自动写入 crontab每天检查一次证书是否需要续期。检查一下安装是否成功source ~/.bashrc acme.sh --version crontab -l | grep acme如果 crontab 里没有 acme.sh 的相关记录可以手动加一行0 0 * * * /root/.acme.sh/acme.sh --cron --home /root/.acme.sh /dev/null安装前建议先确认服务器时间正确。ACME 协议对时间非常敏感服务器时间偏差超过几分钟就会导致签发失败。用这个方法检查date如果时间不对先同步时间再往下走。3.2 配置DNS APILet‘s Encrypt签发一张证书签发证书前要决定用哪种域名验证方式。如果你的服务器有公网 80 端口用 HTTP-01 验证最省事acme.sh --issue -d example.com -d www.example.com --webroot /var/www/html如果没有公网 80 端口或者想签通配符证书就得上 DNS-01 验证。下面以阿里云 DNS 为例。先在阿里云 RAM 访问控制里创建一个子用户只给它 AlidnsFullAccess 权限然后生成 AccessKey ID 和 AccessKey Secret。生产环境不要用主账号的 AccessKey权限太大一旦泄露全盘皆输。配置命密钥和环境变量export Ali_Key你的AccessKey_ID export Ali_Secret你的AccessKey_Secret然后签发证书acme.sh --issue --dns dns_ali -d example.com -d www.example.com --server letsencrypt这条命令执行后acme.sh 会通过阿里云 OpenAPI 自动添加一条 TXT 解析记录等待 DNS 生效确认后删除记录。整个流程全自动不需要去解析平台手动操作。有个细节我要特别说明--server letsencrypt 是强制指定使用 Lets Encrypt。2020 年之后acme.sh 默认使用 ZeroSSL如果你是第一次跑会提示你去 ZeroSSL 邮箱确认账户。想省掉注册流程直接加这个参数就行。3.3 多域名证书、泛域名证书的一行命令生成多域名证书也就是 SANSubject Alternative Name证书允许一张证书同时保护多个域名。签发命令就是把多个 -d 参数拼在一起acme.sh --issue --dns dns_ali -d example.com -d www.example.com -d blog.example.com --server letsencrypt泛域名证书也是同样套路但要注意泛域名只匹配当前一层子域不匹配根域。比如 -d *.example.com 能覆盖 www.example.com、api.example.com但不覆盖 example.com 本身。所以标准写法是根域和泛域名一起签acme.sh --issue --dns dns_ali -d example.com -d *.example.com --server letsencrypt在“一张 SAN 证书挂所有域名”和“每个域名单独一张证书”之间我的建议是如果域名之间没有强关联尽量分开签。SAN 证书最大的问题是续期时所有域名共进退一个域名验证失败整张证书就续不了。分开签的好处是隔离故障某张证书出问题不影响其他站点。三种证书方案的对比方案覆盖范围适用场景缺点单域名证书1个域名小站、独立业务域名多时要签多张SAN多域名多个指定域名关联域名的统一管理续期互相牵连泛域名*.example.com子域名多且不固定必须DNS验证部分根证书兼容性略差3.4 部署到Nginx并用openssl检查到期时间证书签发成功后acme.sh 会默认把证书文件存放在 ~/.acme.sh/example.com/ 目录下。我不建议直接使用这个目录里的文件因为它是 acme.sh 的内部数据结构版本升级后路径可能变化。更稳妥的做法是把它安装到标准位置。运行安装命令acme.sh --install-cert -d example.com \ --key-file /etc/nginx/ssl/example.com.key \ --fullchain-file /etc/nginx/ssl/example.com.pem \ --reloadcmd systemctl reload nginx || nginx -s reload这里有两个关键点一定要用 --fullchain-file而不是 --cert-file。fullchain 文件里包含“网站证书 中间证书”Nginx 配置里写 ssl_certificate 时直接用 fullchain才能保证手机端、老系统不出现证书链不完整的问题。然后修改 Nginx 配置server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.pem; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; }改完检查配置并重载nginx -t systemctl reload nginx查看证书过期时间用 openssl 命令最直接openssl x509 -enddate -noout -in /etc/nginx/ssl/example.com.pem想判断证书 30 天内是否会过期用 --checkend 参数openssl x509 -checkend 2592000 -noout -in /etc/nginx/ssl/example.com.pem如果输出 notAfter... 表示证书有效且剩余时间超过 30 天如果输出会返回非零值说明要到期了或者已过期。这个命令非常适合写进监控脚本里。3.5 顺带解决vsftpd的SSL证书要求vsftpd 配置 SSL 的原理很简单证书文件路径写对私钥权限收紧然后开启强制 SSL 选项。但它不会自动读取系统证书需要手动指定路径。我一般会把 acme.sh 签发的证书直接复制到 /etc/vsftpd/ 目录mkdir -p /etc/vsftpd/certs cp /etc/nginx/ssl/example.com.pem /etc/vsftpd/certs/vsftpd.pem cp /etc/nginx/ssl/example.com.key /etc/vsftpd/certs/vsftpd.key chmod 600 /etc/vsftpd/certs/vsftpd.key然后在 /etc/vsftpd.conf 末尾加上ssl_enableYES allow_anon_sslNO force_local_data_sslYES force_local_logins_sslYES rsa_cert_file/etc/vsftpd/certs/vsftpd.pem rsa_private_key_file/etc/vsftpd/certs/vsftpd.key重启服务systemctl restart vsftpd这里最容易踩的坑是acme.sh 自动续期后Nginx 会通过 reloadcmd 自动加载新证书但 vsftpd 不会。所以如果你把 FTP 也纳入同一张证书记得在 acme.sh 的 --reloadcmd 参数里加上重启 vsftpd 的动作。我自己的命令是这样的--reloadcmd systemctl reload nginx; cp /etc/nginx/ssl/example.com.pem /etc/vsftpd/certs/vsftpd.pem; cp /etc/nginx/ssl/example.com.key /etc/vsftpd/certs/vsftpd.key; chmod 600 /etc/vsftpd/certs/vsftpd.key; systemctl restart vsftpd虽然命令有点长但一次配好以后 90 天自动续期完全不用管 FTP 这块。4. 我亲测踩过的坑续期失败与证书异常的排查实录4.1 续期脚本没跑的五个原因acme.sh 的自动化逻辑是每天通过 crontab 运行一次 --cron检查所有证书是否“过生命周期的 60%”到了就自动续期。表面上看没问题实际跑起来却有不少翻车场景。最常见的原因是系统 crontab 被重置。有些云服务器镜像会在系统迁移、安全加固时把 crontab 清掉我当时就遇到过一台机器上 cPanel 更新后把所有用户 crontab 全清理了acme.sh 的续期任务无声消失。排查方法很简单crontab -l | grep acme没有输出就是 crontab 丢了按前面 3.1 的写法重新补上。第二个常见原因是服务器时间和真实时间偏差过大。ACME 签发时CA 会检查请求时间和服务器时间差偏差超过几分钟就会拒绝请求。我建议在服务器上配置好 chrony 或 systemd-timesyncd不然后续期会一直报错。第三个原因是 DNS API 权限不足或密钥失效。很多同学用阿里云 AccessKey 配置好之后就没管过但 RAM 子账号权限可能被运维同事清理或者 AccessKey 过期被禁用。续期日志里通常会显示“Can not get domain token”之类的错误定位到这一步直接去云控制台检查密钥和权限即可。第四个原因是 HTTP-01 验证时80 端口被防火墙或安全组拦掉。这种排查也很简单临时关掉安全组测试一下或者干脆改 DNS 验证。第五个原因容易被忽略证书还没到“60% 生命期”acme.sh 认为不需要续期。有人手动跑了 --cron 发现啥也没发生就以为脚本坏了。其实这是正常现象LE 证书有效期 90 天第 54 天左右才触发续期。4.2 证书链不完整手机端一片红有一次部署完成后电脑浏览器打开一切正常我拿手机一扫却弹出“证书不受信任”。当时第一反应是证书没配上结果 F12 查看局域网电脑上明明显示 HTTPS 正常。后来才发现我只把网站证书cert.pem配给了 Nginx没带中间证书chain.pem。Nginx 的 ssl_certificate 指令需要的是完整链路也就是“网站证书 中间证书”。acme.sh 安装时如果用了 --cert-file生成的就只有网站证书必须用 --fullchain-file 才能拿到包含中间证书的完整链。验证证书链是否完整的命令openssl s_client -connect example.com:443 -servername example.com -showcerts观察输出里是否能同时看到网站证书和中间证书。如果只有一层基本就是缺链。修复方式很简单重新用 --fullchain-file 安装一次再 reload Nginx。4.3 证书和私钥不匹配、权限太开放证书和私钥不匹配的问题多见于手动复制文件时搞混了不同域名之间的 .key 和 .pem。启动 Nginx 时可能直接报错但有些服务不会第一时间报直到用户访问才暴露。快速判断是否匹配用两个命令分别取证书和私钥的 modulus对比 MD5 结果openssl x509 -noout -modulus -in /path/to/cert.pem | openssl md5 openssl rsa -noout -modulus -in /path/to/key.key | openssl md5输出一致就是匹配不一致就是文件错位了。另外要严格控制私钥文件的权限。Nginx 以 root 启动时能读取任意文件但如果你把 key 文件权限设成了 644其他用户也能读这属于安全隐患。建议统一设成 600属主 root:chmod 600 /etc/nginx/ssl/example.com.key chown root:root /etc/nginx/ssl/example.com.key4.4 多域名与泛域名证书的常见误区泛域名证书用得最多的地方是“给不同环境动态分配子域名”比如 dev.example.com、test.example.com、pre.example.com。但很多人会忽略根域导致访问 example.com 本身时证书不可信。正确的签发姿势是根域和泛域名一起签前面写过的命令再贴一次acme.sh --issue --dns dns_ali -d example.com -d *.example.com还有一个误区是以为泛域名能覆盖二级子域名的二级子域名比如 *.example.com 可以覆盖 a.b.example.com。这是错的泛域名只匹配一级。如果真的有多层子域名需求要么把需要的层级都列进 SAN要么考虑用对应层级的泛域名再签一张。多域名证书的另一个问题是续期时只要有其中一个域名验证失败整张证书都会续期失败。我后来学乖了生产环境的核心域名单独签不太重要的多个项目域名共用一张 SAN 证书避免单点故障。4.5 证书异常速查表现象可能原因处理方式手机端报“证书不受信任”电脑正常证书链不完整只给了 cert.pem改用 fullchain.pem续期任务没执行crontab 被清掉crontab -l 检查并恢复acme.sh 签发提示时间错误服务器时间偏差大配置时间同步DNS 验证失败AccessKey 权限不足/密钥过期到云控制台检查 RAM 授权浏览器提示“证书与域名不匹配”证书只包含 example.com访问了 www重新签发时把 www 加入 SAN私钥权限太开放key 文件 644chmod 600证书到期后 vsftpd 仍用旧证书续期脚本没重启 vsftpdreloadcmd 里补上行 vsftpd restart我现在的习惯是所有证书统一放到 /etc/ssl/域名/ 下Nginx、vsftpd、邮件服务都从这个目录读文件acme.sh 自动续期之外再加一个每日脚本用 openssl x509 -checkend 判断证书是否 30 天内到期如果到期就发一封邮件给我。这样就算自动续期哪天失效了我也能提前知道而不是等用户访问时才发现大红叉。说实话我当时折腾这些自动化配置前后花了大概一个下午但换来的是之后两三年的清净。证书有效期缩短这件事本质上不是逼大家频繁手工续期而是逼所有人把证书管理“现代化”。免费证书不会绝迹只要花十几分钟把自动续期配好它就一直是免费的哪怕未来有效期继续缩到 45 天手上有自动化这套东西也不过是改个参数的事。