前言
在实际运维中,我们经常遇到这样一个场景:
- 有一个域名(比如
example.com),DNS 已经指向了线上服务器 A(主站) - 手里还有一台外网服务器 B(比如用来跑实验、做镜像站、搭建内部服务)
- 想让服务器 B 也能用上这个域名的 SSL 证书,实现 HTTPS 访问
直接在这台服务器 B 上跑 certbot --nginx 通常会失败,因为 Let’s Encrypt 的 HTTP 验证请求会发到服务器 A,而服务器 B 根本收不到。
本文将介绍三种行之有效的解决方案,涵盖不同场景下的最佳实践。
前置准备
无论采用哪种方案,都需要先在服务器 B 上安装 Certbot:
# Ubuntu/Debian
sudo apt update
sudo apt install certbot
# CentOS/RHEL 8+
sudo dnf install certbot
# CentOS 7
sudo yum install epel-release
sudo yum install certbot
方案一:DNS 验证(推荐,无需停服,一次申请泛域名)
原理:Certbot 通过在 DNS 记录中添加 TXT 记录来完成域名所有权验证,完全不依赖 80/443 端口,域名指向哪台服务器都无所谓。
优点:
- 不需要 80 端口,不受 DNS 指向影响
- 可以一次性申请泛域名证书(
*.example.com),所有子域名通用 - 配置好后全自动续期,一劳永逸
缺点:需要 DNS 服务商支持 API,并配置 API 凭据。
第一步:安装 DNS 插件
根据你的 DNS 服务商选择对应插件:
# Cloudflare
sudo apt install certbot python3-certbot-dns-cloudflare
# DNSPod(腾讯云)
sudo apt install certbot python3-certbot-dns-dnspod
# 阿里云 DNS
sudo apt install certbot python3-certbot-dns-aliyun
# AWS Route53
sudo apt install certbot python3-certbot-dns-route53
# Google Cloud DNS
sudo apt install certbot python3-certbot-dns-google
# OVH
sudo apt install certbot python3-certbot-dns-ovh
第二步:配置 DNS API 凭据
以 Cloudflare 为例:
- 登录 Cloudflare 后台
- 右上角「My Profile」→「API Tokens」
- 点击「Create Token」,选择「Edit zone DNS」模板
- 在「Zone Resources」中选择你的域名
- 创建成功后复制 Token
在服务器 B 上创建凭据文件:
mkdir -p ~/.secrets/certbot
chmod 700 ~/.secrets/certbot
nano ~/.secrets/certbot/cloudflare.ini
写入以下内容:
dns_cloudflare_api_token = 你的API_TOKEN
保存后设置权限:
chmod 600 ~/.secrets/certbot/cloudflare.ini
第三步:申请证书
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
-d example.com \
-d *.example.com \
--non-interactive \
--agree-tos \
-m your@email.com
参数说明:
certonly:仅获取证书,不自动配置 Web 服务器--dns-cloudflare:指定使用 Cloudflare DNS 插件-d example.com -d *.example.com:同时申请主域名和泛域名--non-interactive:非交互模式,适合脚本自动化
证书生成在 /etc/letsencrypt/live/example.com/ 目录下。
第四步:配置 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;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 你的其他配置...
}
第五步:自动续期
Certbot 通常会自动安装 systemd 定时器,可以用以下命令验证:
# 测试续期流程
sudo certbot renew --dry-run
# 查看定时任务
systemctl list-timers | grep certbot
如果需要手动添加 crontab:
sudo crontab -e
# 添加以下行,每天凌晨 3 点检查续期
0 3 * * * /usr/bin/certbot renew --quiet && systemctl reload nginx
方案二:HTTP 验证 + 临时转发(无需 DNS API)
原理:在线上服务器 A 上配置一个反向代理,将 Let’s Encrypt 的验证请求转发到服务器 B。
优点:不需要 DNS 服务商提供 API,适用于任何 DNS 服务商。
缺点:需要在线上服务器 A 上临时修改配置,申请完成后记得清理。
第一步:在服务器 A 上配置转发
编辑服务器 A 的 Nginx 配置,在 server 块中添加:
server {
listen 80;
server_name example.com;
# 将 Let's Encrypt 验证请求转发到服务器 B
location /.well-known/acme-challenge/ {
proxy_pass http://服务器B_公网IP:80/.well-known/acme-challenge/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 其他配置...
}
重载 Nginx:
sudo nginx -t && sudo systemctl reload nginx
第二步:在服务器 B 上申请证书
sudo certbot certonly --standalone -d example.com
Certbot 会在服务器 B 的 80 端口上启动一个临时 Web 服务,响应 Let’s Encrypt 的验证请求。由于服务器 A 已经配置了转发,验证请求可以顺利到达服务器 B。
第三步:申请完成后清理
申请成功后,记得删除服务器 A 上的转发配置,恢复原状。
方案三:子域名分离(长期维护最清晰)
原理:如果两台服务器用途不同,用不同的子域名区分,各自独立申请证书。
优点:
- 架构清晰,互不干扰
- 每台服务器各自管理自己的证书
- 不需要额外的转发或 DNS API 配置
缺点:需要规划子域名,且每个子域名需要单独申请证书(除非用泛域名)。
推荐的分工方式
| 服务器 | 子域名 | 用途示例 |
|---|---|---|
| 线上服务器 A | www.example.com | 主站 |
| 线上服务器 A | api.example.com | API 服务 |
| 外网服务器 B | lab.example.com | 实验环境 |
| 外网服务器 B | mirror.example.com | 镜像站 |
配置步骤
- 在 DNS 管理后台,将
lab.example.com的 A 记录指向服务器 B 的 IP - 在服务器 B 上直接运行 Certbot:
sudo certbot --nginx -d lab.example.com
Certbot 会自动完成验证、获取证书并配置 Nginx。
证书续期的注意事项
无论采用哪种方案,证书到期前都需要续期。以下是一些实用建议:
1. 验证续期是否正常工作
sudo certbot renew --dry-run
如果这个命令成功,说明自动续期机制是正常的。
2. 续期后重载 Web 服务器
Certbot 默认会在续期后自动重载 Nginx/Apache,但如果你的配置特殊,可以在 crontab 中手动添加:
0 3 * * * /usr/bin/certbot renew --quiet --renew-hook "systemctl reload nginx"
3. 监控证书过期时间
# 查看证书过期时间
openssl x509 -enddate -noout -in /etc/letsencrypt/live/example.com/fullchain.pem
# 或者用 certbot 查看
sudo certbot certificates
4. 设置邮件提醒
Let’s Encrypt 会在证书过期前发送邮件到申请时填写的邮箱,确保邮箱地址正确且能收到邮件。
常见问题排查
Q1:DNS 验证时提示 “No TXT record found”
- 检查 API Token 权限是否正确(需要有 DNS 编辑权限)
- 确认域名在 DNS 服务商的管理范围内
- 等待 DNS 缓存生效(通常 1-5 分钟)
Q2:HTTP 验证时提示 “Unable to connect”
- 检查服务器 A 的转发配置是否正确
- 确认服务器 B 的 80 端口没有被防火墙阻挡
- 验证服务器 B 上是否已经有程序占用了 80 端口
Q3:证书申请成功但浏览器提示不安全
- 确认 Nginx 配置中证书路径是否正确
- 检查证书是否包含了完整的证书链(使用
fullchain.pem而非cert.pem) - 确认域名和证书中的域名完全匹配
Q4:续期失败
- 检查 DNS API Token 是否仍然有效
- 确认服务器 B 的 80 端口在续期时可访问(如果使用 HTTP 验证)
- 查看 Certbot 日志:
/var/log/letsencrypt/letsencrypt.log
总结
| 方案 | 适用场景 | 复杂度 | 推荐指数 |
|---|---|---|---|
| DNS 验证 | DNS 服务商支持 API | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| HTTP 转发 | 任意 DNS,但不方便配 API | ⭐⭐⭐ | ⭐⭐⭐ |
| 子域名分离 | 可以重新规划域名 | ⭐ | ⭐⭐⭐⭐⭐ |
个人强烈推荐方案一(DNS 验证),配置一次后全自动运行,不仅解决了当前的问题,还能顺便拿到泛域名证书,以后新增子域名都不用再申请证书了。
如果你还在用方案二(HTTP 转发),不妨趁这个机会升级到 DNS 验证,体验一下“一次配置,永久省心”的感觉。