DukeDuke
主页
文档转换
关于我们
主页
文档转换
关于我们
  • Linux 系统

    • Linux 系统管理
    • Linux 网络管理
    • Linux 文件管理
    • Linux 命令大全
  • Nginx Web 服务器

    • Nginx 安装 与 配置
    • Nginx 负载均衡
    • Nginx SSL证书配置
    • Nginx Keepalived 高可用
  • Docker 容器

    • Docker 简介
    • Docker 安装与配置
    • Docker 命令
    • Docker 部署 Nginx
    • Docker 部署 MySQL
    • Docker 部署 Redis
  • 服务器

    • 塔式服务器
    • 机架式服务器
    • 刀片服务器
  • Git 版本控制
  • Jenkins 持续集成
  • Jmeter 性能测试
  • Let's Encrypt 免费SSL证书

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.conf
    • hosts/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 解析不正确:

  1. 登录域名 DNS 管理后台(如阿里云、腾讯云等)
  2. 添加 A 记录:
    • 主机记录:admin(对于 admin.cqcjg.com)
    • 主机记录:gateway(对于 gateway.cqcjg.com)
    • 记录类型:A
    • 记录值:服务器的公网 IP 地址
    • TTL:600
  3. 等待 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 命令失败,检查:

  1. Nginx 是否已启动(参考步骤 3)
  2. 80 端口是否在监听
  3. 防火墙是否允许 80 端口访问
  4. 域名 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 提供了自动续期功能。

续期流程概览

完整的证书续期流程:

  1. 检查证书状态 - 查看证书有效期和续期配置
  2. 配置自动续期 - 设置自动续期任务和钩子脚本
  3. 测试续期流程 - 使用 --dry-run 测试续期是否正常
  4. 监控证书有效期 - 设置监控脚本,及时发现问题
  5. 处理续期问题 - 排查和解决续期失败的问题

续期方式:

  • 自动续期(推荐):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 服务器配置 开始到对应的 } 结束)。

证书申请完成后:

  1. 取消注释 HTTPS 配置块
  2. 恢复 HTTP 到 HTTPS 的重定向
  3. 测试配置:cd /tools/nginx/sbin && ./nginx -t -c /tools/nginx/conf/nginx.conf
  4. 重载配置: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 ownership
  • The 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

最佳实践

  1. 使用多域名证书:为同一服务器上的多个域名申请一个证书,便于管理
  2. 配置自动续期:确保证书不会过期
  3. 使用强加密协议:仅使用 TLSv1.2 和 TLSv1.3
  4. 启用 HSTS:提高安全性
  5. 配置 OCSP Stapling:提高 SSL 握手性能(如果证书支持)
  6. 定期检查证书状态:使用监控工具检查证书有效期
  7. 备份证书和私钥:定期备份 /etc/letsencrypt/ 目录
  8. 监控续期日志:定期检查续期日志,及时发现问题
  9. 测试续期流程:每月测试一次自动续期流程
  10. DNS 解析检查:确保域名 DNS 解析正确,这是证书申请成功的关键

总结

Let's Encrypt 提供了免费、自动化的 SSL 证书解决方案。通过合理配置和定期维护,可以确保网站的安全性和可用性。

关键要点:

  • 域名必须正确绑定配置的服务器公网 IP
  • 首次申请证书前需要注释 HTTPS 配置
  • 配置自动续期,避免证书过期
  • 定期监控证书状态
  • 遇到问题按照"问题解决流程"逐步排查

通过以上配置,您的网站将拥有安全可靠的 HTTPS 加密连接。

最近更新:: 2026/4/17 13:21
Contributors: Duke
Prev
Jmeter 性能测试