资讯动态

免费SSL证书申请到Nginx部署实战:从原理到自动续期

发布时间:2026/9/29 1:03:12 来源:尧图企业网站定制
说实话免费SSL证书这事我已经帮不少人处理过了。每年总有几个朋友过来问同一类问题“为什么我申请的免费证书浏览器不认”“证书到期忘了续签网站挂了怎么办”“照教程配置了Nginx怎么还是SSL连接错误”。这些问题单个看不复杂但它们通常集中在同一个环节——申请和部署之间的衔接没有理解透。我打算把从零申请免费SSL证书到把它稳稳部署在Nginx上、并且长期自动续期的完整过程写下来顺便把我踩过、也看朋友踩过的坑都列出来。路线很简单先搞清楚方案再走一遍实操最后集中排查问题。这篇指南里会覆盖免费证书和收费证书的真实差别、主流签发渠道怎么选、申请之前的准备工作、用acme.sh和Certbot签发证书的具体命令、Nginx部署与安全加固以及一大批SSL常见报错的排查思路。无论你是刚买了域名打算给网站加把锁的新手还是被“证书链不完整”“ssl connection required”这类报错折磨过的运维老哥应该都能从这里找到答案。所有操作都是我实际跑通过的命令照着做基本能落地。1. 方案选型免费证书的几种主流渠道1.1 免费证书和收费证书的真实差别很多朋友一上来就在免费和收费之间纠结。说实话你需要做的第一件事是把“免费证书不安全”这个念头从脑子里去掉。SSL证书的作用是证明两件事第一这个域名确实是你控制的第二客户端和服务器之间传输的数据经过了加密。DV域名验证免费证书已经覆盖了这两个核心需求。收费证书额外提供的通常是更高级的信任背书——比如OV证书会核实企业主体信息EV证书会在浏览器地址栏直接显示公司名称。这些对电商、金融、品牌官网来说是有意义的但如果你只是个人博客、企业内部系统、中小业务官网免费DV证书在加密能力上和收费证书没有任何差别。真正拉开差距的是有效期和维护成本免费证书普遍90天有效期收费证书一般一年或更久这意味着免费方案要求你做好自动化续期。这里有个容易混淆的点。很多人搜“ssl证书免费申请”时想解决的其实是两个完全不同的需求一个是网站部署HTTPS的服务器证书也就是这篇文章讨论的另一个是软件代码签名证书。代码签名证书需要用私钥对软件进行数字签名让Windows等系统识别你的软件发布者身份。到目前为止正规且被操作系统信任的代码签名证书很少提供免费长期方案这和网站SSL是两码事别搞混了。如果你是从“完全免费的windows代码签名证书”这类关键词过来的先明确自己的需求属于哪一类再往下看。1.2 主流免费证书渠道怎么选接下来是方案选型。我把国内常用的免费证书渠道做了个对比你可以直接按自己的场景选渠道有效期签发方式适合场景注意事项Lets Encrypt90天ACME协议自动签发个人站、中小业务、自动化运维要求域名可正常解析80端口或DNS可被验证ZeroSSL90天ACME协议、网页后台需要ECC证书或Web面板操作申请流程多一步邮箱验证API也支持阿里云/腾讯云免费证书通常12个月控制台申请后审核国内服务器环境免费额度有限续期往往需要重新申请Cloudflare源站证书最长15年面板一键生成已用Cloudflare做代理的站点只能在CF和源站之间使用不能替代公网证书从我的个人倾向来说能上ACME的尽量上ACME。原因很直接ACME协议把签发、部署、续期整个流程完全自动化了。你只需要在最开始跑一遍命令后面补上定时任务证书过期就不再是你能感知到的事情。用阿里云或腾讯云控制台申请虽然看起来简单但它有一个让人很头疼的体验——免费证书的续期往往不是“续”而是“重新申请”需要在控制台手动一步步提交审核通过后再手动下载、上传到服务器。一次两次还好长年累月一定会漏。如果你用的是国内厂商的云服务器我仍建议首选Lets Encrypt这类ACME方案原因就一条少一个人工环节就少一个出错的概率。至于阿里云和腾讯云的免费证书适合不想接触命令行、业务量又不大的场景或者临时给某个子域应急用。两者不冲突也可以同时用。2. 原理与准备工作先搞清楚证书是怎么“被信任”的2.1 TLS证书和信任链到底是怎么工作的第一次做HTTPS部署的人往往会被一堆名词绕晕“证书”“密钥”“CA”“公钥”“私钥”“crt文件”“key文件”。这里用个生活类比你把网站想象成一个保险柜柜子上有一把可以复制给任何人的锁——这是公钥你手里留一把只能你自己用的钥匙——这是私钥。浏览器访问网站时先把锁公钥证书拿过来把数据锁进箱子再寄过去只有你手里的私人钥匙能打开。问题来了浏览器凭什么相信这把锁是你的而不是中间人伪造的这就需要“证书信任机制”。CA机构用自己的根证书给网站证书“签字”浏览器和操作系统内置了一批受信任的根证书。当浏览器看到一张证书上有CA的合法签名就会沿着签名的链条往上找一直追到内置的根证书。链条完整就信任断掉就报警。现在你能理解几个常见报错背后的含义了。报“unable to get local issuer certificate”意思是浏览器没办法沿着证书链找到受信任根证书多半是你只部署了网站证书没有把CA的中间证书一起配上去。报“此CA根目录证书不受信任”通常是因为你用的是自签名证书没有把它安装到客户端的信任库。报“no required ssl certificate was sent”则出现在双向认证场景服务器要求客户端出示证书但客户端没有带。2.2 申请之前需要准备好的清单明确了原理之后先把资质和工具准备齐能省下大量返工时间。一份能正常申请受信任免费证书的检查清单如下第一域名。这个必须有且必须由你掌握解析权限。IP地址不能申请Lets Encrypt公网证书因为CA验证的就是你对该域名的控制权。常见验证方式有DNS解析一个TXT记录、在站点根目录放一个验证文件、或者通过HTTP访问一个特定路径三种方式本质上都是“证明你控制这个域名”。第二服务器。本地虚拟机也可以只要它能访问互联网并跑Web服务。国内部署还涉及服务器备案问题这个根据你服务器的运营商要求办跟证书申请本身是两条线不要混着谈。第三端口。HTTP验证方式需要80端口或443端口可被外网访问DNS验证方式则不需要开放端口但需要你能登录域名服务商的控制台操作解析记录。第四Web服务。这里优先推荐Nginx后续我会给出完整配置。Apache、Caddy、Tomcat也都可以原理一致只是配置指令不同。第五联系方式。用ACME方式注册时需要提供一个有效邮箱接收过期提醒用云厂商控制台申请时用账号登录就行。这些准备工作里大家最容易卡在域名解析上。如果解析还没生效就去签发CA访问不到你的域名验证直接失败。建议先执行ping yourdomain.com或者dig yourdomain.com确认解析生效再进入申请环节。3. 实操三分钟申请第一个免费证书3.1 用acme.sh签发Lets Encrypt证书Lets Encrypt是目前用户量最大的免费CA几乎所有自动化方案都围绕它展开。我推荐使用acme.sh它用Shell脚本实现ACME协议安装轻量、支持多种验证方式和DNS服务商API扩展性最好。第一步安装acme.sh。在服务器上执行curl https://get.acme.sh | sh安装脚本会把程序放到~/.acme.sh/目录并自动配置环境变量。装完之后需要重新登录一次终端或者执行source ~/.bashrc让命令行里能找到acme.sh命令。第二步注册账号。Lets Encrypt要求提供一个有效邮箱用于接收证书过期提醒和紧急通知acme.sh --register-account -m youremailexample.com如果你用的是国内服务器在某些网络环境下Lets Encrypt的API可能连接不稳定这时可以用--server参数切换到ZeroSSL的ACME端点命令差别不大。第三步签发证书。以最常见的webroot模式为例验证文件会被放到Nginx根目录下CA通过访问特定地址来确认域名控制权acme.sh --issue -d example.com -d www.example.com --webroot /var/www/html这里的-d参数可以重复使用用于申请多域名证书。签出来的证书会自动包含你指定的所有域名浏览器访问其中任意一个都会匹配不需要再分开申请。执行成功后证书和私钥会存放在~/.acme.sh/example.com/目录下。需要说明的是这个目录是acme.sh的工作目录不建议直接把Nginx的配置指向这里正确的做法是把证书安装到目标目录这一点我在部署部分会讲。如果域名解析还没就绪或者80端口暂时无法对外访问可以改用DNS验证模式acme.sh --issue -d example.com --dns执行后它会给出一个TXT记录值你把它添加到域名解析控制台等一两分钟生效后重新运行即可。这种方式不依赖Web服务器尤其适合申请泛域名证书通配符证书不过对DNS服务商的操作权限有一定要求。3.2 Certbot的另一种方案如果你不喜欢手动折腾脚本Certbot提供了更“开箱即用”的体验。在Debian/Ubuntu系统上安装apt install certbot python3-certbot-nginx如果Nginx站点配置已经写好了server_name直接执行certbot --nginx -d example.com -d www.example.comCertbot会询问一些选项比如是否自动把HTTP重定向到HTTPS按提示选择就行。它甚至会顺手帮你把Nginx配置里的SSL段全部改好这点比acme.sh更省心。但它的自动化程度不如acme.sh灵活尤其是当你要把证书安装到特定目录或者对接自己运维体系的时候。个人建议是单机单站用Certbot非常舒服服务器数量多、域名变动频繁、将来可能要对接DNS服务商API做泛域名证书的直接上acme.sh一步到位。3.3 证书文件到底怎么对应签好证书之后你会看到几个后缀不同的文件不少人的混乱就是从这儿开始的。以acme.sh为例最常用的有这几个example.com.key私钥相当于前面类比里的私人钥匙必须严格保密绝不能泄露到公网。example.com.cer网站证书叶证书包含你的域名信息和公钥。fullchain.cer完整证书链包含网站证书加中间证书。部署时一定要用这个文件而不是单独的cer文件。很多人配完只有一个cer和一个key结果浏览器报警“证书链不完整”就是漏了中间证书。用cat 网站证书 中间证书 完整证书链的方式也能手工合成但既然签发工具已经生成了fullchain直接拿来用就行。我记得第一次自己签发证书时不太清楚这些文件有什么区别把单张证书当成完整链配了上去当时想法很简单——“证书不就是那一张吗”。后来在多个客户端上测试才意识到信任链是浏览器向根证书追溯的关键少了一环就容易在部分设备上报错。而且这类问题在桌面浏览器上不一定马上暴露某些移动端App或老版本系统里却会翻车。4. 把证书部署到Nginx并顺手做好安全加固4.1 Nginx里的最小可用配置证书签发成功只是第一步能不能让浏览器认还得看服务端配得对不对。先把证书安装到Nginx配置目录mkdir -p /etc/nginx/ssl cp ~/.acme.sh/example.com/fullchain.cer /etc/nginx/ssl/ cp ~/.acme.sh/example.com/example.com.key /etc/nginx/ssl/然后编辑站点配置文件加上443端口的server块server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/nginx/ssl/fullchain.cer; ssl_certificate_key /etc/nginx/ssl/example.com.key; root /var/www/html; index index.html; }配置好后测试并重载Nginxnginx -t systemctl reload nginx这样HTTPS已经能正常访问了。但要注意如果之前有监听80端口的server块最好添加一个跳转把HTTP流量统一导到HTTPS避免用户习惯性输入域名时看到明文页面server { listen 80; server_name example.com www.example.com; return 301 https://$host$request_uri; }HTTP/2如果需要启用得看Nginx版本。老版本Linux发行版自带的Nginx可能没有编译http2模块版本不够的情况下建议先升级Nginx再启用。4.2 顺手做几个安全加固项证书配上之后强烈建议把下面几项也一起做了都不是复杂操作但对站点安全性提升非常明显。第一限制TLS协议版本。SSLv3、TLSv1.0、TLSv1.1都已经是过时协议存在公开漏洞实践中应禁用。在server块里加ssl_protocols TLSv1.2 TLSv1.3;第二合理配置加密套件。参考Mozilla推荐的现代配置可以在兼容性和安全性之间取得平衡ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off;第三开启HSTS。告诉浏览器接下来一段时间内只能用HTTPS访问本站能有效防止会话劫持add_header Strict-Transport-Security max-age63072000; includeSubDomains; preload always;需要注意HSTS一旦开启半年内如果临时想用HTTP访问浏览器也会强制跳转测试环境的站点别急着开这个头。第四开启OCSP Stapling。浏览器不再逐个去CA查询证书吊销状态而是由你的Nginx代为查询并附带在握手过程中既提升访问速度又减少隐私泄露ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 1.1.1.1 valid300s;做完这四项免费证书的安全性已经达到常规生产环境的水准了。4.3 需要双向认证时怎么处理有一些朋友在做内部系统比如后端API对接或者Tomcat服务会搜到“ssl双向认证tomcat下如何配置”这类词。双向认证的意思是在常规TLS握手之外服务器也要验证客户端的证书。典型场景是企业内部接口既要防止数据在传输中被窃听又要确保只有装了指定客户端证书的机器才能访问。双向认证和单向认证的区别在于服务器在握手时会要求客户端出示证书拿不到或者证书无法通过信任链校验直接拒绝连接。对应到Nginx配置需要额外加两条ssl_client_certificate /etc/nginx/ssl/ca.crt; ssl_verify_client on;前面提到的“no required ssl certificate was sent”就是典型的客户端没带证书报错。这种场景通常会用自建CA签发客户端证书然后把CA证书配置到ssl_client_certificate中。注意一点自建CA签发的证书不属于公共信任体系它只服务于你的内部系统和外面申请的公共受信任证书是两套逻辑别混在一起配置。5. 常见问题与排查免费证书实战中的那些坑5.1 浏览器报“证书链不完整”或“unable to get local issuer certificate”这是反馈率最高的报错之一。出现这个问题的原因大多是只配置了叶证书cer而没配置中间证书。解决方案很直接把ssl_certificate指向fullchain.cer。如果你是从云厂商控制台下载的证书包一般里面会包含xxx.pem、xxx.key、xxx_ca.pem三个文件配置时要注意ssl_certificate /path/to/xxx.pem; ssl_certificate_key /path/to/xxx.key; ssl_trusted_certificate /path/to/xxx_ca.pem;ssl_trusted_certificate的作用是把中间证书喂给OCSP校验有些人会漏掉这一行。虽然浏览器访问时不一定立刻报错但在某些客户端环境下就会暴露链不完整的问题。排查时还可以用一条命令快速看服务器实际返回的证书链openssl s_client -connect example.com:443 -servername example.com如果输出里只有一段证书而没有中间证书那基本可以确定是链没配全。5.2 各种“SSL握手失败”和“连接错误”常见报错包括“ssl handshake failure”“ssl recv :服务器不支持ssl”“SSL connection required”等。这类问题的原因比证书链复杂需要逐个排查服务端没开443端口或防火墙拦截。云服务器的安全组也需要检查只改系统防火墙有时会遗漏。客户端和服务端TLS版本不兼容。老系统上跑的程序只支持TLSv1.0/1.1而新版OpenSSL可能已经默认禁用了这些版本需要在两端做匹配。域名和证书不匹配。证书只签了example.com访问却是www.example.com或者用IP访问都会触发握手失败。服务端没有正确加载证书。Nginx配置完成后没reload后台还跑着旧配置也会造成类似的报错。遇到这类报错不要凭直觉打补丁。先用openssl s_client验证服务端基础状态再逐段确认端口、证书路径、配置语法按顺序排查最快。5.3 自签名证书和“此CA根目录证书不受信任”很多内网项目使用自签名证书因为内部系统没必要申请公共证书自己生成一张就行。但自签名证书不属于任何受信任CA浏览器默认不信任会弹“此CA根目录证书不受信任”之类的告警。处理方式有三种。第一种把自签名CA证书导出安装到各客户端的“受信任的根证书颁发机构”里适合内网统一管控的场景。第二种在Nginx里直接配置自签名证书客户端访问时手动忽略告警适合临时测试环境。第三种搭建内网私有CA用于需要大量签发证书的团队这需要额外构建一套PKI体系一般企业级应用才会用到。顺带提一下代码签名证书也属于“自签名不被信任”的高发区。Windows系统不会信任未知发布者的软件签名正规解决路径是购买受信任CA签发的代码签名证书。免费且长期有效的代码签名方案目前并没有稳定落地别被某些“免费证书”宣传误导了。5.4 MySQL和Java客户端的经典报错开发场景里的SSL报错很大比例集中在数据库连接和Java程序上。MySQL这边常见的是第一种[08001] ssl connection required, but not provided by server.意思是服务器要求SSL但客户端没有启用SSL。处理方式是在连接参数中加上useSSLtrue并配置CA证书如果后端全在内网且已有其他防护也可以把服务器的require_secure_transport参数关掉再重启MySQL。第二种是证书不匹配或CA校验失败需要在JDBC URL或客户端配置里指定--ssl-ca参数。Java这边比较经典的还有PKIX path building failed或者unable to find valid certification path to requested target。Java运行环境带了一个信任库cacerts里面默认只放公共CA的根证书。如果你的服务端用的是自签名证书Java客户端不会认。解决办法是把对方CA证书导入信任库keytool -import -alias example -file ca.crt -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit导入后重启Java服务即可。在本地开发调试时直接用-Djavax.net.ssl.trustStore...指定自定义信任库会更灵活不会污染全局环境。5.5 抓包工具证书安装后仍然显示unknown移动端开发同学最容易踩的坑就是这个。Charles、Fiddler、mitmproxy这类抓包工具能解密HTTPS流量原理是在手机上安装工具自身的根证书让代理服务器以中间人的身份建立两条TLS连接。你手机确实安装了证书但抓包依然显示“unknown”或“SSL连接错误”。原因通常是Android 7.0以上版本默认不再信任用户安装的CA证书只信任系统级CA。即便你把证书装上了应用也不认。处理办法有三个方向一是用adb把用户证书移动到系统证书目录前提是设备已root或刷了可写系统的ROM二是修改App的调试配置在AndroidManifest里声明只信任调试用的证书三是在测试环境里暂时关闭App的SSL Pinning校验——但这一步非常谨慎它只属于测试手段不能进入生产代码。iOS端相对简单安装证书后还要去“设置-通用-关于本机-证书信任设置”里手动开启完全信任漏掉这一步同样会失败。5.6 免费证书“续期”其实是伪命题如果你用的是云厂商控制台申请的免费证书会发现在证书到期前看到的操作不是“续期”而是“重新申请”。阿里云、腾讯云这类厂商的免费证书通常都是让你重新提交申请、重新审核、再重新下载整个流程无法一键自动化。申请本身不复杂但半年或一年就要重复一轮非常容易忘。解决思路有两个一是直接把证书签发迁到ACME体系通过定时任务自动续期从此不用关注证书有效期二是搭建证书过期监控提前检查证书剩余天数到期前发送告警。检查命令很简单echo | openssl s_client -connect example.com:443 -servername example.com 2/dev/null | openssl x509 -noout -dates把这条命令加进监控系统或者crontab每天跑一次输出里的notAfter就是过期时间。自动续期加过期监控双保险才能彻底摆脱“某天早上发现网站挂了”的命。6. 自动续期免费证书最不能省的一步6.1 给acme.sh装上自动续期既然免费证书的有效期只有90天自动续期就是必须养成的习惯。acme.sh在安装时就会注册一个每日定时任务检查所有证书的剩余有效期当剩余天数小于60天时自动重新签发。不过这还不够自动续期之后证书文件只是更新在~/.acme.sh目录里你还需要一个“安装”动作把新证书复制到Nginx用的目录并触发reload。acme.sh 提供了内置的--install-cert参数可以在证书更新时执行自定义命令acme.sh --install-cert -d example.com \ --key-file /etc/nginx/ssl/example.com.key \ --fullchain-file /etc/nginx/ssl/fullchain.cer \ --reloadcmd systemctl reload nginx当acme.sh自动续期成功后它会自动执行--reloadcmd指定的命令把Nginx重载让新证书立即生效。这一步配置一次之后整个周期全自动基本不需要人工干预。6.2 定时任务与证书过期监控顺手验证一下定时任务是否在运行crontab -l | grep acme你应该能看到类似0 0 * * * ... acme.sh ...的一行。如果因为环境迁移或权限问题导致定时任务丢失用acme.sh --install-cronjob重新安装即可。最后再分享一个我在生产环境里学到的教训不要把自动续期当成万能保险。定时任务本身有可能因为服务重启、服务器迁移、DNS解析变化等原因中断一旦中断没人发现证书就会在你毫无察觉的情况下过期。所以一定要有独立的监控手段哪怕只是每天跑一条命令检查证书剩余天数也比完全盲跑要好。监控告警可以接入你现有的告警渠道企业微信、钉钉或者邮件都行这样能避免“某天早上发现网站挂了”这种惊魂事件。我个人在实际操作中的体会是免费SSL证书如今已经是非常成熟的基础设施它并不比收费方案差真正决定成败的往往是使用习惯。我见过太多因为证书过期导致的线上事故每一个都是自动化没做好或者续期流程过度依赖人工。如果你读完这篇文章只打算做一件事那就把自动续期配置好然后定期检查证书剩余天数。免费的从来不是最贵的最贵的是过期之后才想起它。祝各位申请顺利别再被SSL报错折腾。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑