$ cat post.md

HTTPS 证书自动化:certbot 给 Nginx 免费上锁

承接 Nginx 建站篇:用 Let's Encrypt 免费证书把站点从 http 升级到 https,certbot 一条命令自动改配置,systemd timer 自动续期,一次配置永久免操心。

之前用 Nginx 部署的网站一直是 http:// 裸奔:浏览器地址栏挂着「不安全」警告,传输内容明文可被中间人偷看,很多现代浏览器 API(定位、剪贴板、Service Worker)在 http 下直接禁用。这篇用 Let’s Encrypt + certbot 给它免费挂上 HTTPS,全程十分钟,之后自动续期永不操心。

开工前的三个前提

certbot 申请证书时,Let’s Encrypt 会通过 80 端口访问你的域名来验证你确实控制着这台服务器。所以:

  1. 有一个域名,并且 DNS 已解析到你的服务器 IP(A 记录)。用 dig +short example.com 确认返回的是服务器 IP。
  2. 服务器有公网可达的 80 端口。家宽没有公网 IP 的话这条路走不通(可以改用 DNS 验证,文末会提)。
  3. Nginx 站点配置里的 server_name 已经写成了域名,而不是之前的 _:
server {
    listen 80;
    server_name example.com www.example.com;
    ...
}
sudo nginx -t && sudo systemctl reload nginx

一步签发:certbot –nginx

安装 certbot 和它的 Nginx 插件:

sudo apt update
sudo apt install -y certbot python3-certbot-nginx

然后一条命令:

sudo certbot --nginx -d example.com -d www.example.com

交互过程会问你几件事:

  • 邮箱地址(证书快过期时接收提醒,必填但基本收不到——因为续期是自动的)
  • 同意服务条款
  • 是否把 http 重定向到 https:选 Redirect,以后访问 http 自动跳到 https

跑完之后神奇的事情发生了:打开 /etc/nginx/sites-available/mysite,certbot 已经自动把 SSL 配置写好了——证书路径、443 监听、http 到 https 的跳转,全都不用你手写。

浏览器访问 https://example.com,地址栏出现小锁,收工。

防火墙别忘放行 443

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'   # 可选:80 只用于跳转和续期验证,保留也无妨

如果服务器在 Cloudflare 等 CDN 后面,CDN 到源站之间的加密是另一回事,参考之前的《Cloudflare 源站保护实战》。

自动续期:其实什么都不用做

Let’s Encrypt 证书有效期只有 90 天——这是故意的,短期证书逼着大家自动化。certbot 安装时已经注册了 systemd timer 自动续期:

# 查看续期定时器
systemctl list-timers certbot

# 演练一次续期流程,不真的签发
sudo certbot renew --dry-run

--dry-run 成功就说明续期链路是通的。证书剩 30 天以内时 timer 会自动续,你唯一要做的是别把 80 端口封死(续期验证要用)。

想更优雅一点:安全头与 HSTS

HTTPS 挂上之后,顺手在 Nginx 配置里加两个响应头:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff always;

HSTS 告诉浏览器「这个站以后只走 https」,防止降级攻击。更完整的安全响应头配置见《Nginx 反向代理安全加固实战》。

没有公网 80 端口怎么办

家里宽带没公网 IP,但又有域名想挂 HTTPS?用 DNS-01 验证:certbot 通过在你的 DNS 服务商那里写一条 TXT 记录来证明域名归属,全程不需要入站端口。配合 DNS 服务商的 API 插件(如 python3-certbot-dns-cloudflare)也能全自动化:

sudo apt install -y python3-certbot-dns-cloudflare
sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  -d example.com -d "*.example.com"

DNS 验证还有个独占福利:可以申请泛域名证书(*.example.com),一张证书覆盖所有子域名。

常见坑

现象 原因与解决
Timeout during connect 80 端口公网不通:防火墙没放行 / 家宽无公网 IP / DNS 没解析对
证书签给了错误的站点 server_name 没配对,certbot 找不到对应 server 块
续期失败 改了防火墙把 80 封了,或站点根目录改动导致验证文件 404
浏览器提示证书不受信任 用了自签名证书或证书域名与访问域名不匹配,检查 certbot certificates

小结

整个流程浓缩成三行:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com
sudo certbot renew --dry-run   # 验证自动续期链路

挂 HTTPS 这件事在 2026 年已经没有任何成本和借口。下一篇解决另一个家宽玩家的痛点:没有公网 IP,人在外面怎么安全地访问家里服务器——Tailscale 组网。