多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Nginx + Let‘s Encrypt 上 HTTPS 完整教程:含 2026 年证书新变化

Nginx + Let‘s Encrypt 上 HTTPS 完整教程:含 2026 年证书新变化 给站点上 HTTPS 这件事十年前要买证书、填 CSR、等审核、一年一续。现在免费证书一条命令的事。但 2026 年这块有两个新变化很多教程还没更新Let’s Encrypt 已经支持 160 小时6 天的超短证书和 IP 地址证书默认证书寿命也正在从 90 天往 45 天降。这意味着以前那套提前 30 天告警的经验要重算了。这篇从零开始把 Nginx 上 HTTPS 配完再把自动续期和 2026 年的新选项讲清楚。环境准备# Debian/Ubuntusudoaptupdatesudoaptinstall-ynginx certbot python3-certbot-nginx# 确认版本要看 certbot 4.0 才支持 profile 选择nginx-vcertbot--version配置前有两个前置条件不满足的话 ACME 验证一定失败域名已经解析到这台机器dig yourdomain.com short能查到你的公网 IP。80 端口对公网开放HTTP-01 验证要从外面访问http://yourdomain.com/.well-known/acme-challenge/xxx。云服务器的话除了系统防火墙别忘了安全组也要放行 80 和 443。第一步先让 HTTP 站点跑起来这一步别跳过。证书是签给已经能正常访问的域名的先确保 HTTP 通了再动 HTTPS。# /etc/nginx/conf.d/app.conf server { listen 80; server_name yourdomain.com; root /var/www/app; index index.html; }sudonginx-tsudosystemctl reload nginxcurl-Ihttp://yourdomain.com# 应该返回 200第二步申请证书用 webroot 方式它对现有服务侵入最小sudomkdir-p/var/www/certbotsudocertbot certonly--webroot\-w/var/www/certbot\-dyourdomain.com-dwww.yourdomain.com\--emailyouexample.com\--agree-tos --no-eff-email\--deploy-hooksystemctl reload nginx几个参数说明--webroot -wcertbot 把验证文件写进这个目录Nginx 通过 /.well-known/ 路径把它暴露出去。--deploy-hook签发成功后自动执行。这条很关键不加重载钩子证书换了 Nginx 也不会加载新证书你会一直在用旧的。多个域名用多个-d同一张证书会覆盖所有域名SAN。Nginx 里要加一条 location让验证目录能访问location /.well-known/acme-challenge/ { root /var/www/certbot; }证书文件会生成在/etc/letsencrypt/live/yourdomain.com/下其中fullchain.pem和privkey.pem是 Nginx 要用的两个。第三步配置 HTTPS 站点server { listen 443 ssl; http2 on; server_name yourdomain.com www.yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # OCSP stapling ssl_stapling on; ssl_stapling_verify on; resolver 223.5.5.5 8.8.8.8 valid300s; resolver_timeout 5s; add_header Strict-Transport-Security max-age31536000 always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; add_header Referrer-Policy strict-origin-when-cross-origin always; root /var/www/app; index index.html; location /.well-known/acme-challenge/ { root /var/www/certbot; } } # HTTP 全量跳 HTTPS server { listen 80; server_name yourdomain.com www.yourdomain.com; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } }几个点解释一下。http2 on;是 Nginx 1.25.1 之后的新写法以前是listen 443 ssl http2老写法已经废弃了会报 warning。HSTS 别一上来就加includeSubDomains和preload。max-age31536000意味着浏览器接下来一年强制走 HTTPS如果哪天证书出问题、或者有子域名还是 HTTP用户会被彻底卡住打不开。先跑一两周确认没问题再考虑加预加载。只开TLSv1.2 TLSv1.3就够了1.0 和 1.1 早该淘汰。改完验证sudonginx-tsudosystemctl reload nginxcurl-Ihttps://yourdomain.com第四步确认自动续期真的在工作这是最容易配置完了但没验证的一步。很多人的证书都是某天静默过期然后站点全天报证书错误。# 干跑一次看续期流程会不会成功sudocertbot renew --dry-run# 确认定时任务存在systemctl list-timers|grepcertbotcertbot 装好时会自动加一个 systemd timer老系统是 cron每天跑两次检查有没有证书快到期。这个定时任务是随机的、带偏移的避免所有机器同一秒去请求 Let’s Encrypt。看证书还剩多久sudocertbot certificates第五步2026 年的新选项——要不要用短证书这是今年最大的变化值得单独说。从 2026 年 1 月 15 日起Let’s Encrypt 正式提供了 160 小时刚好超过 6 天的短证书以及 IPv4/IPv6 的 IP 地址证书两者都已 GA。短证书通过 ACME 的shortlivedprofile 申请。为什么会有这个核心原因是吊销机制不可靠。CRL 和 OCSP 这两个用来作废证书的东西实际上很多浏览器根本不好好检查。所以一张私钥泄露的证书在它过期之前可能一直被信任——最长 90 天。把寿命压到 6 天这个窗口就被物理压缩了。现在有三档可选profile有效期说明classic90 天默认最稳tlsserver45 天已在推的路上shortlived160 小时约 6.7 天可选自动化必须完全可靠用 certbot 申请短证书需要 certbot 4.0 的 profile 支持sudocertbot certonly--webroot-w/var/www/certbot\-dyourdomain.com\--preferred-profile shortlived\--deploy-hooksystemctl reload nginx我的建议绝大多数人不要碰 6 天短证书。Let’s Encrypt 自己都说了这不是给所有人用的。算一笔账6 天有效期意味着你的续期管道只要停摆大约 4 天证书就过期了。周末出个故障周一回来站点就是红锁。真正值得你现在做的是另一件事把 profile 设成tlsserver45 天当作自动化的压力测试。它已经在推的路上Let’s Encrypt 计划几年内把默认寿命从 90 天降到 45 天而且业内还有一个 2029 年要落地到 47 天的方案。现在就在 45 天节奏下跑通等到政策真正切换时你什么都不用改。第六步告别硬编码的续期时间以前大家都记一条规则“到期前 30 天续期”。这是 90 天证书时代的经验90 天的三分之一就是 30 天。但证书寿命变成 45 天、47 天甚至 6 天之后这个固定天数就没意义了——45 天的证书还剩 30 天时离该续期还早得很6 天的证书30 天的阈值永远不会触发。标准答案已经有了ACME ARIRFC 9773。CA 会通过一个接口告诉你该在哪个时间窗内续期客户端拿到窗口后在窗口里随机选一个时间点执行。# 客户端会去查询 renewalInfo 端点获取建议的续期窗口sudocertbot renew --dry-run-v21|grep-irenewal好消息是 certbot 已经内置支持 ARI你不需要改任何配置续期时间由服务端建议。坏消息是你的监控告警还停留在老阈值上。所以最后一步要做的是把证书到期前 X 天告警换成基于剩余比例或 ARI 的告警。写个最简单的脚本每天检查剩余天数低于有效期的三分之一就报警#!/bin/bash# check-cert.shDOMAINyourdomain.comEND$(echo|openssl s_client-servername$DOMAIN-connect$DOMAIN:4432/dev/null\|openssl x509-noout-enddate|cut-d-f2)END_TS$(date-d$END%s)NOW_TS$(date%s)DAYS$(((END_TS-NOW_TS)/86400))echo$DOMAIN剩余$DAYS天[$DAYS-lt15]echo告警证书即将过期2几个容易踩的坑1. 泛域名证书只能走 DNS-01。*.yourdomain.com这种通配符证书HTTP-01 签不了必须用 DNS 验证。用 acme.sh 配 DNS API 最方便exportCF_Token你的tokenexportCF_Account_ID你的account_idacme.sh--issue--dnsdns_cf-dyourdomain.com-d*.yourdomain.com\--reloadcmdsystemctl reload nginx但这里有个安全隐患DNS API token 从此就是一份长期有效的生产凭据了它得一直躺在这台机器上。所以务必把这个 token 的权限限制到单个 zone、只允许改 TXT 记录绝对不要用全局 API Key。有条件的话把签发的机器和跑服务的机器分开token 只放在签发机上。2. 别用certonly之后忘了 reload。前面强调过--deploy-hook或者--reloadcmd必须配。签发成功但 Nginx 还在用旧证书会表现成浏览器提示证书过期但 certbot certificates 显示还有 60 天——这种问题挺难一眼看出来的。3. Cloudflare 会把证书搞成两套。开了 CDN 之后访客看到的是 Cloudflare 边缘的证书你自己源站上的证书是另一张两者独立。而且 Cloudflare 的 Origin CA 证书只被 Cloudflare 信任浏览器不认所以它不走上面这套寿命规则别配错。4. 验证失败先看 Nginx 的 log。ACME 报错信息很模糊“some challenges have failed”真正的原因在 Nginx 的 error log 里。九成情况是location 没配对、目录权限不对、或者有个前置的重定向把/.well-known/也跳走了。最后整套流程就是HTTP 先跑通 → webroot 签证书 → 配上 reload hook → 干跑验证续期 → 布一个剩余天数的告警。五分钟能配完。但要记住 2026 年之后的一个判断证书这件事人工介入的余地越来越小了。90 天还能靠日历提醒手动续45 天已经很勉强6 天就必须全自动。所以别把精力花在记得续证书上把精力花在让续期管道绝对可靠上reload 钩子有没有、干跑过没有、失败了有没有告警。管道可靠了证书寿命是 90 天还是 6 天对你来说只是配置里换个值的事。
返回列表