Nginx + Certbot 免费 HTTPS 证书与自动续期(Webroot 方式)
本文记录一次 Nginx 使用 Certbot 申请 HTTPS 证书时,旧证书因 manual 方式无法自动续期的问题。适合使用 Nginx、希望免费部署 SSL 证书的站长阅读。看完可完成 Webroot 验证、首次签发、HTTPS 配置、定时自动续期及续期后自动重载 Nginx。
本文以 site.example.com 为示例域名。请将它替换成自己的真实域名。
本文假设 Nginx 安装目录为/usr/local/nginx,并使用/etc/init.d/nginx reload平滑重载。若你的服务器使用systemctl管理 Nginx,将对应命令替换为systemctl reload nginx。
1. 适用范围
适用于:
- 单个域名或子域名,例如
site.example.com - DNS 已解析到当前服务器公网 IP
- 使用 Nginx 对外提供 HTTP/HTTPS 服务
- 希望通过 Let's Encrypt + Certbot 免费申请并自动续期证书
- 使用 HTTP-01 验证,也就是 Let’s Encrypt 通过 80 端口访问验证文件
2. 前提检查
2.1 DNS 与端口
申请前必须满足:
site.example.com的 A 记录已经解析到当前服务器公网 IP。- 服务器安全组、防火墙已放行 TCP
80和443端口。 - Nginx 已启动,并能从公网访问
http://site.example.com。
可检查解析结果:
ping site.example.com
Ping 被禁并不一定代表 DNS 有问题;重点是域名解析出的 IP 是否为当前服务器公网 IP。
2.2 安装 Certbot(Ubuntu/Debian)
已安装可跳过:
apt update
apt install -y certbot
确认版本:
certbot --version
3. 创建统一的 ACME 验证目录
mkdir -p /usr/local/nginx/acme-webroot/.well-known/acme-challenge
这个目录用于临时放置 Let's Encrypt 的验证文件。
创建 Nginx 公共配置片段:
cat > /usr/local/nginx/conf/certbot-acme.conf <<'EOF'
location ^~ /.well-known/acme-challenge/ {
root /usr/local/nginx/acme-webroot;
default_type "text/plain";
try_files $uri =404;
}
EOF
4. 第一次申请证书:先配置 HTTP 站点
在 Nginx 已启用的虚拟主机配置目录中,新建或修改域名配置。例如:
vi /usr/local/nginx/conf/vhost/site.example.com.conf
首次申请证书时,先使用下面的 HTTP 配置:
server {
listen 80;
server_name site.example.com;
include /usr/local/nginx/conf/certbot-acme.conf;
location / {
return 404;
}
}
说明:
/.well-known/acme-challenge/由 Certbot 验证路径专门处理。- 其他路径暂时返回
404,这是首次部署、尚未配置 HTTPS 时的安全默认行为。 - 不要在尚未申请到证书前就强制跳转 HTTPS。
检查并平滑加载 Nginx:
/usr/local/nginx/sbin/nginx -t && /etc/init.d/nginx reload
5. 先验证 ACME 路径是否可被公网访问
创建一个测试文件:
echo "certbot-ok" > /usr/local/nginx/acme-webroot/.well-known/acme-challenge/test.txt
访问测试:
curl http://site.example.com/.well-known/acme-challenge/test.txt
正常应返回:
certbot-ok
验证完成后可以删除测试文件:
rm -f /usr/local/nginx/acme-webroot/.well-known/acme-challenge/test.txt
6. 申请正式证书
certbot certonly --webroot \
--cert-name site.example.com \
-w /usr/local/nginx/acme-webroot \
-d site.example.com
成功后,证书文件通常在:
/etc/letsencrypt/live/site.example.com/fullchain.pem
/etc/letsencrypt/live/site.example.com/privkey.pem
查看已申请的所有证书:
certbot certificates
若一个证书需要包含多个域名,例如site.example.com和www.site.example.com,首次申请时必须同时写出所有域名,并确保每个域名都已解析到本服务器:
certbot certonly --webroot \
--cert-name site.example.com \
-w /usr/local/nginx/acme-webroot \
-d site.example.com \
-d www.site.example.com
7. 申请成功后,改为 HTTP 跳转 HTTPS
将虚拟主机配置改成下面形式:
server {
listen 80;
server_name site.example.com;
include /usr/local/nginx/conf/certbot-acme.conf;
location / {
return 301 https://site.example.com$request_uri;
}
}
server {
listen 443 ssl http2;
server_name site.example.com;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_certificate /etc/letsencrypt/live/site.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/site.example.com/privkey.pem;
# 按实际项目配置网站根目录、PHP、反向代理等。
location / {
return 404;
}
}
检查并平滑加载 Nginx:
/usr/local/nginx/sbin/nginx -t && /etc/init.d/nginx reload
验证:
curl -I http://site.example.com
curl -I https://site.example.com
预期:
- HTTP 返回
301,并跳转到 HTTPS。 - HTTPS 能正常建立连接。
/.well-known/acme-challenge/仍可在 HTTP 下访问,供未来自动续期使用。
8. 启用 Certbot 自动续期定时器
Ubuntu/Debian 常用的 Certbot 定时器:
systemctl enable --now certbot.timer
查看状态:
systemctl status certbot.timer
看到类似以下状态,说明已启用:
Loaded: loaded (...; enabled; ...)
Active: active (waiting)
Certbot 会定期检查全部证书;证书接近到期时才会真正续期,不会每天重复签发。
9. 续期成功后自动重载 Nginx
证书文件更新后,Nginx 需要 reload 才能立即载入新证书。
创建 Certbot 的 deploy hook:
mkdir -p /etc/letsencrypt/renewal-hooks/deploy
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'EOF'
#!/bin/sh
/usr/local/nginx/sbin/nginx -t && /etc/init.d/nginx reload
EOF
chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
确认脚本内容:
cat /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Certbot 会在任意证书真实续期成功后,自动执行此目录中具有执行权限的脚本。
手动检查脚本是否正常:
/usr/local/nginx/sbin/nginx -t && /etc/init.d/nginx reload
若系统使用 systemd 管理 Nginx,可将脚本中的第二部分改为:
systemctl reload nginx
10. 模拟续期测试
只测试当前证书,避免服务器上其他旧证书影响结果:
certbot renew --cert-name site.example.com --dry-run
成功时会看到类似:
The following certs were successfully renewed:
/etc/letsencrypt/live/site.example.com/fullchain.pem (success)
--dry-run 是模拟测试:
- 会验证域名、HTTP 验证路径和续期配置;
- 不会替换正式证书;
- 不会改变现有证书到期时间。
不建议在存在旧证书的服务器上直接以 certbot renew --dry-run 测试全部证书。
旧证书若曾用 manual 方式申请,可能无法自动续期,从而显示失败;这不会代表当前 Webroot 证书配置失败。
11. 常见问题
11.1 curl 验证文件返回 404
检查:
- Nginx 配置是否已
reload。 certbot-acme.conf是否确实被include在当前域名的server {}内。- 验证文件是否位于:
/usr/local/nginx/acme-webroot/.well-known/acme-challenge/
- 域名是否解析到当前服务器。
11.2 Certbot 提示连接超时或无法验证
通常是:
- 域名 A/AAAA 记录不正确;
- 80 端口未开放;
- 云服务器安全组未开放 80 端口;
- 另一个 Web 服务器或 CDN 接管了该域名;
- HTTP 被强制跳转到错误站点或错误域名。
11.3 旧证书提示 manual plugin 无法自动续期
说明该证书以前是用手动 DNS/文本验证方式申请的,缺少自动验证脚本。
解决方式:后续为该域名补上 Webroot 验证路径后,用本文的 certbot certonly --webroot ... 方式重新申请或更新该证书。
11.4 为什么优先使用 reload,不使用 restart
推荐:
/usr/local/nginx/sbin/nginx -t && /etc/init.d/nginx reload
原因:
- 先检查配置语法;
- 配置错误时不会重载;
- 平滑加载新配置和新证书;
- 通常不会中断现有访问。
restart 会先停止再启动;如果新配置有错误,可能导致 Nginx 无法重新启动,网站暂时不可访问。
12. 常用命令速查
# 查看已申请证书
certbot certificates
# 查看自动续期定时器
systemctl status certbot.timer
# 只模拟测试某一张证书
certbot renew --cert-name site.example.com --dry-run
# 检查 Nginx 配置并平滑重载
/usr/local/nginx/sbin/nginx -t && /etc/init.d/nginx reload
# 查看 Certbot 续期成功后的重载脚本
cat /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh