Web 服务器
Nginx 用 Certbot 配置 Let's Encrypt 免费 HTTPS 证书
用 snap 安装 Certbot 后运行 certbot --nginx,就能为 Nginx 上的 example.com 和 www.example.com 申请 Let's Encrypt 免费证书。Certbot 会改好 HTTPS 配置和 HTTP 跳转,并在到期前自动续期。适用于 Ubuntu 22.04/24.04、Debian 12/13,Nginx 任意在维护的版本,Certbot 4.1 及以上(截至 2026 年 11 月最新是 5.x)。
前提条件
Let's Encrypt 需要能从公网通过 80 端口访问到你的服务器。
- 一台带 systemd 的 Linux 服务器,有 sudo 权限。Ubuntu 自带 snap;Debian 先运行
sudo apt install snapd。 - 已安装并运行 Nginx,域名有对应的 server 配置。
- 域名
example.com、www.example.com的 A 记录(用 IPv6 的话还有 AAAA 记录)指向服务器,例如203.0.113.10。 - 服务器在中国大陆的,域名必须已完成 ICP 备案,否则云厂商会拦截 80/443 端口的网站访问,HTTP 验证会失败。
- 防火墙和云服务器安全组都放行 TCP 80 和 443。Let's Encrypt 会从多个地点同时验证,不要只对某几个 IP 开放 80 端口。
开始前先检查解析和防火墙:
dig +short example.com A
dig +short www.example.com A
sudo ufw allow 'Nginx Full' # 用 ufw 时才需要
用宝塔面板管理网站的,直接看 宝塔面板配置 SSL 证书,不要再手动改宝塔生成的 Nginx 配置。
第一步:确认 Nginx 有这个域名的 server 配置
Certbot 的 Nginx 插件按 server_name 查找配置,名字必须和要申请的域名一致。只有 HTTP 的最小配置如下:
# /etc/nginx/sites-available/example.com
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
}
启用并检查配置:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
CentOS、Rocky 等系统没有 sites-enabled 目录,把配置放到 /etc/nginx/conf.d/example.com.conf 即可。
第二步:用 snap 安装 Certbot
snap 是 Certbot 官方推荐的安装方式,自带 Nginx 插件和续期定时器。先卸载系统源里的旧版 certbot,避免两个版本冲突:
sudo apt-get remove certbot # 提示未安装可以忽略
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
certbot --version
不能用 snap 时,官方也提供 pip + 虚拟环境的安装方式(官方称“尽力支持”):
sudo apt update
sudo apt install python3 python3-dev python3-venv libaugeas-dev gcc
sudo python3 -m venv /opt/certbot/
sudo /opt/certbot/bin/pip install --upgrade pip
sudo /opt/certbot/bin/pip install certbot certbot-nginx
sudo ln -s /opt/certbot/bin/certbot /usr/local/bin/certbot
国内服务器 pip 下载慢,可以在 pip install 后面加 -i https://pypi.tuna.tsinghua.edu.cn/simple 使用国内镜像。
第三步:申请证书并自动配置 Nginx
一条命令完成 HTTP-01 验证、签发证书、往 server 配置里加 HTTPS 设置并重载 Nginx:
sudo certbot --nginx -d example.com -d www.example.com
过程中需要同意 Let's Encrypt 用户协议,邮箱可以不填:Let's Encrypt 从 2025 年 6 月 4 日起已不再发送到期提醒邮件。在脚本里运行时用非交互模式:
sudo certbot --nginx --non-interactive --agree-tos \
-d example.com -d www.example.com
想自己改 Nginx 配置的,用 sudo certbot certonly --nginx -d example.com -d www.example.com 只申请证书,文件保存在 /etc/letsencrypt/live/example.com/。
第四步:检查 HTTPS 配置
Certbot 改完后,server 配置里应该引用 fullchain.pem 和 privkey.pem,并且 HTTP 会跳转到 HTTPS。自己手写配置可以参考:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on; # Nginx 1.25.1 及以上;更老的版本改成 "listen 443 ssl http2;"
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
root /var/www/example.com;
index index.html;
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
不要加 ssl_stapling 和 ssl_stapling_verify,Let's Encrypt 证书里已经没有 OCSP 地址了。加密套件可以用 TLS 配置生成器 按兼容性需求生成。改完后重载:
sudo nginx -t && sudo systemctl reload nginx
验证
配置正确时,证书颁发者是 Let's Encrypt,curl -I http://example.com 返回 301,Location 指向 https://。从外部检查线上证书:打开 SSL 证书检查,或在任意终端运行:
curl ssl.sh/example.com
在服务器上确认 Certbot 管理的证书和 Nginx 实际返回的证书:
sudo certbot certificates
curl -sI https://example.com | head -n 1
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
自动续期
snap 版已经配置好续期:systemd 定时器 snap.certbot.renew.timer 每天运行两次 certbot renew。Certbot 4.1 及以上会查询 ARI(ACME 续期信息),按 Let's Encrypt 建议的时间续期;没有 ARI 时在剩余三分之一有效期时续期。确认定时器并做一次续期演练:
systemctl list-timers | grep certbot
sudo certbot renew --dry-run
用 --nginx 申请的证书续期后会自动重载 Nginx。用 certonly --webroot 或 --standalone 申请的,要加部署钩子让 Nginx 加载新证书:
sudo certbot reconfigure --cert-name example.com --deploy-hook "systemctl reload nginx"
pip 安装的没有定时器,需要按官方说明加 cron。钩子的详细用法见 Certbot 续期钩子。Let's Encrypt 默认证书 2027 年 2 月 10 日改为 64 天、2028 年 2 月 16 日改为 45 天,只要定时器在跑就不用改任何配置。Let's Encrypt 不再发提醒邮件,建议把域名加到 ssl.sh 监控(开发中) 兜底。
常见问题排查
大部分失败出在解析、端口和 server 配置上。
- Timeout during connect 或 Connection refused:80 端口不通(安全组没放行、运营商封端口、未备案被拦截)或解析不对,见 certbot 连接超时。端口实在打不开就改用 DNS-01 验证。
- Could not automatically find a matching server block:
server_name里没写对应域名,补上后重新运行。 - too many certificates already issued:测试时触发了频率限制,测试请用
--dry-run或--test-cert(测试环境),见 Let's Encrypt 频率限制。 - CAA record prevents issuance:域名的 CAA 记录没有允许
letsencrypt.org,见 CAA 记录阻止签发。 - 重载 Nginx 报 key values mismatch:证书和私钥不是一对,见 nginx key values mismatch。
- 访问
www报 NET::ERR_CERT_COMMON_NAME_INVALID:证书里没有这个域名,带上所有-d重新运行并选择 Expand,见 NET::ERR_CERT_COMMON_NAME_INVALID。 - 浏览器正常但 curl、小程序或 App 报错:Nginx 用了
cert.pem,见 缺少中间证书。
常见问题
Nginx 里该用 cert.pem 还是 fullchain.pem?
用 fullchain.pem。它包含你的证书和 Let's Encrypt 的中间证书;cert.pem 只有站点证书,部分浏览器因为缓存了中间证书能打开,但 curl、Java、安卓 App 和微信小程序会报证书链不完整。
还需要配置 ssl_stapling 吗?
Let's Encrypt 证书不需要。Let's Encrypt 2025 年 5 月起签发的证书已不含 OCSP 地址,8 月关闭了 OCSP 服务。开着 ssl_stapling on; 只会让 Nginx 在日志里警告证书没有 OCSP 地址,删掉相关配置即可。
服务器 80 端口不通或者域名没备案,还能用 certbot --nginx 申请证书吗?
不能。certbot --nginx 用的是 HTTP-01 验证,Let's Encrypt 必须能从公网访问你服务器的 80 端口。80 端口被封、域名未备案无法开放访问时,改用 DNS-01 验证,见 acme.sh + 阿里云 DNS/DNSPod 申请通配符证书。
能用 certbot --nginx 申请通配符证书吗?
不能。*.example.com 这类通配符证书只能用 DNS-01 验证。国内 DNS 推荐用 acme.sh 的 DNS API,域名在 Cloudflare 的可以用 Certbot Cloudflare DNS 插件。
怎么改用 45 天的 tlsserver 证书?
Certbot 4.0 及以上支持 --preferred-profile tlsserver(或 --required-profile),4.1 起会把选择保存到续期配置里。切换前先看 Let's Encrypt 证书配置文件,保证续期至少每天检查一次。