主题模式
Are you an LLM? You can read better optimized documentation at /vps/settings/ssl-certificate-management.md for this page in Markdown format
SSL/TLS 证书管理:Let's Encrypt 自动续签与多域名配置指南
HTTPS 已经是现代网站的标配。没有 SSL 证书的网站会被浏览器标记为「不安全」,影响用户体验和 SEO 排名。Let's Encrypt 提供免费的 SSL/TLS 证书,配合 Certbot 工具可以实现全自动申请和续签,无需任何费用。
📋 SSL 证书基础
证书类型对比
| 类型 | 验证方式 | 价格 | 适用场景 |
|---|---|---|---|
| DV(域名验证) | 自动验证域名所有权 | 免费(Let's Encrypt) | 个人网站、博客 |
| OV(组织验证) | 人工验证组织信息 | ~$100-300/年 | 企业官网 |
| EV(扩展验证) | 严格人工审核 | ~$200-700/年 | 银行、金融 |
| 通配符证书 | 验证主域名 | 免费(Let's Encrypt) | 多子域名场景 |
Let's Encrypt 证书特点
| 特性 | 说明 |
|---|---|
| 免费 | 完全免费,无任何费用 |
| 自动化 | Certbot 自动申请、续签、部署 |
| 有效期 | 90 天(需要定期续签) |
| 通配符 | 支持 *.example.com 泛域名证书 |
| 信任度 | 全球所有主流浏览器信任 |
| 限制 | 每个域名每周最多 50 个证书 |
证书链结构
根证书 (ISRG Root X1)
└── 中间证书 (Let's Encrypt R3/R10)
└── 你的域名证书 (example.com)证书链完整性
服务器必须同时部署域名证书和中间证书,否则部分浏览器会报「证书不受信任」错误。Certbot 的 fullchain.pem 已包含完整证书链。
🔧 Certbot 安装
Ubuntu/Debian
bash
sudo apt update
sudo apt install certbot python3-certbot-nginxCentOS/RHEL
bash
sudo dnf install epel-release
sudo dnf install certbot python3-certbot-nginxDocker
bash
# 使用 Docker 运行 Certbot
docker run -it --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/www/html:/var/www/html \
certbot/certbot certonly --webroot -w /var/www/html -d example.comSnap(通用)
bash
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot📝 申请单域名证书
方式一:Nginx 插件(推荐)
如果已安装 Nginx,Certbot 可以自动修改 Nginx 配置:
bash
# 申请证书并自动配置 Nginx
sudo certbot --nginx -d example.com -d www.example.com
# 仅申请证书,不修改 Nginx 配置
sudo certbot certonly --nginx -d example.com方式二:Webroot 方式
适合不希望 Certbot 修改 Web 服务器配置的场景:
bash
sudo certbot certonly --webroot \
-w /var/www/html \
-d example.com \
-d www.example.com方式三:Standalone 方式
适合没有运行 Web 服务器的场景(Certbot 临时启动一个 HTTP 服务):
bash
# 先停止 Nginx(释放 80 端口)
sudo systemctl stop nginx
# 申请证书
sudo certbot certonly --standalone -d example.com
# 重新启动 Nginx
sudo systemctl start nginx申请成功后的文件
/etc/letsencrypt/live/example.com/
├── cert.pem # 域名证书
├── chain.pem # 中间证书
├── fullchain.pem # 完整证书链(推荐使用)
├── privkey.pem # 私钥
└── README # 说明文件🌐 申请泛域名证书
泛域名(通配符)证书可以覆盖所有子域名:*.example.com。
DNS 验证必须
泛域名证书只能通过 DNS 验证申请,不能使用 HTTP 验证。
手动 DNS 验证
bash
sudo certbot certonly --manual \
--preferred-challenges dns \
-d "*.example.com" \
-d example.comCertbot 会提示添加一条 TXT 记录:
请在 _acme-challenge.example.com 添加 TXT 记录:
值:xJ3j2kLm5nQ8rT4vW7yZ0aB3cD6eF9gH到你的 DNS 服务商添加该 TXT 记录,等待生效后按回车继续。
自动化 DNS 验证(推荐)
手动添加 TXT 记录太麻烦,且每次续签都要重复。使用 DNS 插件可以实现自动化:
Cloudflare DNS 插件
bash
# 安装 Cloudflare 插件
sudo apt install python3-certbot-dns-cloudflarebash
# 创建 Cloudflare API 凭据文件
sudo nano /etc/letsencrypt/cloudflare.ini
dns_cloudflare_api_token = your_api_token_herebash
# 保护凭据文件
sudo chmod 600 /etc/letsencrypt/cloudflare.inibash
# 申请泛域名证书
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "*.example.com" \
-d example.com阿里云 DNS 插件
bash
# 安装阿里云 DNS 插件
pip install certbot-dns-aliyun
# 创建凭据文件
sudo nano /etc/letsencrypt/aliyun.ini
dns_aliyun_access_key = your_access_key
dns_aliyun_access_key_secret = your_secret_keybash
sudo chmod 600 /etc/letsencrypt/aliyun.ini
sudo certbot certonly \
--authenticator dns-aliyun \
--dns-aliyun-credentials /etc/letsencrypt/aliyun.ini \
-d "*.example.com" \
-d example.com腾讯云 DNS 插件
bash
pip install certbot-dns-tencentcloud
sudo nano /etc/letsencrypt/tencentcloud.ini
dns_tencentcloud_secretid = your_secret_id
dns_tencentcloud_secretkey = your_secret_keybash
sudo certbot certonly \
--authenticator dns-tencentcloud \
--dns-tencentcloud-credentials /etc/letsencrypt/tencentcloud.ini \
-d "*.example.com" \
-d example.comAPI Token 权限
为 DNS API Token 设置最小权限:仅需 Zone:DNS:Edit 权限,不要授予账号完整权限。
🔄 自动续签
Certbot 自动续签机制
Certbot 安装后会自动创建定时任务:
bash
# 查看定时任务
systemctl list-timers | grep certbot
# 或检查 cron
ls /etc/cron.d/ | grep certbot默认配置:每天检查两次,在证书到期前 30 天自动续签。
测试续签
bash
# 模拟续签(不实际执行)
sudo certbot renew --dry-run续签后重载服务
续签成功后需要重载 Web 服务器使新证书生效:
bash
# 配置续签后钩子
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shbash
#!/bin/bash
# 重载 Nginx
systemctl reload nginx
# 或重载其他服务
# systemctl reload apache2
# docker exec nginx nginx -s reloadbash
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh多服务续签钩子
如果有多台服务使用同一证书:
bash
#!/bin/bash
# /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh
# 重载 Nginx
systemctl reload nginx
# 重载 HAProxy
systemctl reload haproxy
# 重载 Docker 中的 Nginx
docker exec nginx nginx -s reload
# 复制证书到其他位置
cp /etc/letsencrypt/live/example.com/fullchain.pem /path/to/app/cert.pem
cp /etc/letsencrypt/live/example.com/privkey.pem /path/to/app/key.pem
systemctl restart your-app🖥️ Nginx SSL 配置
基础 HTTPS 配置
nginx
server {
listen 80;
server_name example.com www.example.com;
# 强制跳转 HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL 证书
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL 优化
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
# 现代协议配置
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;
# HSTS(强制 HTTPS)
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;
# OCSP 装订
ssl_stapling on;
ssl_stapling_verify on;
# 网站根目录
root /var/www/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}泛域名配置
nginx
# 使用泛域名证书
server {
listen 443 ssl http2;
server_name *.example.com example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 根据子域名路由
location / {
# 默认站点
root /var/www/html;
index index.html;
}
}
# 特定子域名
server {
listen 443 ssl http2;
server_name blog.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}反向代理 SSL 配置
nginx
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 反向代理到后端服务
location / {
proxy_pass http://127.0.0.1:3000;
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;
# WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}🟢 Caddy 自动 HTTPS
Caddy 自动申请和续签 Let's Encrypt 证书,无需 Certbot:
caddyfile
# Caddyfile
example.com {
root * /var/www/html
file_server
}
# 反向代理
app.example.com {
reverse_proxy 127.0.0.1:3000
}
# 泛域名(需要 DNS 插件)
*.example.com {
tls {
dns cloudflare your_api_token
}
reverse_proxy 127.0.0.1:8080
}Caddy 优势
Caddy 默认开启 HTTPS、HTTP/2、HTTP/3,自动处理证书申请和续签,零配置即可获得 A+ 评分。适合不想折腾 Certbot 的用户。
📊 证书监控与告警
检查证书状态
bash
# 查看证书信息
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates -subject -issuer
# 查看到期时间
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# 查看证书链
openssl s_client -connect example.com:443 -showcerts 2>/dev/nullCertbot 管理命令
bash
# 查看所有证书
sudo certbot certificates
# 删除证书
sudo certbot delete --cert-name example.com
# 修改证书域名
sudo certbot certonly --cert-name example.com -d example.com -d new.example.com
# 强制续签
sudo certbot renew --force-renewal --cert-name example.com到期告警脚本
bash
#!/bin/bash
# /root/scripts/cert-alert.sh
ALERT_DAYS=30
WEBHOOK="https://api.telegram.org/bot<TOKEN>/sendMessage"
CHAT_ID="your_chat_id"
certbot certificates 2>/dev/null | grep -E "Certificate Name|Expiry" | \
while read -r name_line; do
read -r expiry_line
cert_name=$(echo "$name_line" | awk '{print $3}')
expiry_date=$(echo "$expiry_line" | grep -oP '\d{4}-\d{2}-\d{2}')
if [ -n "$expiry_date" ]; then
days_left=$(( ($(date -d "$expiry_date" +%s) - $(date +%s)) / 86400 ))
if [ "$days_left" -le "$ALERT_DAYS" ]; then
message="⚠️ SSL 证书告警: $cert_name 将在 ${days_left} 天后到期 ($expiry_date)"
curl -s -X POST "$WEBHOOK" -d chat_id="$CHAT_ID" -d text="$message"
fi
fi
done添加定时检查:
bash
# crontab -e
0 9 * * * /bin/bash /root/scripts/cert-alert.sh外部监控
除了本地监控,建议使用外部服务监控证书:
| 监控工具 | 方式 | 特点 |
|---|---|---|
| Uptime Kuma | 自托管 | 支持 HTTPS 证书到期监控 |
| SSL Labs | 在线扫描 | comprehensive SSL 评估 |
| CertExpiry | 在线监控 | 免费,邮件告警 |
| Prometheus | 自托管 | blackbox_exporter 监控 |
🔒 SSL 安全最佳实践
SSL 等级评分标准
| 等级 | 说明 | 要求 |
|---|---|---|
| A+ | 最佳安全 | TLS 1.2+1.3、HSTS、完美前向保密 |
| A | 优秀 | TLS 1.2+1.3、无已知漏洞 |
| B | 合格 | TLS 1.2,存在小问题 |
| C | 不足 | 支持 TLS 1.0/1.1 |
| F | 不安全 | 存在严重漏洞(如 Heartbleed) |
使用 SSL Labs 检测你的网站等级。
禁用过时协议
nginx
# 仅使用 TLS 1.2 和 1.3
ssl_protocols TLSv1.2 TLSv1.3;
# 禁用 TLS 1.0 和 1.1(已不安全)
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # ❌ 不要这样启用 OCSP 装订
OCSP 装订可以减少证书验证的延迟:
nginx
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;完美前向保密(PFS)
确保使用 ECDHE 或 DHE 密钥交换:
nginx
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;❓ 常见问题
Q: 续签失败怎么办?
bash
# 查看续签日志
sudo certbot renew --dry-run -v
# 常见原因
# 1. DNS 记录未生效(泛域名续签)
# 2. 80 端口被占用(standalone 模式)
# 3. 证书目录权限问题
# 4. 达到速率限制Q: 如何迁移证书到新服务器?
bash
# 复制整个 letsencrypt 目录
sudo tar czf letsencrypt-backup.tar.gz /etc/letsencrypt/
# 在新服务器上恢复
sudo tar xzf letsencrypt-backup.tar.gz -C /
# 重载 Web 服务器
sudo systemctl reload nginxQ: 一个证书可以包含多少个域名?
Let's Encrypt 每个证书最多支持 100 个域名(SAN)。但建议使用泛域名证书减少管理复杂度。
Q: Let's Encrypt 证书和付费证书有什么区别?
加密强度和浏览器信任度完全相同。主要区别:
- Let's Encrypt 只有 DV 证书,不显示组织名称
- 有效期 90 天(付费证书通常 1-2 年)
- 完全自动化(付费证书可能需要人工审核)
Q: 如何为内网服务配置 HTTPS?
- 使用泛域名证书覆盖内网域名(如
*.internal.example.com) - 通过 Cloudflare Tunnel 或 Tailscale 暴露内网服务
- 或使用自签证书(但浏览器会警告)
🔗 相关文章
- SSH 安全加固实战 — SSH 安全防护
- VPS 安全加固指南 — 服务器安全基础
- Cloudflare Tunnel 内网穿透 — 免端口暴露方案
- Uptime Kuma 服务监控 — 证书到期监控
- N100 小主机搭建全攻略 — 家庭服务器方案
