Skip to content

SSL证书申请与续期自动化 ​

1. 核心选择:为什么推荐 "泛域名证书"? ​

你提到的 "不想每次加服务都重新配置 SSL" 和 "免费自动续期",最佳解决方案是申请 泛域名证书 (Wildcard Certificate)。

方案对比 ​

特性方案 A: 泛域名 (推荐)方案 B: 单域名 (旧方案)
证书域名*.hongjy.cn (含 blog, home, nas...)仅 photo.hongjy.cn (指定一个)
新增子域名无需任何操作,直接复用证书必须重新运行申请命令
验证方式DNS 验证 (需要 API Key)HTTP 验证 (需要 Nginx 配置)
适用场景想要一劳永逸,子域名很多无法获取 DNS 权限,单体应用
对旧服务影响无影响。新旧证书可共存无影响

关键说明: 你之前印象中 "没有 Key、需要配置 Nginx 验证步骤" 的是 方案 B (HTTP 验证)。 但 方案 B 不支持泛域名。如果你想要 "一次配置,永久通用",必须 使用 方案 A (DNS 验证),这就必须用到阿里云的 API Key 来自动添加 DNS 记录以证明域名归属权。


2. 准备工作 (仅方案 A 需要) ​

为了申请泛域名证书,我们需要一个只能修改 DNS 的阿里云子账号 (RAM 用户),确保安全。

  1. 登录 阿里云 RAM 访问控制。
  2. 创建用户: 用户名如 acme-dns-bot,勾选 "OpenAPI 调用访问"。
  3. 保存密钥: 复制下来的 AccessKey ID 和 AccessKey Secret (只显示一次)。
  4. 授权: 点击用户 -> 权限管理 -> 新增授权 -> 搜索 AliyunDNSFullAccess (管理云解析DNS的权限) -> 确认。

3. 证书申请 (acme.sh Docker 版) ​

我们使用 Docker 运行 acme.sh,干净且易于管理。

3.1 初始化容器 ​

bash
# 宿主机执行 (首次初始化)
docker run --rm -it \
  -v /srv/core/acme:/acme.sh \
  neilpang/acme.sh --install-online -m hongjy1991@gmail.com

3.2 申请泛域名证书 (DNS API 方式) ​

请根据你的域名解析服务商选择对应的命令。

选项 A: 腾讯云 (DNSPod) [用户当前使用] ​

  1. 获取密钥: 登录 DNSPod 控制台 -> 密钥管理,创建密钥 (API Token)。

  2. 执行申请:

6.4 ZeroSSL 账户注册报错 ​

  • 现象: acme.sh 默认 CA 变更为 ZeroSSL,提示 Please update your account with an email address first.
  • 原因: ZeroSSL 需要关联邮箱账户,或者 acme.sh 容器内的账户信息未正确持久化。
  • 解决:
    1. 注册账户 (推荐): 执行一次注册命令 (替换你的邮箱)。

      bash
      docker run --rm -it \
        -v /srv/core/acme:/acme.sh \
        neilpang/acme.sh --register-account -m hongjy1991@gmail.com
    2. 或者切换回 Let's Encrypt: 在申请命令中显式指定 CA。

      bash
      # 在原命令末尾添加 --server letsencrypt
      neilpang/acme.sh --issue ... --server letsencrypt

6.5 No such file or directory 安装失败 ​

  • 现象: Installing key to: /ssl/hongjy.cn/key.pem 后报错 cat: ... key: No such file.

  • 原因: 上一步申请证书失败 (如上述 ZeroSSL 错误),导致证书文件根本没有生成,自然无法安装。

  • 解决: 先解决申请报错,确保看到 Cert success 后,再运行 install 命令。 bash

    申请 hongjy.cn 和 *.hongjy.cn ​

    docker run --rm -it
    -v /srv/core/acme:/acme.sh
    -e DP_Id="你的ID"
    -e DP_Key="你的Token"
    neilpang/acme.sh --issue --dns dns_dp -d hongjy.cn -d *.hongjy.cn

    docker run --rm -it
    -v /srv/core/acme:/acme.sh
    -e DP_Id="614622"
    -e DP_Key="a215c4a8235ebf83f340bb7c32d69987"
    neilpang/acme.sh --issue --dns dns_dp -d hongjy.cn -d *.hongjy.cn

选项 B: 阿里云 (Aliyun) ​

  1. 获取密钥: 使用 RAM 子账号获取 AccessKey ID 和 Secret。

  2. 执行申请:

    bash
    # 申请 hongjy.cn 和 *.hongjy.cn
    docker run --rm -it \
      -v /srv/core/acme:/acme.sh \
      -e Ali_Key="你的AccessKey_ID" \
      -e Ali_Secret="你的AccessKey_Secret" \
      neilpang/acme.sh --issue --dns dns_ali -d hongjy.cn -d *.hongjy.cn

成功提示: 看到 Cert success 且输出证书路径,即表示申请成功。证书已保存在宿主机 /srv/core/acme/hongjy.cn/ 下。


4. Nginx 配置与部署 ​

4.1 安装证书到 Nginx ​

不要直接使用 acme 目录下的证书,使用 install-cert 命令将其复制到 Nginx 专用目录。

bash
# 1. 创建 Nginx SSL 目录
mkdir -p /srv/core/nginx-proxy/ssl/hongjy.cn

# 2. 安装证书 (将证书复制过去,并指定重载命令)
docker run --rm -it \
  -v /srv/core/acme:/acme.sh \
  -v /srv/core/nginx-proxy/ssl:/ssl \
  neilpang/acme.sh --install-cert -d hongjy.cn \
  --key-file       /ssl/hongjy.cn/key.pem  \
  --fullchain-file /ssl/hongjy.cn/cert.pem

4.2 配置 Nginx (通用模板) ​

现在,你可以在任何 Nginx 配置文件中使用这个泛域名证书。

示例: nginx-proxy/conf/home.conf

nginx
# HTTP 自动跳转 HTTPS
server {
    listen 80;
    server_name home.hongjy.cn;
    return 301 https://$host$request_uri;
}

# HTTPS 服务
server {
    listen 443 ssl http2;
    server_name home.hongjy.cn; # 这里的域名可以是任意 *.hongjy.cn

    root /srv/site/home;
    index index.html;

    # ✅ 核心: 引用泛域名证书
    ssl_certificate     /etc/nginx/ssl/hongjy.cn/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/hongjy.cn/key.pem;
    
    # SSL 推荐配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    
    location / {
        try_files $uri $uri/ /index.html;
    }
}

未来扩展: 当你要添加 blog2.hongjy.cn 时,只需复制上面的 server 块,修改 server_name 和 root 路径即可,无需再申请证书。


5. 自动化续期 (Crontab) ​

Let's Encrypt 证书有效期 90 天。我们设置每月自动检测续期。

5.1 编写续期脚本 ​

创建 /srv/core/scripts/renew_ssl.sh:

bash
#!/bin/bash
# 日志
LOG_FILE="/var/log/ssl-renew.log"
echo "[$(date)] Starting SSL renewal..." >> $LOG_FILE

# 1. 触发 acme.sh 续期 (DNS 方式无需 Nginx 配合验证)
# 只要证书快过期了 (默认 <60天),它就会自动调用阿里云 API 续期
docker run --rm -v /srv/core/acme:/acme.sh neilpang/acme.sh --cron >> $LOG_FILE 2>&1

# 2. 强制刷新 Nginx 证书文件
# 注意: acme.sh 内部其实记住了 install-cert 的目标,但为了保险我们显式再刷一次
docker run --rm -v /srv/core/acme:/acme.sh -v /srv/core/nginx-proxy/ssl:/ssl \
  neilpang/acme.sh --install-cert -d hongjy.cn \
  --key-file       /ssl/hongjy.cn/key.pem  \
  --fullchain-file /ssl/hongjy.cn/cert.pem >> $LOG_FILE 2>&1

# 3. 重载 Nginx
docker exec gateway nginx -s reload
echo "[$(date)] Nginx reloaded." >> $LOG_FILE

赋予执行权限:

bash
chmod +x /srv/core/scripts/renew_ssl.sh

5.2 添加定时任务 ​

bash
crontab -e
# 每月 1 号凌晨 3 点执行
0 3 1 * * /bin/bash /srv/core/scripts/renew_ssl.sh

6. (备选) 传统 HTTP 验证方案 ​

仅当你无法获取阿里云 Key 时使用此方案。注意:此方案不支持泛域名,每加一个子域名都要重复操作。

如果你坚持使用旧的 "验证文件" 方式:

  1. 配置 Nginx: 在 home.conf 中添加验证路由:

    nginx
    server {
        listen 80;
        server_name home.hongjy.cn;
        
        # 验证文件路由
        location ^~ /.well-known/acme-challenge/ {
            alias /usr/share/nginx/html/.well-known/acme-challenge/;
        }
    }
  2. 重载 Nginx: docker exec gateway nginx -s reload

  3. 申请证书 (Webroot 模式):

    bash
    # 必须指定 --webroot,且不支持 *.hongjy.cn
    docker run --rm -it \
      -v /srv/core/acme:/acme.sh \
      -v /srv/core/nginx-proxy/html:/usr/share/nginx/html \
      neilpang/acme.sh --issue -d home.hongjy.cn --webroot /usr/share/nginx/html
  4. 缺点: 每次新增 xxx.hongjy.cn,都需要先改 Nginx 加 location,再跑一遍命令申请。极不推荐。

方舟 · Ark