Let's Encrypt 免费 SSL 证书全流程指南
概述
Let's Encrypt 是一个免费、自动化和开放的证书颁发机构(CA),提供免费的 SSL/TLS 证书。它通过 ACME(Automated Certificate Management Environment)协议实现证书的自动颁发和续期。
主要特点
- 完全免费:无需支付任何费用
- 自动化:支持自动颁发和续期
- 开放透明:所有证书记录公开可查
- 安全可靠:符合行业标准的加密算法
实际环境说明
本文档基于实际的 Nginx 配置结构(docs/technical/operation/nginx-conf/),包含以下域名:
- admin.cqcjg.com - 管理后台前端(静态文件服务)
- gateway.cqcjg.com - API 网关(反向代理到 localhost:9999)
配置结构:
- Nginx 安装目录:
/tools/nginx/ - 主配置文件:
/tools/nginx/conf/nginx.conf - 主机配置目录:
/tools/nginx/conf/hosts/hosts/admin.cqcjg.com.confhosts/gateway.cqcjg.com.conf
- 日志目录:
/tools/nginx/logs/ - 网站根目录:
/tools/nginx/html/admin/dist/ - 证书验证目录:
/tools/nginx/html/.well-known/acme-challenge/
目录
第一次申请证书流程
前置准备
1. 安装 Certbot
Ubuntu/Debian:
sudo apt update
sudo apt install certbot
CentOS/RHEL:
sudo yum install epel-release
sudo yum install certbot
2. 确保域名 DNS 解析正确
重要: 域名必须正确绑定配置的服务器公网 IP,否则证书申请会失败。
# 获取服务器公网 IP
SERVER_IP=$(curl -s ifconfig.me)
echo "服务器公网 IP: $SERVER_IP"
# 检查域名 DNS 解析
dig admin.cqcjg.com +short
dig gateway.cqcjg.com +short
# 验证 DNS 解析是否正确
DNS_IP=$(dig admin.cqcjg.com +short | head -1)
if [ "$SERVER_IP" = "$DNS_IP" ]; then
echo "✓ DNS 解析正确"
else
echo "✗ DNS 解析错误"
echo " 服务器 IP: $SERVER_IP"
echo " DNS 解析 IP: $DNS_IP"
echo " 请到域名 DNS 管理后台添加 A 记录指向服务器 IP"
fi
如果 DNS 解析不正确:
- 登录域名 DNS 管理后台(如阿里云、腾讯云等)
- 添加 A 记录:
- 主机记录:
admin(对于 admin.cqcjg.com) - 主机记录:
gateway(对于 gateway.cqcjg.com) - 记录类型:
A - 记录值:服务器的公网 IP 地址
- TTL:600
- 主机记录:
- 等待 DNS 生效(通常几分钟到几小时)
3. 确保 80 端口可访问
# 检查 80 端口是否开放
sudo netstat -tlnp | grep :80
# 或
sudo ss -tlnp | grep :80
# 检查防火墙
sudo ufw status # Ubuntu
sudo firewall-cmd --list-all # CentOS
# 确保防火墙允许 80 和 443 端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
第一次申请证书步骤
步骤 1: 创建验证目录
# 创建验证目录
sudo mkdir -p /tools/nginx/html/.well-known/acme-challenge
# 设置目录权限
sudo chmod -R 755 /tools/nginx/html
步骤 2: 配置 Nginx 支持 HTTP 验证(首次申请需要特殊处理)
⚠️ 重要提示:首次申请证书前的配置处理
配置文件已经包含了完整的 HTTPS 配置,但是在证书申请之前,证书文件还不存在。如果直接启动 Nginx,会报错:
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/admin.cqcjg.com/fullchain.pem":
BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory)
解决方案:在申请证书之前,需要先注释掉 HTTPS 配置块
编辑配置文件:
# 编辑配置文件
sudo nano /tools/nginx/conf/hosts/admin.cqcjg.com.conf
sudo nano /tools/nginx/conf/hosts/gateway.cqcjg.com.conf
hosts/admin.cqcjg.com.conf - 首次申请时的配置:
# HTTP 服务器配置
server {
listen 80;
server_name admin.cqcjg.com;
# Let's Encrypt 验证路径
location /.well-known/acme-challenge/ {
root /tools/nginx/html;
try_files $uri =404;
}
# 其他请求暂时不重定向(证书申请时需要返回200)
location / {
return 200 "Certificate validation in progress";
add_header Content-Type text/plain;
}
}
# HTTPS 服务器配置 - 第一次申请证书需要注释
# server {
# listen 443 ssl http2;
# server_name admin.cqcjg.com;
# ...
# }
hosts/gateway.cqcjg.com.conf - 首次申请时的配置:
# HTTP 服务器配置
server {
listen 80;
server_name gateway.cqcjg.com;
# Let's Encrypt 验证路径
location /.well-known/acme-challenge/ {
root /tools/nginx/html;
try_files $uri =404;
}
# 其他请求暂时不重定向(证书申请时需要返回200)
location / {
return 200 "Certificate validation in progress";
add_header Content-Type text/plain;
}
}
# HTTPS 服务器配置 - 第一次申请证书需要注释
# server {
# listen 443 ssl http2;
# server_name gateway.cqcjg.com;
# ...
# }
步骤 3: 启动 Nginx
重要: 必须先启动 Nginx,才能进行后续的验证目录测试和证书申请。
# 进入 Nginx 目录
cd /tools/nginx/sbin
# 测试配置
./nginx -t -c /tools/nginx/conf/nginx.conf
# 启动 Nginx
./nginx -c /tools/nginx/conf/nginx.conf
# 或者如果已经在运行,重载配置
./nginx -s reload -c /tools/nginx/conf/nginx.conf
验证 Nginx 是否正常运行:
# 检查 Nginx 进程
ps aux | grep nginx
# 应该看到 80 端口在监听
步骤 4: 测试验证目录可访问
重要: 必须先完成步骤 3(启动 Nginx),才能进行此步骤的测试。
# 创建测试文件
echo "test-validation" | sudo tee /tools/nginx/html/.well-known/acme-challenge/test.txt
# 测试访问(应该能访问到 test-validation)
# 注意:如果 Nginx 未启动,这些命令会失败
curl http://admin.cqcjg.com/.well-known/acme-challenge/test.txt
curl http://gateway.cqcjg.com/.well-known/acme-challenge/test.txt
# 如果都能正常访问,删除测试文件
sudo rm /tools/nginx/html/.well-known/acme-challenge/test.txt
如果 curl 命令失败,检查:
- Nginx 是否已启动(参考步骤 3)
- 80 端口是否在监听
- 防火墙是否允许 80 端口访问
- 域名 DNS 是否正确解析
步骤 5: 检查 DNS 解析(重要)
在申请证书之前,必须先确保域名 DNS 解析正确!
Let's Encrypt 需要能够通过 DNS 解析找到您的服务器,如果 DNS 解析失败,会出现以下错误:
no valid A records found for admin.cqcjg.com; no valid AAAA records found for admin.cqcjg.com
检查 DNS 解析:
# 1. 获取服务器公网 IP
SERVER_IP=$(curl -s ifconfig.me)
echo "服务器公网 IP: $SERVER_IP"
# 2. 检查域名 DNS 解析
echo "检查 admin.cqcjg.com DNS 解析:"
dig admin.cqcjg.com +short
nslookup admin.cqcjg.com
echo "检查 gateway.cqcjg.com DNS 解析:"
dig gateway.cqcjg.com +short
nslookup gateway.cqcjg.com
# 3. 验证 DNS 解析是否正确
DNS_IP=$(dig admin.cqcjg.com +short | head -1)
if [ "$SERVER_IP" = "$DNS_IP" ]; then
echo "✓ admin.cqcjg.com DNS 解析正确"
else
echo "✗ admin.cqcjg.com DNS 解析错误"
echo " 服务器 IP: $SERVER_IP"
echo " DNS 解析 IP: $DNS_IP"
echo " 请到域名 DNS 管理后台添加 A 记录指向服务器 IP"
exit 1
fi
如果 DNS 解析不正确,请先配置 DNS 记录,等待生效后再继续。
步骤 6: 申请证书
根据实际配置,两个域名使用独立的证书。分别申请:
申请 admin.cqcjg.com 证书:
sudo certbot certonly --webroot \
-w /tools/nginx/html \
-d admin.cqcjg.com \
--email cqchejiaguan@163.com \
--agree-tos \
--no-eff-email
申请 gateway.cqcjg.com 证书:
sudo certbot certonly --webroot \
-w /tools/nginx/html \
-d gateway.cqcjg.com \
--email cqchejiaguan@163.com \
--agree-tos \
--no-eff-email
参数说明:
--webroot: 使用 webroot 方式验证-w: 指定 webroot 目录(/tools/nginx/html)-d: 指定域名--email: 邮箱地址,用于接收证书到期提醒--agree-tos: 同意服务条款--no-eff-email: 不订阅 EFF 邮件列表
可选:申请多域名证书
如果希望两个域名使用同一个证书(便于管理),可以这样申请:
sudo certbot certonly --webroot \
-w /tools/nginx/html \
-d admin.cqcjg.com \
-d gateway.cqcjg.com \
--email cqchejiaguan@163.com \
--agree-tos \
--no-eff-email
如果使用多域名证书,需要在 gateway.cqcjg.com.conf 中修改证书路径为:
ssl_certificate /etc/letsencrypt/live/admin.cqcjg.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/admin.cqcjg.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/admin.cqcjg.com/chain.pem;
步骤 7: 验证证书文件
证书申请成功后,验证证书文件是否存在:
# 查看 admin.cqcjg.com 证书文件
sudo ls -la /etc/letsencrypt/live/admin.cqcjg.com/
# 查看 gateway.cqcjg.com 证书文件
sudo ls -la /etc/letsencrypt/live/gateway.cqcjg.com/
应该看到以下文件:
/etc/letsencrypt/live/域名/ 目录下:
├── cert.pem # 证书文件
├── chain.pem # 中间证书链
├── fullchain.pem # 完整证书链(cert.pem + chain.pem)
└── privkey.pem # 私钥文件
重要提示:
fullchain.pem用于 Nginx 的ssl_certificate配置privkey.pem用于 Nginx 的ssl_certificate_key配置chain.pem用于 Nginx 的ssl_trusted_certificate配置(OCSP Stapling)
查看证书详细信息:
# 查看证书有效期
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -noout -dates
# 查看证书信息
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -text -noout | head -20
步骤 8: 确认配置文件中的证书路径
配置文件已经包含了正确的证书路径,无需修改:
hosts/admin.cqcjg.com.conf 中的证书配置:
ssl_certificate /etc/letsencrypt/live/admin.cqcjg.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/admin.cqcjg.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/admin.cqcjg.com/chain.pem;
hosts/gateway.cqcjg.com.conf 中的证书配置:
ssl_certificate /etc/letsencrypt/live/gateway.cqcjg.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/gateway.cqcjg.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/gateway.cqcjg.com/chain.pem;
步骤 9: 恢复 HTTPS 配置并测试
证书申请成功后,需要恢复完整的 HTTPS 配置:
1. 取消注释 HTTPS 配置块
编辑两个配置文件,取消注释之前注释掉的 HTTPS server 块:
# 编辑配置文件
sudo nano /tools/nginx/conf/hosts/admin.cqcjg.com.conf
sudo nano /tools/nginx/conf/hosts/gateway.cqcjg.com.conf
2. 恢复 HTTP 到 HTTPS 的重定向
将 HTTP 配置中的临时返回改为重定向:
# 其他请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
完整的配置示例(证书申请后):
hosts/admin.cqcjg.com.conf:
# HTTP 服务器配置 - 重定向到 HTTPS
server {
listen 80;
server_name admin.cqcjg.com;
# Let's Encrypt 验证路径
location /.well-known/acme-challenge/ {
root /tools/nginx/html;
try_files $uri =404;
}
# 其他请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 服务器配置
server {
listen 443 ssl http2;
server_name admin.cqcjg.com;
# SSL 证书配置(Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/admin.cqcjg.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/admin.cqcjg.com/privkey.pem;
# 现代加密协议
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
# SSL 会话配置
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP Stapling(提高性能)
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/admin.cqcjg.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS 安全头(推荐)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 网站根目录
root /tools/nginx/html/admin/dist;
# 配置页面路由(访问 / 时,访问 网站根目录下的 index.html 文件)
location = / {
index index.html;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 日志配置
access_log /tools/nginx/logs/admin.cqcjg.com.access.log main;
error_log /tools/nginx/logs/admin.cqcjg.com.error.log error;
}
hosts/gateway.cqcjg.com.conf:
# HTTP 服务器配置 - 重定向到 HTTPS
server {
listen 80;
server_name gateway.cqcjg.com;
# Let's Encrypt 验证路径
location /.well-known/acme-challenge/ {
root /tools/nginx/html;
try_files $uri =404;
}
# 其他请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 服务器配置
server {
listen 443 ssl http2;
server_name gateway.cqcjg.com;
# SSL 证书配置(Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/gateway.cqcjg.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/gateway.cqcjg.com/privkey.pem;
# 现代加密协议
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
# SSL 会话配置
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP Stapling(提高性能)
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/gateway.cqcjg.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS 安全头(推荐)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# API代理到本地后端
location / {
proxy_pass http://localhost:9999/;
# 代理请求头
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
# 不缓冲响应
proxy_request_buffering off;
}
# 日志配置
access_log /tools/nginx/logs/gateway.cqcjg.com.access.log main;
error_log /tools/nginx/logs/gateway.cqcjg.com.error.log error;
}
3. 创建必要的目录
# 创建日志目录
sudo mkdir -p /tools/nginx/logs
# 创建网站根目录(admin.cqcjg.com)
sudo mkdir -p /tools/nginx/html/admin/dist
4. 测试并重载 Nginx
# 测试 Nginx 配置语法(使用绝对路径)
cd /tools/nginx/sbin
./nginx -t -c /tools/nginx/conf/nginx.conf
# 如果测试通过,重载 Nginx(不中断服务)
./nginx -s reload -c /tools/nginx/conf/nginx.conf
⚠️ 关于 OCSP Stapling 警告:
如果看到以下警告信息,这是正常的,不会影响 HTTPS 的正常工作:
nginx: [warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate
警告原因:
- 某些证书(包括部分 Let's Encrypt 证书)可能不包含 OCSP responder URL
- Nginx 无法获取 OCSP 响应,因此忽略 OCSP Stapling 配置
- 这只是一个警告,不是错误,HTTPS 仍然可以正常工作
解决方案(可选):
方案一:忽略警告(推荐)
- 警告不影响功能,可以安全忽略
- HTTPS 连接仍然安全可靠
方案二:禁用 OCSP Stapling(如果不想看到警告)
如果不想看到警告,可以注释掉 OCSP Stapling 相关配置:
# OCSP Stapling(提高性能)
# ssl_stapling on;
# ssl_stapling_verify on;
# ssl_trusted_certificate /etc/letsencrypt/live/admin.cqcjg.com/chain.pem;
# resolver 8.8.8.8 8.8.4.4 valid=300s;
# resolver_timeout 5s;
然后重载 Nginx:
cd /tools/nginx/sbin
./nginx -s reload -c /tools/nginx/conf/nginx.conf
步骤 10: 验证 HTTPS 访问
证书配置完成后,验证 HTTPS 是否正常工作:
# 测试 admin.cqcjg.com HTTPS 访问
curl -I https://admin.cqcjg.com
# 测试 gateway.cqcjg.com HTTPS 访问
curl -I https://gateway.cqcjg.com
# 使用浏览器访问,检查证书是否正常
# 或使用在线工具检查:https://www.ssllabs.com/ssltest/
验证要点:
- 浏览器地址栏显示锁图标
- 证书信息显示正确的域名
- 没有安全警告
- SSL Labs 测试评分达到 A 或 A+
证书续期流程
Let's Encrypt 证书有效期为 90 天,需要定期续期。Certbot 提供了自动续期功能。
续期流程概览
完整的证书续期流程:
- 检查证书状态 - 查看证书有效期和续期配置
- 配置自动续期 - 设置自动续期任务和钩子脚本
- 测试续期流程 - 使用
--dry-run测试续期是否正常 - 监控证书有效期 - 设置监控脚本,及时发现问题
- 处理续期问题 - 排查和解决续期失败的问题
续期方式:
- 自动续期(推荐):Certbot 自动在证书到期前续期
- 手动续期:需要时手动执行续期命令
续期流程详细步骤
步骤 1: 检查当前证书状态
在配置续期之前,先检查当前证书的状态:
# 查看所有证书及其状态
sudo certbot certificates
# 查看证书有效期
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -noout -dates
sudo openssl x509 -in /etc/letsencrypt/live/gateway.cqcjg.com/cert.pem -noout -dates
# 查看证书剩余天数
for domain in admin.cqcjg.com gateway.cqcjg.com; do
echo "=== $domain ==="
cert_file="/etc/letsencrypt/live/$domain/cert.pem"
if [ -f "$cert_file" ]; then
expiry=$(openssl x509 -enddate -noout -in "$cert_file" | cut -d= -f2)
expiry_epoch=$(date -d "$expiry" +%s 2>/dev/null || date -j -f "%b %d %H:%M:%S %Y" "$expiry" +%s)
current_epoch=$(date +%s)
days_left=$(( ($expiry_epoch - $current_epoch) / 86400 ))
echo "证书有效期剩余: $days_left 天"
else
echo "证书文件不存在"
fi
done
步骤 2: 配置自动续期
2.1 测试自动续期
在配置自动续期之前,先测试续期流程是否正常:
# 测试续期(不会真正续期,只是测试流程)
sudo certbot renew --dry-run
# 使用详细模式查看测试过程
sudo certbot renew --dry-run -v
测试成功的标志:
- 显示 "The dry run was successful"
- 没有错误信息
- 所有证书都能正常验证
如果测试成功,说明自动续期配置正常。如果测试失败,请参考"问题解决流程"部分进行排查。
2.2 查看自动续期任务
Certbot 会自动创建 systemd timer 或 cron 任务:
systemd 系统(Ubuntu 16.04+, CentOS 7+):
# 查看 systemd timer
systemctl list-timers | grep certbot
# 查看 timer 状态
systemctl status certbot.timer
# 查看 timer 配置
systemctl cat certbot.timer
非 systemd 系统:
# 查看 cron 任务
sudo crontab -l | grep certbot
# 或查看系统 cron
sudo cat /etc/cron.d/certbot
2.3 配置续期后自动重载 Nginx
创建续期后钩子脚本,证书续期成功后自动重载 Nginx:
# 创建续期后钩子脚本目录
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
# 创建重载脚本
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
添加以下内容:
#!/bin/bash
# 证书续期后自动重载 Nginx
NGINX_BIN="/tools/nginx/sbin/nginx"
NGINX_CONF="/tools/nginx/conf/nginx.conf"
# 测试 Nginx 配置
if $NGINX_BIN -t -c $NGINX_CONF > /dev/null 2>&1; then
# 配置正确,重载 Nginx
$NGINX_BIN -s reload -c $NGINX_CONF
echo "$(date): Nginx reloaded after certificate renewal" >> /var/log/letsencrypt/renewal.log
else
# 配置错误,记录日志
echo "$(date): Nginx configuration test failed, not reloading" >> /var/log/letsencrypt/renewal.log
exit 1
fi
设置执行权限:
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
2.4 测试续期钩子
# 测试续期(包含钩子执行)
sudo certbot renew --dry-run
# 查看钩子日志
sudo tail -f /var/log/letsencrypt/renewal.log
步骤 3: 手动续期(可选)
如果需要手动续期证书(例如测试或紧急情况):
# 续期所有证书(只续期即将到期的证书)
sudo certbot renew
# 续期指定证书
sudo certbot renew --cert-name admin.cqcjg.com
# 强制续期(即使未到期,用于测试)
sudo certbot renew --force-renewal
# 使用详细模式查看续期过程
sudo certbot renew --force-renewal -v
手动续期后,需要重载 Nginx:
# 测试配置
cd /tools/nginx/sbin
./nginx -t -c /tools/nginx/conf/nginx.conf
# 重载配置
./nginx -s reload -c /tools/nginx/conf/nginx.conf
注意: 如果配置了续期钩子脚本(步骤 2.3),续期成功后会自动重载 Nginx,无需手动操作。
步骤 4: 验证续期结果
续期完成后,验证证书是否已成功更新:
# 1. 查看所有证书状态
sudo certbot certificates
# 2. 检查证书有效期(应该显示新的到期时间)
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -noout -dates
sudo openssl x509 -in /etc/letsencrypt/live/gateway.cqcjg.com/cert.pem -noout -dates
# 3. 验证 Nginx 是否已重载(检查进程启动时间)
ps aux | grep nginx
# 4. 测试 HTTPS 访问是否正常
curl -I https://admin.cqcjg.com
curl -I https://gateway.cqcjg.com
步骤 5: 设置证书有效期监控
5.1 检查证书有效期
# 查看证书有效期
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -noout -dates
# 查看所有证书状态
sudo certbot certificates
5.2 创建证书有效期监控脚本
创建监控脚本,定期检查证书有效期:
# 创建监控脚本
sudo nano /usr/local/bin/check-cert-expiry.sh
添加以下内容:
#!/bin/bash
# 检查证书有效期
DOMAINS=("admin.cqcjg.com" "gateway.cqcjg.com")
WARNING_DAYS=30 # 提前 30 天警告
for DOMAIN in "${DOMAINS[@]}"; do
CERT_PATH="/etc/letsencrypt/live/$DOMAIN/cert.pem"
if [ -f "$CERT_PATH" ]; then
EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$CERT_PATH" | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s 2>/dev/null || date -j -f "%b %d %H:%M:%S %Y" "$EXPIRY_DATE" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt $WARNING_DAYS ]; then
echo "警告: $DOMAIN 证书将在 $DAYS_LEFT 天后过期!"
# 可以添加邮件通知等
else
echo "$DOMAIN 证书有效期剩余: $DAYS_LEFT 天"
fi
else
echo "错误: $DOMAIN 证书文件不存在: $CERT_PATH"
fi
done
设置执行权限:
sudo chmod +x /usr/local/bin/check-cert-expiry.sh
添加到 cron 任务(每周检查一次):
# 编辑 crontab
sudo crontab -e
# 添加以下行(每周一早上 9 点检查)
0 9 * * 1 /usr/local/bin/check-cert-expiry.sh >> /var/log/cert-check.log 2>&1
手动执行检查:
# 手动检查证书有效期
sudo /usr/local/bin/check-cert-expiry.sh
续期流程总结
完整的续期操作流程:
# 1. 检查证书状态
sudo certbot certificates
# 2. 测试自动续期(首次配置时)
sudo certbot renew --dry-run
# 3. 配置续期钩子(首次配置时,参考步骤 2.3)
# 创建 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
# 4. 验证自动续期任务(首次配置时)
systemctl list-timers | grep certbot
# 5. 手动续期(需要时)
sudo certbot renew
# 6. 验证续期结果
sudo certbot certificates
curl -I https://admin.cqcjg.com
curl -I https://gateway.cqcjg.com
续期时间线:
- Let's Encrypt 证书有效期:90 天
- 自动续期触发时间:证书到期前 30 天
- 建议检查频率:每周检查一次证书状态
- 建议测试频率:每月测试一次自动续期流程
问题解决流程
问题 1: Nginx 启动失败 - 证书文件不存在(首次申请证书)
错误信息:
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/admin.cqcjg.com/fullchain.pem":
BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:
calling fopen(/etc/letsencrypt/live/admin.cqcjg.com/fullchain.pem, r)
error:10000080:BIO routines::no such file)
问题原因: 配置文件已经包含了 SSL 证书路径,但是证书文件还没有申请,所以 Nginx 无法启动。
解决方案:
方法一:注释 HTTPS 配置(推荐)
在申请证书之前,临时注释掉 HTTPS server 块:
# 编辑配置文件
sudo nano /tools/nginx/conf/hosts/admin.cqcjg.com.conf
sudo nano /tools/nginx/conf/hosts/gateway.cqcjg.com.conf
注释掉整个 HTTPS server 块(从 # HTTPS 服务器配置 开始到对应的 } 结束)。
证书申请完成后:
- 取消注释 HTTPS 配置块
- 恢复 HTTP 到 HTTPS 的重定向
- 测试配置:
cd /tools/nginx/sbin && ./nginx -t -c /tools/nginx/conf/nginx.conf - 重载配置:
cd /tools/nginx/sbin && ./nginx -s reload -c /tools/nginx/conf/nginx.conf
详细步骤请参考"第一次申请证书流程"中的"步骤 2"和"步骤 9"。
问题 2: 证书申请失败 - DNS 解析问题
错误信息:
no valid A records found for admin.cqcjg.com; no valid AAAA records found for admin.cqcjg.com
问题原因: 域名 DNS 没有正确解析到服务器 IP,Let's Encrypt 无法通过 DNS 找到服务器。
解决方案:
1. 检查服务器 IP:
# 查看服务器公网 IP
curl ifconfig.me
# 或
curl ip.sb
2. 检查 DNS 解析:
# 检查域名解析
dig admin.cqcjg.com +short
dig gateway.cqcjg.com +short
# 使用 dig 查看完整 DNS 信息
dig admin.cqcjg.com
dig gateway.cqcjg.com
3. 在域名 DNS 管理后台添加 A 记录:
- 登录域名 DNS 管理后台(如阿里云、腾讯云等)
- 添加 A 记录:
- 主机记录:
admin(对于 admin.cqcjg.com) - 主机记录:
gateway(对于 gateway.cqcjg.com) - 记录类型:
A - 记录值:服务器的公网 IP 地址
- TTL:600
- 主机记录:
4. 等待 DNS 生效:
- DNS 记录通常需要几分钟到几小时才能全球生效
- 可以使用以下命令检查 DNS 是否已生效:
# 检查 DNS 是否已更新(从不同 DNS 服务器查询)
dig @8.8.8.8 admin.cqcjg.com +short
dig @114.114.114.114 admin.cqcjg.com +short
dig @223.5.5.5 admin.cqcjg.com +short
5. 验证 DNS 解析是否正确:
# 确保解析的 IP 与服务器 IP 一致
SERVER_IP=$(curl -s ifconfig.me)
DNS_IP=$(dig admin.cqcjg.com +short)
echo "服务器 IP: $SERVER_IP"
echo "DNS 解析 IP: $DNS_IP"
if [ "$SERVER_IP" = "$DNS_IP" ]; then
echo "✓ DNS 解析正确"
else
echo "✗ DNS 解析错误,请检查 DNS 配置"
fi
问题 3: 证书申请失败 - 验证失败
错误信息:
Failed to verify domain ownershipThe server could not prove that it is admin.cqcjg.com
可能原因:
- DNS 解析问题(最常见,参考问题 2)
- 80 端口无法访问
- 验证目录权限问题
- Nginx 配置未正确加载
- 防火墙阻止了 Let's Encrypt 服务器的访问
解决方案:
# 1. 检查 DNS 解析(参考问题 2)
# 2. 检查 80 端口是否可访问
sudo netstat -tlnp | grep :80
# 或
sudo ss -tlnp | grep :80
# 3. 检查 Nginx 是否运行
ps aux | grep nginx
# 4. 检查防火墙是否允许 80 端口
sudo ufw status
sudo firewall-cmd --list-all
# 5. 检查验证目录权限
sudo ls -la /tools/nginx/html/.well-known/acme-challenge/
# 确保目录权限为 755
# 6. 手动测试验证路径(从服务器本地测试)
echo "test-validation" | sudo tee /tools/nginx/html/.well-known/acme-challenge/test.txt
curl http://localhost/.well-known/acme-challenge/test.txt
curl http://admin.cqcjg.com/.well-known/acme-challenge/test.txt
curl http://gateway.cqcjg.com/.well-known/acme-challenge/test.txt
sudo rm /tools/nginx/html/.well-known/acme-challenge/test.txt
# 7. 检查 Nginx 配置是否正确加载
cd /tools/nginx/sbin
./nginx -t -c /tools/nginx/conf/nginx.conf
./nginx -s reload -c /tools/nginx/conf/nginx.conf
# 8. 查看 Certbot 详细日志
sudo certbot certonly --webroot \
-w /tools/nginx/html \
-d admin.cqcjg.com \
--email cqchejiaguan@163.com \
--agree-tos \
--no-eff-email \
--verbose
# 9. 查看完整的错误日志
sudo tail -f /var/log/letsencrypt/letsencrypt.log
问题 4: 证书文件不存在
错误信息: No such file or directory 或 Nginx 启动失败提示证书文件不存在
解决方案:
# 1. 检查证书文件是否存在(两个域名都要检查)
sudo ls -la /etc/letsencrypt/live/admin.cqcjg.com/
sudo ls -la /etc/letsencrypt/live/gateway.cqcjg.com/
# 2. 如果目录不存在,重新申请证书
sudo certbot certonly --webroot \
-w /tools/nginx/html \
-d admin.cqcjg.com \
--email cqchejiaguan@163.com \
--agree-tos \
--no-eff-email
# 3. 如果目录存在但文件不存在,检查权限
sudo ls -la /etc/letsencrypt/live/admin.cqcjg.com/
sudo ls -la /etc/letsencrypt/archive/
# 4. 检查证书文件是否为符号链接
sudo readlink -f /etc/letsencrypt/live/admin.cqcjg.com/fullchain.pem
问题 5: 权限问题
错误信息: Permission denied 或 Nginx 无法读取证书文件
解决方案:
# 1. 检查证书文件权限
sudo ls -la /etc/letsencrypt/live/admin.cqcjg.com/
sudo ls -la /etc/letsencrypt/live/gateway.cqcjg.com/
# 2. 确保 Nginx 用户有读取权限
sudo chmod 755 /etc/letsencrypt/live/
sudo chmod 755 /etc/letsencrypt/archive/
sudo chmod 644 /etc/letsencrypt/live/*/fullchain.pem
sudo chmod 600 /etc/letsencrypt/live/*/privkey.pem
# 3. 检查 Nginx 运行用户
ps aux | grep nginx
# 或查看配置文件
grep "^user" /tools/nginx/conf/nginx.conf
# 4. 确保验证目录权限正确
sudo chmod -R 755 /tools/nginx/html
问题 6: Nginx 配置测试失败
错误信息: nginx: configuration file test failed
可能原因:
- 证书路径配置错误
- SSL 配置语法错误
- 证书文件不存在
解决方案:
# 1. 查看详细错误信息
cd /tools/nginx/sbin
./nginx -t -c /tools/nginx/conf/nginx.conf
# 2. 检查证书路径是否正确
grep ssl_certificate /tools/nginx/conf/hosts/admin.cqcjg.com.conf
grep ssl_certificate /tools/nginx/conf/hosts/gateway.cqcjg.com.conf
# 3. 验证证书文件是否存在
sudo test -f /etc/letsencrypt/live/admin.cqcjg.com/fullchain.pem && echo "存在" || echo "不存在"
sudo test -f /etc/letsencrypt/live/gateway.cqcjg.com/fullchain.pem && echo "存在" || echo "不存在"
# 4. 检查配置文件语法
cd /tools/nginx/sbin
./nginx -T -c /tools/nginx/conf/nginx.conf # 显示完整配置并测试
问题 7: HTTPS 访问失败
错误信息: 浏览器显示 "连接不安全" 或证书错误
解决方案:
# 1. 检查证书是否过期
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -noout -dates
# 2. 检查证书域名是否匹配
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -noout -text | grep -A 1 "Subject Alternative Name"
# 3. 测试 HTTPS 连接
openssl s_client -connect admin.cqcjg.com:443 -servername admin.cqcjg.com
# 4. 检查防火墙是否允许 443 端口
sudo ufw status
sudo firewall-cmd --list-all
# 5. 检查 Nginx 错误日志
sudo tail -f /tools/nginx/logs/admin.cqcjg.com.error.log
sudo tail -f /tools/nginx/logs/gateway.cqcjg.com.error.log
问题 8: 自动续期失败
检查方法:
# 查看续期日志
sudo tail -f /var/log/letsencrypt/letsencrypt.log
# 手动测试续期
sudo certbot renew --dry-run -v
常见原因:
- 域名解析变更
- 80 端口被占用
- 验证目录权限问题
- 网络连接问题
解决方案:
- 参考问题 2 和问题 3 的解决方案
- 确保 DNS 解析正确
- 确保 80 端口可访问
- 检查验证目录权限
问题 9: 续期后 Nginx 未重载
检查方法:
# 检查续期钩子脚本
sudo cat /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
# 手动执行钩子脚本测试
sudo /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
# 查看续期日志
sudo tail -f /var/log/letsencrypt/renewal.log
解决方案:
- 确保钩子脚本有执行权限:
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh - 确保 Nginx 配置正确
- 检查脚本日志
- 手动重载 Nginx:
cd /tools/nginx/sbin && ./nginx -s reload -c /tools/nginx/conf/nginx.conf
问题 10: OCSP Stapling 警告
警告信息:
nginx: [warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate
问题说明:
- 这是一个警告,不是错误
- 不会影响 HTTPS 的正常工作
- 某些证书(包括部分 Let's Encrypt 证书)可能不包含 OCSP responder URL
解决方案:
方案一:忽略警告(推荐)
- 警告不影响功能,可以安全忽略
- HTTPS 连接仍然安全可靠
方案二:禁用 OCSP Stapling
如果不想看到警告,可以注释掉 OCSP Stapling 相关配置:
# OCSP Stapling(提高性能)
# ssl_stapling on;
# ssl_stapling_verify on;
# ssl_trusted_certificate /etc/letsencrypt/live/admin.cqcjg.com/chain.pem;
# resolver 8.8.8.8 8.8.4.4 valid=300s;
# resolver_timeout 5s;
然后重载 Nginx:
cd /tools/nginx/sbin
./nginx -s reload -c /tools/nginx/conf/nginx.conf
证书管理
查看证书信息
# 查看所有证书
sudo certbot certificates
# 查看证书详细信息
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -text -noout
# 查看证书有效期
sudo openssl x509 -in /etc/letsencrypt/live/admin.cqcjg.com/cert.pem -noout -dates
撤销证书
# 撤销证书
sudo certbot revoke --cert-path /etc/letsencrypt/live/admin.cqcjg.com/cert.pem
删除证书
# 删除证书(不会删除文件,只是取消自动续期)
sudo certbot delete --cert-name admin.cqcjg.com
最佳实践
- 使用多域名证书:为同一服务器上的多个域名申请一个证书,便于管理
- 配置自动续期:确保证书不会过期
- 使用强加密协议:仅使用 TLSv1.2 和 TLSv1.3
- 启用 HSTS:提高安全性
- 配置 OCSP Stapling:提高 SSL 握手性能(如果证书支持)
- 定期检查证书状态:使用监控工具检查证书有效期
- 备份证书和私钥:定期备份
/etc/letsencrypt/目录 - 监控续期日志:定期检查续期日志,及时发现问题
- 测试续期流程:每月测试一次自动续期流程
- DNS 解析检查:确保域名 DNS 解析正确,这是证书申请成功的关键
总结
Let's Encrypt 提供了免费、自动化的 SSL 证书解决方案。通过合理配置和定期维护,可以确保网站的安全性和可用性。
关键要点:
- 域名必须正确绑定配置的服务器公网 IP
- 首次申请证书前需要注释 HTTPS 配置
- 配置自动续期,避免证书过期
- 定期监控证书状态
- 遇到问题按照"问题解决流程"逐步排查
通过以上配置,您的网站将拥有安全可靠的 HTTPS 加密连接。
