对于个人开发者和小型项目来说,由 Let’s Encrypt 提供的免费 SSL 证书无疑是开启 HTTPS 的福音。但它有一个烦恼——证书有效期只有 90 天。这意味着每隔两三个月,我们就需要登录服务器,手动执行续签命令,否则网站就会因证书过期而无法访问。

虽然可以在网站服务器上直接设置 cron 定时任务来续签,但这有几个缺点:

  1. 分散管理:如果有多台服务器,需要在每台服务器上都进行配置。
  2. 验证麻烦:使用 HTTP-01 方式验证时,需要临时占用 80 端口,有时会与现有 Web 服务冲突。
  3. 无法申请泛域名证书:HTTP-01 验证不支持申请像 *.yourdomain.com 这样的泛域名证书。

那么,有没有一种方法,可以集中、自动、且一劳永逸地解决这个问题呢?答案是肯定的。

使用内网树莓派作为“证书管家”

我们的核心思路是,将证书的申请与续签任务,与网站的实际运行分离开来。我们指定一台低功耗、可 7x24 小时运行的设备作为“证书管家”,定期执行续签工作。

整个自动化流程如下:

  1. 定时触发:树莓派上的 cron 定时任务,在每天凌晨自动触发续签脚本。
  2. 智能续签:脚本调用 Certbot,Certbot 会检查证书是否在未来 30 天内过期。如果不需要续签,则直接退出;如果需要,则进入下一步。
  3. DNS-01 验证:Certbot 使用我们预先配置的 DNSPod API 密钥,自动在我们的域名解析中添加一条临时的 TXT 记录,以向 Let’s Encrypt 证明我们对该域名的所有权。
  4. 获取证书:验证成功后,Let’s Encrypt 会颁发新的证书,并由 Certbot 将其保存在树莓派本地。
  5. 安全部署:树莓派通过 scp (Secure Copy) 将最新的证书文件安全地推送到远端的腾讯云服务器上。
  6. 远程生效:证书推送完毕后,树莓派再通过 ssh 远程命令,让腾讯云服务器上的 Nginx 服务重新加载配置,使新证书即刻生效。

准备工作

在开始之前,请确保你拥有:

  1. 一台安装了 Ubuntu (ARM64) 系统的树莓派,并能正常联网。
  2. 一台部署了网站的腾讯云服务器 (Ubuntu)。
  3. 一个在腾讯云 DNSPod 进行解析的域名。
  4. 树莓派和服务器之间可以通过 SSH 正常通信。

实战步骤

获取 DNSPod API 密钥

这是实现 DNS-01 验证的关键。API 密钥需要从腾讯云主控制台获取。

  1. 登录腾讯云控制台,进入访问管理 (CAM)
  2. 在左侧菜单选择 访问密钥” -> “API 密钥管理
  3. 点击 新建密钥,你将获得一对 SecretIdSecretKey请务必立即复制并妥善保管 SecretKey

在树莓派上安装并配置 Certbot

  1. 安装 Certbot 及腾讯云插件

    # 在树莓派上执行
    sudo apt update
    sudo apt install python3-pip -y
    sudo pip3 install certbot certbot-dns-tencentcloud
    
  2. 创建 API 凭证文件

    # 在树莓派上执行
    mkdir -p ~/.secrets/certbot
    nano ~/.secrets/certbot/tencentcloud.ini
    

    在文件中写入以下内容,并替换成你自己的密钥:

    dns_tencentcloud_secret_id = 你的SecretId
    dns_tencentcloud_secret_key = 你的SecretKey
    
  3. 设置严格的文件权限(非常重要!)

    # 在树莓派上执行
    sudo chmod 600 ~/.secrets/certbot/tencentcloud.ini
    

配置服务器的远程接收环境

我们需要在腾讯云服务器上创建一个专用的、低权限的用户来接收证书和执行命令,以提高安全性。

  1. 创建专用用户

    # 在腾讯云服务器上执行
    sudo adduser cert-updater
    
  2. 创建证书存放目录并授权

    # 在腾讯云服务器上执行
    sudo mkdir -p /home/cert-updater/certs
    sudo chown -R cert-updater:cert-updater /home/cert-updater/certs
    

打通树莓派到服务器的“自动化通道”

要让脚本自动运行,必须配置两个关键的“免密”环节。

  1. 配置树莓派 root 用户的 SSH 免密登录
    由于我们的定时任务最终会以 root 权限运行,所以需要为树莓派的 root 用户配置到服务器的免密登录。

    # 在树莓派上执行
    sudo -i  # 切换到 root 用户
    ssh-keygen -t rsa  # 一直回车
    ssh-copy-id cert-updater@<你的腾讯云服务器IP> # 按提示输入一次 cert-updater 的密码
    exit # 退回到普通用户
    
  2. 配置服务器 cert-updater 用户的 Sudo 免密权限
    cert-updater 用户可以无需密码就执行 Nginx 重载命令。

    # 在腾讯云服务器上执行
    sudo visudo
    

    在打开的文件的最底部,添加这一行:

    cert-updater ALL=(ALL) NOPASSWD: /bin/systemctl reload nginx
    

首次手动获取证书

我们先手动运行一次 Certbot,获取第一个泛域名证书。

# 在树莓派上执行
sudo certbot certonly \
  --authenticator dns-tencentcloud \
  --dns-tencentcloud-credentials ~/.secrets/certbot/tencentcloud.ini \
  -d yourdomain.com \
  -d *.yourdomain.com \
  --agree-tos -m [email protected] --non-interactive

请将上面的 *.yourdomain.com [email protected]字段更换为实际的内容。
如果看到 Successfully received certificate. 的提示说明已经成功!

编写自动化脚本

在树莓派上,创建一个 renew_ssl.sh 脚本,将续签、上传、重载三个动作串联起来。

# 在树莓派上执行
nano ~/renew_ssl.sh

将下面的完整脚本粘贴进去,并修改顶部的配置项

#!/bin/bash
## 配置项 ##
DOMAIN="yourdomain.com"
REMOTE_USER="cert-updater"
REMOTE_IP="<你的腾讯云服务器IP>"
REMOTE_CERT_DIR="/home/cert-updater/certs"
LOG_FILE="/var/log/ssl_renew.log"

## 脚本主体 ##
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}

log_message "开始执行 SSL 证书续签与部署任务..."

# 1. 续签
log_message "步骤 1/3: 正在尝试使用 Certbot 续签证书..."
sudo certbot renew --quiet

# 2. 部署
if [ $? -eq 0 ]; then
    log_message "Certbot 续签检查完成,开始同步证书..."
    ssh $REMOTE_USER@$REMOTE_IP "mkdir -p $REMOTE_CERT_DIR"
    sudo scp -r /etc/letsencrypt/live/$DOMAIN/* $REMOTE_USER@$REMOTE_IP:$REMOTE_CERT_DIR/
    
    if [ $? -eq 0 ]; then
        log_message "证书同步成功。"
        # 3. 重载
        log_message "步骤 3/3: 正在远程重载 Nginx 服务..."
        ssh $REMOTE_USER@$REMOTE_IP "sudo systemctl reload nginx"
        if [ $? -eq 0 ]; then
            log_message "任务成功: Nginx 重载成功!"
        else
            log_message "错误: 远程 Nginx 重载失败!"
        fi
    else
        log_message "错误: SCP 同步证书失败!"
    fi
else
    log_message "错误: 'certbot renew' 命令执行失败!"
fi
log_message "所有任务执行完毕。"

为脚本添加执行权限,并将其移动到 /root/ 目录,方便管理:

# 在树莓派上执行
chmod +x ~/renew_ssl.sh
sudo mv ~/renew_ssl.sh /root/renew_ssl.sh

手动测试一下脚本sudo /root/renew_ssl.sh

设置定时任务

# 在树莓派上执行
sudo crontab -e

在文件末尾添加一行,让脚本每天凌晨 3:15 自动运行:

15 3 * * * /root/renew_ssl.sh

保存退出,大功告成!

配置 Nginx

最后,别忘了登录你的腾讯云服务器,修改 Nginx 配置文件,让它使用我们自动部署的证书。

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    # SSL 证书路径指向我们配置的目录
    ssl_certificate /home/cert-updater/certs/fullchain.pem;
    ssl_certificate_key /home/cert-updater/certs/privkey.pem;

    # ... 其他 SSL 优化配置和网站配置 ...
}

检查配置并重载 Nginx:

sudo nginx -t
sudo systemctl reload nginx

总结

完成以上操作我们便成功配置了SSL 证书的全自动续签。