域名已指向线上服务器?教你用 Certbot 给另一台外网服务器轻松配置 SSL 证书

前言

在实际运维中,我们经常遇到这样一个场景:

  • 有一个域名(比如 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​ 为例:

  1. 登录 Cloudflare 后台
  2. 右上角「My Profile」→「API Tokens」
  3. 点击「Create Token」,选择「Edit zone DNS」模板
  4. 在「Zone Resources」中选择你的域名
  5. 创建成功后复制 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 配置

缺点:需要规划子域名,且每个子域名需要单独申请证书(除非用泛域名)。

推荐的分工方式

服务器子域名用途示例
线上服务器 Awww.example.com主站
线上服务器 Aapi.example.comAPI 服务
外网服务器 Blab.example.com实验环境
外网服务器 Bmirror.example.com镜像站

配置步骤

  1. 在 DNS 管理后台,将 lab.example.com 的 A 记录指向服务器 B 的 IP
  2. 在服务器 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 验证,体验一下“一次配置,永久省心”的感觉。


Comments

No comments yet. Why don’t you start the discussion?

发表回复