1034 lines
59 KiB
Markdown
1034 lines
59 KiB
Markdown
# 腾讯云服务器运行七牛图片域名 HTTPS 证书自动续期
|
||
|
||
> 文档日期:2026-09-30。操作示例:腾讯云 Linux 服务器、Ubuntu 24.04、DNSPod 中国站、七牛 Kodo 私有空间与 CDN 加速域名、Let's Encrypt、acme.sh 3.1.6。
|
||
>
|
||
> 状态:2026-10-03 已完成 Let's Encrypt staging 与正式证书签发,正式证书的颁发者、有效期和 SAN 已由维护者提供的 OpenSSL 输出确认;七牛 hook 对两个图片域名返回部署成功,两个图片域名的网络检查均返回本次正式证书的颁发者、有效期,且指纹一致。服务器使用 1Panel/OpenResty,Atlas 生产、开发应用尚未部署。定时自动续期仍待验收;网站 HTTPS 接入留待应用部署时完成。现场进度见第 6.2 节、第 7 节、第 8.2 节、第 9.2 节和第 10.2 节。操作系统、DNS 托管商和实际域名需要按现场情况核对。
|
||
|
||
## 1. 要完成的事情
|
||
|
||
Atlas 的生产、开发网站及两个环境的图片域名共用一张证书。七牛空间仍按环境隔离,由腾讯云服务器集中执行证书申请、续期和部署。
|
||
|
||
| 环境 | 七牛空间示例 | 下载域名示例 | 空间访问控制 |
|
||
|---|---|---|---|
|
||
| 开发联调 | `atlas-dev-assets` | `img-dev.atlas.joeyone.cn` | 私有 |
|
||
| 生产 | `atlas-prod-assets` | `img.atlas.joeyone.cn` | 私有 |
|
||
|
||
### 1.1 四个域名与一张证书
|
||
|
||
统一把 Atlas 的域名放在 `atlas.joeyone.cn` 下:
|
||
|
||
| 用途 | 完整域名 | DNSPod 主机记录(区域为 `joeyone.cn`) | 类型 | 目标 |
|
||
|---|---|---|---|---|
|
||
| 生产网站 | `atlas.joeyone.cn` | `atlas` | A | 生产腾讯云服务器 IP |
|
||
| 开发网站 | `dev.atlas.joeyone.cn` | `dev.atlas` | A | 开发服务器 IP;同机部署时可与生产相同 |
|
||
| 生产图片 | `img.atlas.joeyone.cn` | `img.atlas` | CNAME | 七牛生产 CDN 分配的目标 |
|
||
| 开发图片 | `img-dev.atlas.joeyone.cn` | `img-dev.atlas` | CNAME | 七牛开发 CDN 分配的目标 |
|
||
|
||
申请一张 SAN 包含以下两项的证书:
|
||
|
||
```text
|
||
atlas.joeyone.cn
|
||
*.atlas.joeyone.cn
|
||
```
|
||
|
||
`atlas.joeyone.cn` 覆盖生产网站;`*.atlas.joeyone.cn` 覆盖 `dev`、`img`、`img-dev` 这一级子域名。避免使用 `img.dev.atlas.joeyone.cn`,因为它多了一层,不能被这张通配符证书覆盖。`*.joeyone.cn` 也不能覆盖 `img.atlas.joeyone.cn`。
|
||
|
||
这张证书只申请、续期一次,但有三个部署目标:腾讯云 Nginx、七牛生产图片域名、七牛开发图片域名。多个域名写入同一张证书不表示它们需要指向同一个服务器或空间。
|
||
|
||
```text
|
||
腾讯云服务器上的证书维护任务
|
||
→ 通过 DNSPod API 创建临时 TXT 记录
|
||
→ Let's Encrypt 签发 atlas.joeyone.cn + *.atlas.joeyone.cn
|
||
→ acme.sh 上传到七牛并更新两个图片域名的证书绑定
|
||
→ 导出证书,验证本机 Nginx 配置后重载
|
||
|
||
生产 / 开发网站 → 腾讯云 Nginx → 各环境应用
|
||
Ozon / 图片访问 → 七牛 CDN HTTPS 域名 → 各环境私有空间
|
||
```
|
||
|
||
图片下载流量直接经过七牛,不经过证书维护服务器。网站 A 记录指向腾讯云,图片 CNAME 指向七牛。本手册的 Nginx 自动部署示例假设两个网站均由维护服务器上的 Nginx 提供 HTTPS;如果开发网站在另一台机器,需要为那台机器另加安全分发和配置检查/重载步骤,集中签发不会自动部署到远端服务器。
|
||
|
||
### 1.2 通配符 DNS 与其他系统
|
||
|
||
申请通配符证书不要求创建通配符 A 记录。主流程只创建上表四条明确记录,更容易检查各环境指向。
|
||
|
||
如果希望新建 Atlas 网站子域名默认指向同一服务器,可以另设主机记录 `*.atlas`、类型 A、值为服务器 IP。已有明确的 `img.atlas`、`img-dev.atlas` CNAME 仍优先匹配,不要将图片 CNAME 改成服务器 A 记录。`*.atlas` 也不能替代 `atlas` 本身的记录。[DNSPod 泛解析说明](https://cloud.tencent.com/document/product/302/9073)
|
||
|
||
其他系统继续使用各自的域名和证书,例如 `git.joeyone.cn`、`img.other-system.joeyone.cn`。新增 Atlas 证书不会修改它们的现有绑定;不需要为了 Atlas 更换全站 `*.joeyone.cn` 证书,也不需要修改主域名的 `*` 解析。
|
||
|
||
### 两种有效期要分开理解
|
||
|
||
| 对象 | 用途 | 谁负责更新 |
|
||
|---|---|---|
|
||
| HTTPS 证书 | 证明网站/图片域名身份并加密连接 | acme.sh 自动续期并部署 |
|
||
| 图片签名 URL 的 `e` / `token` | 授权下载某一张私有图片 | Atlas Worker 在发布时生成 |
|
||
|
||
七牛的“上传自有证书”只上传当前证书,不会自动向 Let's Encrypt 续期或替换域名绑定;自动化依赖本手册的签发、部署 hook 和定时任务。
|
||
|
||
更换 HTTPS 证书通常不改变图片 URL。自动换证书也不会延长已经到期的图片签名链接。
|
||
|
||
## 2. 操作前准备
|
||
|
||
准备以下资源,不需要将真实密钥填进本文或 Git 仓库:
|
||
|
||
- 一台长期运行、有公网出站能力的腾讯云 Linux 服务器;已有业务服务器也可运行这个小任务。
|
||
- 可以 SSH 登录,且当前管理用户具有 `sudo` 权限。
|
||
- 你拥有的 `joeyone.cn` 域名,以及上表四个未被其他用途占用的 Atlas 域名。
|
||
- 域名实际 DNS 托管商的 API 权限。域名在哪里买、服务器在哪家云、DNS 在哪家托管是三个独立问题。
|
||
- 两个七牛私有空间,以及开通七牛 CDN 的账号。
|
||
- 能接收故障通知的运维邮箱,以及可用的 SMTP 账号或其他现有告警渠道。
|
||
|
||
示例替换表:
|
||
|
||
| 本文示例 | 替换为 |
|
||
|---|---|
|
||
| `joeyone.cn` | 你的主域名 |
|
||
| `atlas.joeyone.cn` | 生产网站及证书主域名 |
|
||
| `dev.atlas.joeyone.cn` | 开发网站 |
|
||
| `*.atlas.joeyone.cn` | Atlas 一级子域名的通配符 SAN |
|
||
| `img.atlas.joeyone.cn` | 生产图片域名 |
|
||
| `img-dev.atlas.joeyone.cn` | 开发图片域名 |
|
||
| `ops@joeyone.cn` | 能接收通知的邮箱 |
|
||
| `atlas-prod-assets` / `atlas-dev-assets` | 你实际创建的空间 |
|
||
| `OWNER_UIN` / `DNSPOD_DOMAIN_ID` | 腾讯云主账号 UIN / DNSPod 域名 ID |
|
||
|
||
确认实际 DNS 服务商:
|
||
|
||
```bash
|
||
dig +short NS joeyone.cn
|
||
```
|
||
|
||
主流程使用腾讯云 DNSPod 新版 API,即 `dns_tencent` 插件及 `Tencent_SecretId`、`Tencent_SecretKey`。如果 NS 和管理控制台不是 DNSPod,先阅读第 15 节,不要申请无关的腾讯云 DNS 密钥。
|
||
|
||
## 3. 在七牛创建空间和 CDN 下载域名
|
||
|
||
### 3.1 创建两个私有空间
|
||
|
||
在七牛控制台的对象存储中创建开发、生产空间:
|
||
|
||
1. 访问控制选 **私有**。
|
||
2. 为两环境分别记录空间名、区域、S3 空间名和 S3 endpoint。
|
||
3. 区域按应用访问和目标客户地区选择;Ozon 抓图需要额外验证境外可访问性。
|
||
4. 应用使用的存储凭据按环境授权,不在本地开发配置生产空间的读写凭据。
|
||
|
||
本文的证书自动化任务是集中运维任务,可以维护两个域名。它使用的七牛管理凭据不应下发给浏览器,也不应与本地开发的素材上传权限混为一谈。
|
||
|
||
### 3.2 绑定「自定义 CDN 加速域名」
|
||
|
||
分别为两个空间添加域名:
|
||
|
||
| 控制台项目 | 开发域名 | 生产域名 |
|
||
|---|---|---|
|
||
| 域名 | `img-dev.atlas.joeyone.cn` | `img.atlas.joeyone.cn` |
|
||
| 域名类型 | 自定义 CDN 加速域名 | 自定义 CDN 加速域名 |
|
||
| 源站 | 对应开发私有空间 | 对应生产私有空间 |
|
||
| 使用场景 | 图片 / 小文件 | 图片 / 小文件 |
|
||
| 覆盖范围 | 按实际访问地区选择 | 必须包含 Ozon 实际抓图所需地区并验收 |
|
||
|
||
本流程使用 CDN 域名。七牛官方 FAQ 明确区分:CDN 可以通过 API 更新证书,Kodo 自定义源站域名目前需要在控制台手动绑定证书。[七牛 SSL FAQ,Q15](https://developer.qiniu.com/fusion/kb/3905/ssl-certificate-faq?category=kb)
|
||
|
||
涉及中国大陆的域名接入,按七牛控制台要求完成 ICP 备案;不将选择境外节点视为本项目的备案替代方案。
|
||
|
||
首次创建时如果支持先以 HTTP 创建,可以先完成域名和 CNAME,稍后用正式证书开启 HTTPS。如果界面要求证书才能继续,可先完成第 4~7 节申请证书,再回来绑定。若已有可用 HTTPS 证书,保留原绑定,直到新证书准备好后替换。
|
||
|
||
### 3.3 配置四个域名的 DNS
|
||
|
||
先按第 1.1 节为网站配置 `atlas`、`dev.atlas` 的 A 记录;如果服务器有 IPv6 并已提供相应服务,可按实际情况另配 AAAA。
|
||
|
||
为两个图片子域名添加以下解析,记录值分别从七牛域名配置页复制,不自行猜测:
|
||
|
||
| 主机记录 | 类型 | 记录值 | 线路 |
|
||
|---|---|---|---|
|
||
| `img-dev.atlas` | CNAME | 七牛给开发域名提供的目标 | 默认 |
|
||
| `img.atlas` | CNAME | 七牛给生产域名提供的目标 | 默认 |
|
||
|
||
同一个主机记录不要同时保留指向应用服务器的 A / AAAA 记录。若 DNS 服务商具有代理/CDN 开关,本手册路径使用 DNS 解析模式,避免引入第二层代理。
|
||
|
||
验证:
|
||
|
||
```bash
|
||
dig +short A atlas.joeyone.cn
|
||
dig +short A dev.atlas.joeyone.cn
|
||
dig +short CNAME img-dev.atlas.joeyone.cn
|
||
dig +short CNAME img.atlas.joeyone.cn
|
||
```
|
||
|
||
本证书的两个 SAN 都使用 `_acme-challenge.atlas.joeyone.cn` 验证,在 `joeyone.cn` 区域内的主机记录是 `_acme-challenge.atlas`。同一记录下可能同时出现两个 TXT 值,这是正常的;由 acme.sh 自动创建、保留到验证完成后清理,不手工覆盖其中一个。它和网站 A、图片 CNAME 不冲突。不要提前给挑战记录添加会干扰验证的其他 CNAME。
|
||
|
||
### 3.4 开启私有空间回源鉴权
|
||
|
||
在七牛 **CDN → 域名管理 → 对应域名 → 配置 → 访问控制 → 回源鉴权** 中开启。源站为七牛私有 bucket 时,按七牛内置私有空间模式配置,不需要搭建自己的鉴权服务器。[七牛回源鉴权说明](https://developer.qiniu.com/fusion/3930/back-to-the-source-authentication)
|
||
|
||
两个域名都要配置,并等待控制台显示配置生效。Ozon 发布链路使用七牛私有下载凭证 `e` / `token`:
|
||
|
||
- 不额外开启一套要求 `sign` / `t` 的 CDN 时间戳防盗链;那是不同签名协议,现有 Worker 不会生成该凭证。
|
||
- 不设置仅允许 Atlas 网站 Referer 的白名单;平台抓图可能没有 Referer。
|
||
- 不用登录 Cookie、固定浏览器 UA 或未经验证的 Ozon IP 白名单作为抓图前提。
|
||
- CDN 缓存可以启用,但缓存命中也必须执行私有访问鉴权。第 11 节会验证这一点。
|
||
|
||
两种签名协议和互斥限制参见[七牛访问控制 API](https://developer.qiniu.com/fusion/13364/fusion-api-domain-config)。
|
||
|
||
## 4. 腾讯云服务器准备
|
||
|
||
### 4.1 确认系统与网络
|
||
|
||
SSH 登录后先检查:
|
||
|
||
```bash
|
||
cat /etc/os-release
|
||
timedatectl status
|
||
```
|
||
|
||
主流程假设 Ubuntu 24.04 + systemd。若为 TencentOS Server、Rocky Linux 等,使用相应包管理器安装 Bash、Git、curl、OpenSSL、CA 根证书、Python 3、DNS 查询工具及 util-linux;其余 systemd 流程相同。不要为执行本手册重装正在运行的服务器。
|
||
|
||
DNS-01 验证本身不需要开放入站 80 / 443。网站仍需要 Nginx 的 443 入站及现有 HTTP 跳转规则;保留业务服务原有规则。证书任务需要以下出站能力:
|
||
|
||
| 流量 | 目的 |
|
||
|---|---|
|
||
| TCP 443 | GitHub、Let's Encrypt、DNSPod API、七牛 API、两个图片域名 |
|
||
| UDP / TCP 53 | DNS 查询和验证 |
|
||
| 实际 SMTP 端口,例如 TCP 465 / 587 | 第 10 节的通知 |
|
||
| 系统原有时间同步流量 | 正确验证签名和证书时间 |
|
||
|
||
腾讯云 CVM 检查实例关联的安全组及本机防火墙;轻量应用服务器检查其防火墙与实际出站限制。不覆盖现有规则、不放通全部端口。无公网出站的私网实例还需要 NAT 等出口。[腾讯云安全组概述](https://cloud.tencent.com/document/product/213/112610)
|
||
|
||
### 4.2 安装工具并创建维护账号
|
||
|
||
以下命令由具有 `sudo` 权限的管理用户执行:
|
||
|
||
```bash
|
||
sudo apt-get update
|
||
sudo apt-get install -y ca-certificates curl git openssl dnsutils python3 util-linux nano
|
||
|
||
sudo useradd --system --create-home \
|
||
--home-dir /var/lib/atlas-cert \
|
||
--shell /bin/bash atlas-cert
|
||
sudo chmod 700 /var/lib/atlas-cert
|
||
sudo install -d -m 700 -o atlas-cert -g atlas-cert /var/lib/atlas-cert/src
|
||
sudo -iu atlas-cert
|
||
```
|
||
|
||
`useradd` 只在首次执行;如果账号已经存在,检查其 home 和用途后复用,不重复创建。维护账号不需要 sudo 权限。接下来第 5~8 节在这个账号的 Bash 会话里执行。
|
||
|
||
## 5. 创建 DNSPod 和七牛凭据
|
||
|
||
### 5.1 腾讯云 DNSPod API 凭据
|
||
|
||
在腾讯云 **访问管理 CAM → 用户列表** 创建仅用于证书 DNS 验证的子用户,再为该子用户创建 API 密钥。保存 `SecretId` 和 `SecretKey`,不要使用主账号全权限密钥。[子账号 API 密钥管理](https://cloud.tencent.com/document/product/598/37140)
|
||
|
||
acme.sh 3.1.6 的 `dns_tencent` 脚本调用以下四个 DNSPod 操作:
|
||
|
||
| 操作 | 用途 |
|
||
|---|---|
|
||
| `DescribeRecordList` | 探测域名所在 DNS 区域 |
|
||
| `DescribeRecordFilterList` | 查找本次验证创建的 TXT |
|
||
| `CreateRecord` | 创建验证 TXT |
|
||
| `DeleteRecord` | 清理验证 TXT |
|
||
|
||
参考实现:[dns_tencent 3.1.6](https://github.com/acmesh-official/acme.sh/blob/3.1.6/dnsapi/dns_tencent.sh)。
|
||
|
||
在 CAM 创建自定义策略并关联子用户。以下 JSON 中的 `OWNER_UIN` 必须换成资源所属主账号 UIN,`DNSPOD_DOMAIN_ID` 换成 DNSPod 控制台/API 获取的域名 ID,不是文字域名:
|
||
|
||
```json
|
||
{
|
||
"version": "2.0",
|
||
"statement": [
|
||
{
|
||
"effect": "allow",
|
||
"action": [
|
||
"dnspod:DescribeRecordList",
|
||
"dnspod:DescribeRecordFilterList",
|
||
"dnspod:CreateRecord",
|
||
"dnspod:DeleteRecord"
|
||
],
|
||
"resource": ["qcs::dnspod::uin/OWNER_UIN:domain/DNSPOD_DOMAIN_ID"]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
本例授权 `joeyone.cn` 所在的 domain 资源。DNSPod 当前资源模型按域名授权,上述权限能修改该主域名内的记录,并非仅 `_acme-challenge.atlas` 的 TXT;更严格的隔离可另行采用挑战域委托。资源格式以[腾讯云 DNSPod 授权资源说明](https://cloud.tencent.com/document/product/302/105719)为准,首次验证失败应检查策略和资源归属,不直接改成全账号管理权限。
|
||
|
||
### 5.2 七牛证书部署凭据
|
||
|
||
准备可访问目标 CDN 域名的七牛 AK / SK。证书部署需要上传证书及修改这两个 CDN 域名的 HTTPS 配置;单纯的 bucket 上传 token 或 S3 对象写入权限不能代替这些管理权限。
|
||
|
||
能使用子账号/策略时按当前七牛账号实际支持的权限限制授权范围,并通过首次部署验证。不要假设所有七牛 AK 都是 bucket 级凭据。若开发、生产域名属于不同七牛账号,本手册单组 AK / SK 无法同时更新两者,需分别部署各账号的任务和凭据。
|
||
|
||
### 5.3 保存维护配置
|
||
|
||
在 `atlas-cert` 会话执行。先创建文件,再用编辑器填写,真实密钥不作为命令参数或终端历史输入:
|
||
|
||
```bash
|
||
umask 077
|
||
test -e /var/lib/atlas-cert/secrets.env || \
|
||
install -m 600 /dev/null /var/lib/atlas-cert/secrets.env
|
||
nano /var/lib/atlas-cert/secrets.env
|
||
```
|
||
|
||
填写下面的内容,替换所有示例值:
|
||
|
||
```bash
|
||
CERT_EMAIL='ops@joeyone.cn'
|
||
CERT_MAIN_DOMAIN='atlas.joeyone.cn'
|
||
CERT_WILDCARD_DOMAIN='*.atlas.joeyone.cn'
|
||
|
||
Tencent_SecretId='替换为证书维护子账号的SecretId'
|
||
Tencent_SecretKey='替换为证书维护子账号的SecretKey'
|
||
|
||
QINIU_AK='替换为七牛证书部署AK'
|
||
QINIU_SK='替换为七牛证书部署SK'
|
||
QINIU_CDN_DOMAIN='img.atlas.joeyone.cn img-dev.atlas.joeyone.cn'
|
||
QINIU_FORCE_HTTPS='true'
|
||
```
|
||
|
||
这是 Bash 配置文件,键名区分大小写。`CERT_WILDCARD_DOMAIN` 必须保留 `*` 并加引号;后面的申请命令也始终给变量加引号,避免 shell 展开。`QINIU_CDN_DOMAIN` 只填两个实际图片域名,用空格分隔,不带 `https://`、路径、通配符或前导点,也不填两个网站域名。
|
||
|
||
加载配置:
|
||
|
||
```bash
|
||
set -a
|
||
. /var/lib/atlas-cert/secrets.env
|
||
set +a
|
||
```
|
||
|
||
acme.sh 会在自己的配置目录缓存 DNS/七牛凭据,因此 `secrets.env` 和 `.acme.sh` 整个目录都必须按秘密文件管理;仅删除环境文件并不能撤销缓存凭据。不要执行会完整输出配置的 `--info`,不要启用 `set -x`、不安全调试输出或把原始日志发到公共渠道。
|
||
|
||
## 6. 安装 acme.sh 并先做 DNS 验证演练
|
||
|
||
### 6.1 安装固定版本
|
||
|
||
继续在 `atlas-cert` 会话执行:
|
||
|
||
```bash
|
||
git clone --depth 1 --branch 3.1.6 \
|
||
https://github.com/acmesh-official/acme.sh.git \
|
||
/var/lib/atlas-cert/src/acme.sh
|
||
cd /var/lib/atlas-cert/src/acme.sh
|
||
./acme.sh --install \
|
||
--home /var/lib/atlas-cert/.acme.sh \
|
||
--accountemail "$CERT_EMAIL" \
|
||
--no-cron --no-profile
|
||
chmod 700 /var/lib/atlas-cert/.acme.sh
|
||
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh --version
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh --set-default-ca --server letsencrypt
|
||
```
|
||
|
||
安装目录与源码目录如果已存在,先检查原部署;不要覆盖其他证书任务。本文明确禁用安装器的默认 cron,第 9 节统一用 systemd timer,避免重复续期。版本升级应在维护窗口检查发行说明后进行,而非每次定时任务自动下载最新代码。
|
||
|
||
### 6.2 使用 Let's Encrypt 测试环境验证 DNS 权限
|
||
|
||
测试证书保存到独立目录,不上传七牛,也不用于浏览器/Ozon。它只用于确认 DNS 验证流程可自动运行:
|
||
|
||
```bash
|
||
install -d -m 700 /var/lib/atlas-cert/acme-staging
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--home /var/lib/atlas-cert/.acme.sh \
|
||
--config-home /var/lib/atlas-cert/acme-staging \
|
||
--register-account --server letsencrypt_test -m "$CERT_EMAIL"
|
||
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--home /var/lib/atlas-cert/.acme.sh \
|
||
--config-home /var/lib/atlas-cert/acme-staging \
|
||
--issue --server letsencrypt_test --dns dns_tencent \
|
||
-d "$CERT_MAIN_DOMAIN" -d "$CERT_WILDCARD_DOMAIN" \
|
||
--keylength 2048
|
||
```
|
||
|
||
RSA 2048 用作兼容性示例,避免后续文件目录和 `--ecc` 参数混用。acme.sh 会创建临时 TXT、等待 DNS 验证并清理;首次可能需几分钟。成功后在 DNSPod 检查本次 TXT 已清理,且两个图片 CNAME 保持正确。
|
||
|
||
### 2026-10-03 现场执行记录
|
||
|
||
- 服务器上的 `atlas-cert` 账号运行上述 staging `--issue` 命令,于北京时间 2026-10-03 11:02:09 收到证书文件路径及续期窗口输出;这确认测试环境签发已完成,不能视为正式证书或七牛部署验收。
|
||
- 测试证书位于 `/var/lib/atlas-cert/acme-staging/atlas.joeyone.cn/`:叶证书 `atlas.joeyone.cn.cer`、私钥 `atlas.joeyone.cn.key`、中间证书 `ca.cer`、完整证书链 `fullchain.cer`。这里只记录路径,不记录证书或私钥内容。
|
||
- 本次 staging 输出的 ARI 建议窗口为 `2026-12-01T04:47:36Z`~`2026-12-02T23:58:26Z`,所选下次续期时间为 `2026-12-01T20:38:56Z`;这些是**测试证书**的输出,不能用作正式证书续期日程。
|
||
- DNSPod 自动验证已使签发完成;临时 TXT 是否清理、两个图片域名 CNAME 是否保持正确仍需在 DNSPod 复核。随后按第 7 节申请正式证书,并用 `openssl` 检查正式证书的 SAN 和有效期。
|
||
- 正式签发和部署前,确认此前截图中暴露的腾讯云及七牛凭据均已停用、更换,并核对 `secrets.env` 与 acme.sh 缓存中的凭据。不要在项目文档或排错日志中保存真实密钥。
|
||
|
||
如果有 CAA 记录,确保它允许 Let's Encrypt 的 `letsencrypt.org` 签发;不要为排错直接删除业务已有 CAA。DNS-01 验证原理参见[Let's Encrypt 官方说明](https://letsencrypt.org/docs/challenge-types/)。
|
||
|
||
## 7. 申请正式证书
|
||
|
||
测试验证通过后,仍在 `atlas-cert` 会话执行。正式流程使用默认配置目录,与测试目录分开:
|
||
|
||
```bash
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--register-account --server letsencrypt -m "$CERT_EMAIL"
|
||
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--issue --server letsencrypt --dns dns_tencent \
|
||
-d "$CERT_MAIN_DOMAIN" -d "$CERT_WILDCARD_DOMAIN" \
|
||
--keylength 2048
|
||
|
||
openssl x509 \
|
||
-in "/var/lib/atlas-cert/.acme.sh/$CERT_MAIN_DOMAIN/fullchain.cer" \
|
||
-noout -issuer -dates -ext subjectAltName
|
||
```
|
||
|
||
确认 SAN 同时包含 `atlas.joeyone.cn` 与 `*.atlas.joeyone.cn`,证书颁发者属于正式受信任 CA。不要把第 6 节测试证书部署到七牛;不要通过反复 `--force` 申请正式证书来测试定时任务。
|
||
|
||
证书目录下:
|
||
|
||
| 文件 | 七牛用途 |
|
||
|---|---|
|
||
| `fullchain.cer` | 完整证书链,上传为证书内容 |
|
||
| `atlas.joeyone.cn.key` | 证书私钥 |
|
||
|
||
证书私钥仅用于证书部署,不是七牛 SK,也不是 Ozon 店铺 API Key。
|
||
|
||
### 2026-10-03 正式签发记录
|
||
|
||
维护者在北京时间 2026-10-03 11:08:13 收到正式证书签发成功输出,证书目录为 `/var/lib/atlas-cert/.acme.sh/atlas.joeyone.cn/`。随后运行本节的 OpenSSL 检查,结果如下;尚未据此确认七牛或网站已使用新证书。
|
||
|
||
| 项目 | 本次结果 |
|
||
|---|---|
|
||
| 颁发者 | `C = US, O = Let's Encrypt, CN = YR2` |
|
||
| SAN | `*.atlas.joeyone.cn`、`atlas.joeyone.cn` |
|
||
| 生效时间 | UTC `2026-10-03 02:09:40`;北京时间 `2026-10-03 10:09:40` |
|
||
| 到期时间 | UTC `2027-01-01 02:09:39`;北京时间 `2027-01-01 10:09:39` |
|
||
| ARI 建议窗口 | UTC `2026-12-01 04:53:44`~`2026-12-03 00:04:34` |
|
||
| acme.sh 所选下次续期时间 | UTC `2026-12-01 20:51:08`;北京时间 `2026-12-02 04:51:08` |
|
||
|
||
ARI 时间是客户端本次选择的续期时间,实际自动执行仍依赖第 9 节的定时任务。下一步为第 8.1 节首次上传和启用七牛 HTTPS。
|
||
|
||
## 8. 首次开启七牛 HTTPS 并配置自动部署
|
||
|
||
### 8.1 首次开启 HTTPS
|
||
|
||
内置七牛 hook 调用修改 HTTPS 配置接口。因此首次先在控制台将两个 CDN 域名的 HTTPS 都启用,再交给 hook 维护;避免域名尚未开启 HTTPS 时直接调用更新接口失败。
|
||
|
||
1. 用 SSH/SFTP 客户端从服务器安全取回第 7 节的 `fullchain.cer` 和域名 `.key` 文件。
|
||
2. 在七牛 **SSL 证书服务 → 证书管理 → 上传自有证书** 中上传完整链和私钥;使用 PEM/Nginx 格式。
|
||
3. 在七牛 **CDN → 域名管理 → 对应域名 → HTTPS 配置**,两个域名都选择刚上传的证书并开启 HTTPS。
|
||
4. 如需 HTTP 强制跳转 HTTPS,保持与 `QINIU_FORCE_HTTPS='true'` 一致。
|
||
5. 等待控制台显示部署完成,检查两个域名的证书;临时下载到本机的私钥按秘密文件管理,传递结束后清理临时副本。
|
||
|
||
取回文件时可复用已有管理员 SSH 连接的 SFTP 文件面板。本次服务器使用已有的 `root` 管理连接访问证书目录;终端内的 `sudo -iu atlas-cert` 不会改变文件面板的登录身份。不要为下载文件给维护账号新增 SSH 密码或放宽证书目录权限。
|
||
|
||
1. 打开客户端的服务器文件面板,将远端路径设为 `/var/lib/atlas-cert/.acme.sh/atlas.joeyone.cn/`。`.acme.sh` 是隐藏目录,优先直接输入完整路径,或启用“显示隐藏文件”。
|
||
2. 只下载 `fullchain.cer` 和 `atlas.joeyone.cn.key` 到本机专用临时目录,保留服务器上的原文件。不要下载整个 `.acme.sh`,其中包含账户与 DNS/API 凭据。
|
||
3. 在七牛上传这两个文件;若页面要求填写 PEM 文本,在本机文本编辑器打开对应文件,完整复制各自的 BEGIN/END 区块。私钥不发送到聊天、项目仓库或公共日志。
|
||
4. 两个域名证书验收完成后,清理本机临时副本;服务器原文件继续供后续自动续期与部署使用。
|
||
|
||
如果两个域名原本就已开启 HTTPS,先上传并切换到新证书即可。不要先删除旧证书。
|
||
|
||
### 8.2 执行一次自动部署
|
||
|
||
在 `atlas-cert` 会话执行:
|
||
|
||
```bash
|
||
set -a
|
||
. /var/lib/atlas-cert/secrets.env
|
||
set +a
|
||
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--deploy -d "$CERT_MAIN_DOMAIN" --deploy-hook qiniu
|
||
```
|
||
|
||
该步骤会上传证书,并逐一更新 `QINIU_CDN_DOMAIN` 中的两个域名,同时保存部署 hook 供续期时调用。确认输出包含两个域名的部署成功记录,并在七牛控制台复核。首次手工上传和 hook 上传可能留下两条证书记录,这是正常的;验收后按引用情况清理旧条目。
|
||
|
||
2026-10-03 现场记录:维护者以 `atlas-cert` 执行上述部署命令,于北京时间 11:26:12 收到 `img.atlas.joeyone.cn` 和 `img-dev.atlas.joeyone.cn` 各自的 `certificate has been deployed successfully`,最终输出 `Success`。随后两个图片域名的网络证书检查结果已记录于第 10.2 节;自动续期执行仍需完成第 9 节的 systemd timer。日志中的 `updating domain atlas.joeyone.cn` 使用证书主域名标识本次证书,不能据此判断网站 Nginx 已更新。
|
||
|
||
参考:[acme.sh 七牛部署实现](https://github.com/acmesh-official/acme.sh/blob/3.1.6/deploy/qiniu.sh)、[七牛证书管理与部署 FAQ](https://developer.qiniu.com/fusion/3905/ssl-certificate-faq)。
|
||
|
||
收紧本地文件权限:
|
||
|
||
```bash
|
||
find /var/lib/atlas-cert/.acme.sh -type d -exec chmod 700 {} +
|
||
find /var/lib/atlas-cert/.acme.sh -type f -exec chmod go-rwx {} +
|
||
find /var/lib/atlas-cert/acme-staging -type d -exec chmod 700 {} +
|
||
find /var/lib/atlas-cert/acme-staging -type f -exec chmod go-rwx {} +
|
||
```
|
||
|
||
### 8.3 导出同一张证书给本机 Nginx
|
||
|
||
继续在 `atlas-cert` 会话执行:
|
||
|
||
```bash
|
||
install -d -m 700 /var/lib/atlas-cert/nginx-export
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--install-cert -d "$CERT_MAIN_DOMAIN" \
|
||
--key-file /var/lib/atlas-cert/nginx-export/privkey.pem \
|
||
--fullchain-file /var/lib/atlas-cert/nginx-export/fullchain.pem
|
||
chmod 600 /var/lib/atlas-cert/nginx-export/privkey.pem \
|
||
/var/lib/atlas-cert/nginx-export/fullchain.pem
|
||
```
|
||
|
||
`--install-cert` 会保存导出路径,续期时自动更新这两个文件。Nginx 不直接引用 acme.sh 内部文件;本流程由第 9.2 节的 root 管理脚本复制到 `/etc/nginx/tls/atlas/current/`、执行 `nginx -t` 并重载,因此这里没有设置 `--reloadcmd`。必须完成第 9 节,只有导出证书不能让 Nginx 使用新证书。[acme.sh 证书安装说明](https://github.com/acmesh-official/acme.sh#3-install-the-cert-to-apachenginx-etc)
|
||
|
||
2026-10-03 现场记录:北京时间 11:27:26,维护者收到两项 `Installing` 输出,证书已导出到以下路径;Nginx 接入仍需完成第 9.2 节。
|
||
|
||
| 文件用途 | 实际导出路径 |
|
||
|---|---|
|
||
| 证书私钥 | `/var/lib/atlas-cert/nginx-export/privkey.pem` |
|
||
| 完整证书链 | `/var/lib/atlas-cert/nginx-export/fullchain.pem` |
|
||
|
||
维护账号不获得通用 sudo 权限。证书申请和七牛 API 调用以 `atlas-cert` 执行;复制到系统证书目录与 Nginx 重载由 systemd 的 root 步骤完成。root 脚本不加载 `secrets.env`,只读取固定路径的证书文件。
|
||
|
||
## 9. 配置 systemd 定时续期
|
||
|
||
### 9.1 创建续期入口
|
||
|
||
在 `atlas-cert` 会话创建脚本:
|
||
|
||
```bash
|
||
cat > /var/lib/atlas-cert/renew-qiniu.sh <<'SH'
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
umask 077
|
||
|
||
# 统一加载维护凭据,定时任务不依赖人工登录会话。
|
||
set -a
|
||
. /var/lib/atlas-cert/secrets.env
|
||
set +a
|
||
|
||
# 与手工维护共用锁文件,避免并发操作同一套证书。
|
||
exec 9>/var/lib/atlas-cert/renew.lock
|
||
flock -n 9 || exit 0
|
||
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--cron --home /var/lib/atlas-cert/.acme.sh
|
||
SH
|
||
chmod 700 /var/lib/atlas-cert/renew-qiniu.sh
|
||
# 首次由维护账号创建锁,避免 root 部署脚本先创建后导致维护账号无法写入。
|
||
test -e /var/lib/atlas-cert/renew.lock || \
|
||
install -m 600 /dev/null /var/lib/atlas-cert/renew.lock
|
||
bash -n /var/lib/atlas-cert/renew-qiniu.sh
|
||
exit
|
||
```
|
||
|
||
`exit` 返回原管理账号。
|
||
|
||
### 9.2 创建 Nginx 部署脚本并完成首次接入
|
||
|
||
本节按网站服务选择接入方式:当前现场使用 **9.2.1 的 1Panel 分支**;9.2.2 仅适用于已经安装并运行宿主机 systemd Nginx 的服务器。
|
||
|
||
> 2026-10-03 现场环境确认:服务器为 1Panel `v2.0.11 stable`,网站服务容器为 `1Panel-openresty-C1B1`,镜像为 `1panel/openresty:1.27.1.2-2-3-focal`。维护者执行本节原脚本时,证书检查与宿主机 `nginx -t` 通过,但 `systemctl reload nginx` 报 `nginx.service is not active, cannot reload`;本节接入未完成。应用部署后应使用 1Panel 配置网站 HTTPS,证书续期后的同步与容器重载需按实际网站配置适配。当前可先启用第 9.3 节不含网站部署步骤的基础定时任务,待适配验收后补上 `ExecStartPost`。
|
||
>
|
||
> 1Panel v2.0.11 从服务器路径导入证书时会读取并保存内容,不能把导入操作视为持续引用源文件;acme.sh 更新 `nginx-export` 后仍需主动同步到 1Panel 网站使用的证书。依据:[v2.0.11 证书导入实现](https://github.com/1Panel-dev/1Panel/blob/v2.0.11/agent/app/service/website_ssl.go)。
|
||
|
||
#### 9.2.1 当前现场:1Panel/OpenResty,应用尚未部署
|
||
|
||
2026-10-03,维护者通过 `docker inspect` 与容器内 `nginx -T` 确认以下挂载关系:
|
||
|
||
| 宿主机路径 | OpenResty 容器路径 | 用途 |
|
||
|---|---|---|
|
||
| `/opt/1panel/www` | `/www` | 网站目录及各网站证书文件 |
|
||
| `/opt/1panel/www/conf.d` | `/usr/local/openresty/nginx/conf/conf.d` | 网站配置 |
|
||
| `/opt/1panel/apps/openresty/openresty/conf/ssl` | `/usr/local/openresty/nginx/conf/ssl` | 默认站点证书 |
|
||
|
||
现有网站包括 `git.joeyone.cn`、`pipi-assets.joeyone.cn`、`test.joeyone.cn`、`wmd.joeyone.cn`,分别使用 `/www/sites/<网站域名>/ssl/fullchain.pem` 和 `privkey.pem`。输出中没有 `atlas.joeyone.cn` 或 `dev.atlas.joeyone.cn` 的网站配置;维护者确认两套 Atlas 应用尚未部署。
|
||
|
||
**当前可先完成图片域名验收及第 9.3 节的七牛续期任务。** 网站应用未部署前,无需创建占位反向代理,也不把项目本地开发端口当作云端应用地址。现有网站及默认站点证书继续由各自配置维护。
|
||
|
||
应用部署时按以下顺序接入:
|
||
|
||
1. 部署生产、开发应用,确认各自实际访问地址、监听端口及 OpenResty 容器可达性。
|
||
2. 在 1Panel 的“网站 → 证书”上传正式证书,使用“本地导入/服务器路径”时填写以下**宿主机路径**;若界面要求文件内容,则在受控终端读取后粘贴,不将私钥发送到聊天或提交到仓库。
|
||
|
||
- 证书:`/var/lib/atlas-cert/nginx-export/fullchain.pem`
|
||
- 私钥:`/var/lib/atlas-cert/nginx-export/privkey.pem`
|
||
|
||
3. 在 1Panel 新建 `atlas.joeyone.cn` 和 `dev.atlas.joeyone.cn` 网站,配置各自真实应用的反向代理,并在 HTTPS 设置中选择导入的同一张 Atlas 证书。
|
||
4. 再次检查网站配置中的实际证书路径,并从网络验证两个网站证书和环境路由。文件目录可能由网站创建方式决定,不预先假设一定为 `/www/sites/atlas.joeyone.cn`。
|
||
5. 接入续期后同步:优先通过与 1Panel 版本匹配的证书更新接口更新已导入证书,使面板记录与关联网站一起更新;验收后再接入第 9.3 节的 `ExecStartPost`。当前未确认面板接口配置、证书 ID 和新网站实际路径,自动同步尚未完成。
|
||
|
||
仅手工导入证书不会完成网站自动续期部署。以后只替换网站目录里的 PEM 文件也可能造成面板保存的证书内容与实际文件不一致,后续面板操作可能重新写入旧内容,应完成上述同步适配。
|
||
|
||
#### 9.2.2 宿主机 systemd Nginx 分支
|
||
|
||
以下示例仅用于宿主机 Nginx。当前 1Panel 现场跳过本小节;不要为使旧脚本成功而启动另一个宿主机 Nginx。
|
||
|
||
以下由管理账号执行。脚本及系统证书目录由 root 管理,维护账号不能修改部署脚本。每次部署使用独立版本目录,只有配置检查和重载成功后才记录成功指纹;失败则恢复原目录链接,供下次重试:
|
||
|
||
```bash
|
||
sudo install -d -m 700 -o root -g root /etc/nginx/tls/atlas
|
||
sudo tee /usr/local/sbin/atlas-cert-install-nginx > /dev/null <<'SH'
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
umask 077
|
||
|
||
# 与申请、手工部署共用锁,避免读取尚未导出完的证书。
|
||
exec 9>/var/lib/atlas-cert/renew.lock
|
||
flock 9
|
||
|
||
cert_root=/etc/nginx/tls/atlas
|
||
export_root=/var/lib/atlas-cert/nginx-export
|
||
release=$(mktemp -d "$cert_root/release.XXXXXXXX")
|
||
old_target=$(readlink "$cert_root/current" || true)
|
||
activated=0
|
||
finished=0
|
||
|
||
# 失败时恢复上一次目录,不把未成功部署的指纹标记为完成。
|
||
cleanup() {
|
||
if [[ "$finished" != 1 ]]; then
|
||
if [[ "$activated" == 1 ]]; then
|
||
if [[ -n "$old_target" ]]; then
|
||
ln -s "$old_target" "$cert_root/.rollback"
|
||
mv -Tf "$cert_root/.rollback" "$cert_root/current"
|
||
else
|
||
rm -f "$cert_root/current"
|
||
fi
|
||
fi
|
||
rm -rf "$release"
|
||
fi
|
||
}
|
||
trap cleanup EXIT
|
||
|
||
install -m 600 "$export_root/fullchain.pem" "$release/fullchain.pem"
|
||
install -m 600 "$export_root/privkey.pem" "$release/privkey.pem"
|
||
openssl x509 -in "$release/fullchain.pem" -noout -checkend 0
|
||
for cert_domain in atlas.joeyone.cn dev.atlas.joeyone.cn img.atlas.joeyone.cn img-dev.atlas.joeyone.cn; do
|
||
openssl x509 -in "$release/fullchain.pem" -noout -checkhost "$cert_domain"
|
||
done
|
||
|
||
# 验证公钥一致,不输出私钥或证书原文。
|
||
cert_pub=$(openssl x509 -in "$release/fullchain.pem" -pubkey -noout |
|
||
openssl pkey -pubin -outform DER | sha256sum)
|
||
key_pub=$(openssl pkey -in "$release/privkey.pem" -pubout -outform DER | sha256sum)
|
||
[[ "$cert_pub" == "$key_pub" ]]
|
||
fingerprint=$(openssl x509 -in "$release/fullchain.pem" -noout -fingerprint -sha256)
|
||
if [[ -L "$cert_root/current" && -f "$cert_root/deployed-fingerprint" ]] &&
|
||
[[ "$(cat "$cert_root/deployed-fingerprint")" == "$fingerprint" ]]; then
|
||
rm -rf "$release"
|
||
finished=1
|
||
exit 0
|
||
fi
|
||
|
||
ln -s "$(basename "$release")" "$cert_root/.next"
|
||
mv -Tf "$cert_root/.next" "$cert_root/current"
|
||
activated=1
|
||
/usr/sbin/nginx -t
|
||
/usr/bin/systemctl reload nginx
|
||
printf '%s\n' "$fingerprint" > "$cert_root/deployed-fingerprint"
|
||
finished=1
|
||
SH
|
||
sudo chown root:root /usr/local/sbin/atlas-cert-install-nginx
|
||
sudo chmod 700 /usr/local/sbin/atlas-cert-install-nginx
|
||
sudo bash -n /usr/local/sbin/atlas-cert-install-nginx
|
||
sudo /usr/local/sbin/atlas-cert-install-nginx
|
||
```
|
||
|
||
第一次运行会建立 `current` 目录链接,并检查/重载已有 Nginx。随后在**现有**生产和开发网站 `server` 配置中分别设置如下 TLS 指令,保留各自原有 `location`、反向代理、访问控制和日志配置。以下是待合并的片段,不是完整站点配置:
|
||
|
||
```nginx
|
||
# 生产网站的 TLS 配置,业务路由沿用现有生产配置。
|
||
listen 443 ssl;
|
||
server_name atlas.joeyone.cn;
|
||
ssl_certificate /etc/nginx/tls/atlas/current/fullchain.pem;
|
||
ssl_certificate_key /etc/nginx/tls/atlas/current/privkey.pem;
|
||
```
|
||
|
||
```nginx
|
||
# 开发网站使用同一张证书,业务路由指向开发环境。
|
||
listen 443 ssl;
|
||
server_name dev.atlas.joeyone.cn;
|
||
ssl_certificate /etc/nginx/tls/atlas/current/fullchain.pem;
|
||
ssl_certificate_key /etc/nginx/tls/atlas/current/privkey.pem;
|
||
```
|
||
|
||
同一 IP 可承载两个网站,Nginx 按域名选择对应的 `server`;两个网站的 upstream 和环境配置仍分别维护。不要仅因证书共用就让开发流量进入生产应用。[Nginx HTTPS 配置说明](https://nginx.org/en/docs/http/configuring_https_servers.html)
|
||
|
||
配置编辑完成后,由管理账号执行:
|
||
|
||
```bash
|
||
sudo nginx -t
|
||
sudo systemctl reload nginx
|
||
```
|
||
|
||
旧证书版本目录暂时保留作为回滚材料。新证书在四个域名验收通过后,可由管理账号清理不再需要的旧版本,保留当前版本和仍有效的回滚版本。目录含私钥,权限保持 700/600。
|
||
|
||
### 9.3 配置定时任务
|
||
|
||
当前 1Panel 现场尚未部署 Atlas 网站,先创建**证书续期、七牛部署及 PEM 导出**的定时任务。以下基础服务不调用第 9.2.2 节的宿主机 Nginx 脚本,因此不会因 `nginx.service` 未运行而报错;网站自动同步仍须在应用部署后单独接入。
|
||
|
||
以下由管理账号执行,创建 systemd 单元。如果先前已创建含 `ExecStartPost=/usr/local/sbin/atlas-cert-install-nginx` 的服务,使用此基础单元覆盖后重新加载:
|
||
|
||
```bash
|
||
sudo tee /etc/systemd/system/atlas-qiniu-cert-renew.service > /dev/null <<'UNIT'
|
||
[Unit]
|
||
Description=Atlas shared certificate renewal and deployment
|
||
Wants=network-online.target
|
||
After=network-online.target
|
||
|
||
[Service]
|
||
Type=oneshot
|
||
WorkingDirectory=/var/lib/atlas-cert
|
||
UMask=0077
|
||
ExecStart=/usr/sbin/runuser -u atlas-cert -- /var/lib/atlas-cert/renew-qiniu.sh
|
||
TimeoutStartSec=30min
|
||
NoNewPrivileges=true
|
||
PrivateTmp=true
|
||
ProtectHome=true
|
||
UNIT
|
||
|
||
sudo tee /etc/systemd/system/atlas-qiniu-cert-renew.timer > /dev/null <<'UNIT'
|
||
[Unit]
|
||
Description=Daily Atlas Qiniu certificate check
|
||
|
||
[Timer]
|
||
OnCalendar=*-*-* 03:20:00 Asia/Shanghai
|
||
RandomizedDelaySec=30min
|
||
Persistent=true
|
||
Unit=atlas-qiniu-cert-renew.service
|
||
|
||
[Install]
|
||
WantedBy=timers.target
|
||
UNIT
|
||
|
||
sudo systemd-analyze verify \
|
||
/etc/systemd/system/atlas-qiniu-cert-renew.service \
|
||
/etc/systemd/system/atlas-qiniu-cert-renew.timer
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl enable --now atlas-qiniu-cert-renew.timer
|
||
sudo systemctl start atlas-qiniu-cert-renew.service
|
||
sudo systemctl list-timers atlas-qiniu-cert-renew.timer --all
|
||
sudo systemctl show atlas-qiniu-cert-renew.service \
|
||
-p Result -p ExecMainStatus
|
||
sudo journalctl -u atlas-qiniu-cert-renew.service -n 50 --no-pager
|
||
```
|
||
|
||
该基础服务由 root 启动,`ExecStart` 通过 `runuser` 降权执行 acme.sh,维护账号仍没有 sudo 权限。基础服务成功只证明当前续期检查流程完成,不证明网站证书已同步;还须监控 service 失败和两个图片域名实际证书。
|
||
|
||
每天北京时间 03:20 后随机延迟最多 30 分钟执行。每天检查不等于每天重新申请;acme.sh 按证书续期窗口决定是否申请,并更新保存的证书导出路径、调用七牛部署 hook。服务器关机时不会运行,`Persistent=true` 会在恢复后补跑错过的定时检查。
|
||
|
||
**已有宿主机 Nginx 网站的服务器**:先完成第 9.2.2 节验收,再在服务 `[Service]` 中添加 `ExecStartPost=/usr/local/sbin/atlas-cert-install-nginx`,重新执行单元校验、`daemon-reload` 和手工触发 service。**1Panel 现场**:完成第 9.2.1 节的网站及证书同步适配后,才添加对应的部署脚本;不能使用宿主机 Nginx 脚本替代。带 `ExecStartPost` 时,只有前置续期流程成功才执行网站部署,网站部署失败会使整个 service 失败;应同时监控网站证书和任务状态。
|
||
|
||
刚申请的证书显示跳过续期是正常的。`Type=oneshot` 完成后显示 inactive/dead 也是正常的,检查 timer 为 active、任务 `Result=success`、`ExecMainStatus=0`。日志只在受控终端查看,不导出带凭据的调试日志。
|
||
|
||
## 10. 配置通知与独立到期检查
|
||
|
||
### 10.1 配置续期/部署邮件通知
|
||
|
||
在管理账号执行 `sudo -iu atlas-cert`,编辑 `/var/lib/atlas-cert/secrets.env`,追加以下值。示例采用邮箱服务商的 SMTP 465;主机、端口及授权码按实际邮箱说明填写:
|
||
|
||
```bash
|
||
SMTP_BIN='/usr/bin/curl'
|
||
SMTP_HOST='smtp.your-mail-provider.example'
|
||
SMTP_PORT='465'
|
||
SMTP_SECURE='ssl'
|
||
SMTP_USERNAME='cert-bot@example.com'
|
||
SMTP_PASSWORD='替换为SMTP授权码'
|
||
SMTP_FROM='cert-bot@example.com'
|
||
SMTP_TO='ops@joeyone.cn'
|
||
```
|
||
|
||
如使用 587/STARTTLS,改为 `SMTP_PORT='587'`、`SMTP_SECURE='tls'`。在服务器/安全组出站规则中允许对应端口,不使用可能被云平台限制的 25 端口。
|
||
|
||
```bash
|
||
set -a
|
||
. /var/lib/atlas-cert/secrets.env
|
||
set +a
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--set-notify --notify-hook smtp --notify-level 2 --notify-mode 0
|
||
exit
|
||
```
|
||
|
||
这条命令会发送配置测试邮件给 `SMTP_TO`,应确认实际收到。级别 2 用于报告错误和实际续期结果,日常跳过无需每次发信。已有可靠通知渠道时可替换为 acme.sh 支持的 hook,但部署失败必须能通知到维护者。参数见[acme.sh 通知说明](https://github.com/acmesh-official/acme.sh/wiki/notify)及[SMTP hook 实现](https://github.com/acmesh-official/acme.sh/blob/master/notify/smtp.sh)。
|
||
|
||
### 10.2 从网络检查四个域名实际证书
|
||
|
||
本地证书更新成功不等于所有 CDN 节点完成更新。当前两个网站尚未部署,先使用 OpenSSL 检查两个图片域名。应用上线且网站 HTTPS 配置完成后,将循环域名扩展为 `atlas.joeyone.cn dev.atlas.joeyone.cn img.atlas.joeyone.cn img-dev.atlas.joeyone.cn`,再验收四个域名。
|
||
|
||
仅复制代码块内的命令,不复制 Markdown 的三个反引号。若终端显示连续的 `>` 续行提示,先按 `Ctrl+C` 返回正常提示符,再重新粘贴命令。
|
||
|
||
```bash
|
||
set -o pipefail
|
||
for cert_domain in img.atlas.joeyone.cn img-dev.atlas.joeyone.cn; do
|
||
printf '%s\n' "$cert_domain"
|
||
timeout 20 openssl s_client \
|
||
-connect "$cert_domain:443" -servername "$cert_domain" \
|
||
-verify_hostname "$cert_domain" -verify_return_error </dev/null |
|
||
openssl x509 -noout -issuer -dates -fingerprint -sha256
|
||
done
|
||
```
|
||
|
||
四个域名的网络证书指纹应在部署传播完成后与正式 `fullchain.cer` 的叶证书指纹一致。私有图片返回 401/403 不能据此判断 TLS 失败;TLS 握手验证可以独立于图片授权完成。
|
||
|
||
2026-10-03 现场网络检查记录(维护者从服务器执行,检查的具体时刻未提供):
|
||
|
||
| 项目 | 两个图片域名的结果 |
|
||
|---|---|
|
||
| 域名 | `img.atlas.joeyone.cn`、`img-dev.atlas.joeyone.cn` |
|
||
| 颁发者 | `C = US, O = Let's Encrypt, CN = YR2` |
|
||
| 有效期开始 | `2026-10-03 02:09:40 GMT`(北京时间 10:09:40) |
|
||
| 有效期结束 | `2027-01-01 02:09:39 GMT`(北京时间 10:09:39) |
|
||
| SHA-256 指纹 | `E0:EB:B3:0B:A7:3A:B0:12:10:5F:EC:8D:F0:1E:99:F5:0D:09:9C:CA:29:27:BF:8A:B0:4C:74:48:04:44:D0:00` |
|
||
|
||
两域名返回的指纹相同,颁发者和有效期与第 7 节本次正式签发结果一致,确认本次探测到的 CDN 节点已提供正式证书;这不代表所有地区节点都已完成传播,也不代表定时续期任务已验收。
|
||
|
||
同次检查中,`atlas.joeyone.cn` 与 `dev.atlas.joeyone.cn` 返回 `Could not read certificate from <stdin>` / `Unable to load certificate`,表示管道没有获得可解析的证书。由于当时隐藏了 `s_client` 的错误输出,无法仅凭这一结果区分 DNS、连接或 TLS 失败;结合应用尚未部署的现场状态,两个网站暂列待部署后验收,无需重新签发证书。
|
||
|
||
### 10.3 给四个域名分别加独立监控
|
||
|
||
在现有外部监控系统或支持证书检查的云监控产品中,当前先把两个图片域名纳入 TLS 到期监控;网站上线后补齐两个网站域名。同一张证书也可能在某个部署目标更新失败:
|
||
|
||
- 证书剩余不足 21 天告警,不足 7 天升级处理。
|
||
- TLS 握手、证书链或域名匹配失败立即告警。
|
||
- 日常任务长期没有运行,单独按任务执行时间监控。
|
||
- 私有资源 HTTP 探测需使用受控授权;普通无签名 403 不是资源故障。
|
||
|
||
首次手工检查到期阈值可使用以下命令;它只检查当前网络节点,不能代替多地区监控。当前仅检查图片域名,网站上线后再扩展域名列表:
|
||
|
||
```bash
|
||
set -o pipefail
|
||
for cert_domain in img.atlas.joeyone.cn img-dev.atlas.joeyone.cn; do
|
||
if timeout 20 openssl s_client \
|
||
-connect "$cert_domain:443" -servername "$cert_domain" \
|
||
-verify_hostname "$cert_domain" -verify_return_error </dev/null 2>/dev/null |
|
||
openssl x509 -noout -checkend 1814400; then
|
||
printf '%s:当前证书超过21天有效\n' "$cert_domain"
|
||
else
|
||
printf '%s:证书不足21天或TLS检查失败,请处理\n' "$cert_domain" >&2
|
||
fi
|
||
done
|
||
```
|
||
|
||
## 11. 验证私有图片链接和缓存鉴权
|
||
|
||
为每个空间上传一张没有敏感内容的测试 JPEG,例如对象键 `ops/cert-smoke.jpg`。使用浏览器或七牛工具上传即可,保留该测试对象供验收;不要覆盖业务图片。
|
||
|
||
先确认第 10.2 节 TLS 验证通过,再执行图片访问测试。签名 URL、AK/SK 都不直接打印到终端。以下脚本在 `atlas-cert` 会话运行,当前配置假设管理 AK/SK 同时具有这两个空间的私有下载签名能力;若使用了仅能管理证书的凭据,请改用目标空间的授权下载凭据执行本步骤,不扩大证书维护凭据权限。
|
||
|
||
```bash
|
||
set -a
|
||
. /var/lib/atlas-cert/secrets.env
|
||
set +a
|
||
python3 <<'PY'
|
||
import base64
|
||
import hashlib
|
||
import hmac
|
||
import os
|
||
import time
|
||
import urllib.error
|
||
import urllib.parse
|
||
import urllib.request
|
||
|
||
|
||
def status(url):
|
||
try:
|
||
with urllib.request.urlopen(url, timeout=20) as response:
|
||
response.read(1)
|
||
return response.status
|
||
except urllib.error.HTTPError as error:
|
||
return error.code
|
||
except Exception as error:
|
||
# 网络异常可能含完整签名链接,只输出异常类型。
|
||
raise SystemExit(f"网络检查失败:{type(error).__name__}") from None
|
||
|
||
|
||
def signed(base, deadline):
|
||
url = f"{base}?e={deadline}"
|
||
digest = hmac.new(
|
||
os.environ["QINIU_SK"].encode(), url.encode(), hashlib.sha1
|
||
).digest()
|
||
token = base64.urlsafe_b64encode(digest).decode()
|
||
return f"{url}&token={os.environ['QINIU_AK']}:{token}"
|
||
|
||
|
||
for domain in os.environ["QINIU_CDN_DOMAIN"].split():
|
||
base = f"https://{domain}/{urllib.parse.quote('ops/cert-smoke.jpg', safe='/')}"
|
||
unsigned = status(base)
|
||
valid_url = signed(base, int(time.time()) + 30)
|
||
valid = status(valid_url)
|
||
cached_unsigned = status(base)
|
||
# 对同一个已访问链接等待过期,验证缓存命中没有绕过授权。
|
||
time.sleep(32)
|
||
expired = status(valid_url)
|
||
print(f"{domain}: 无签名={unsigned}, 有效签名={valid}, "
|
||
f"缓存后无签名={cached_unsigned}, 过期签名={expired}")
|
||
if not (unsigned in (401, 403) and valid == 200
|
||
and cached_unsigned in (401, 403) and expired in (401, 403)):
|
||
raise SystemExit("私有访问验收未通过,请检查对象和回源鉴权")
|
||
PY
|
||
```
|
||
|
||
预期:有效签名 200,无签名、缓存后无签名和已过期签名均被拒绝。有效链接得到 404 通常表示测试对象未上传到对应空间或对象键不同;得到 403 应检查签名密钥、域名、时钟和访问控制。
|
||
|
||
这个测试只验证你的网络到七牛的访问。还需从另一网络/境外环境核验,最终以测试商品提交后的 Ozon 图片抓取与处理结果验收为准。[七牛私有下载凭证](https://developer.qiniu.com/kodo/1656/download-private)
|
||
|
||
## 12. 与 Atlas 应用配置对接
|
||
|
||
### 12.1 应用配置与维护配置分开
|
||
|
||
证书任务使用 `QINIU_AK` / `QINIU_SK`;应用使用以下既有环境项。两者职责和权限不同,不把证书维护文件放到应用仓库或前端构建环境。
|
||
|
||
以华东浙江区域的生产空间为示例,实际 endpoint 和 S3 空间名从七牛控制台获取:
|
||
|
||
```dotenv
|
||
OBJECT_STORAGE_PROVIDER=qiniu_kodo
|
||
OBJECT_STORAGE_ENDPOINT=https://s3.cn-east-1.qiniucs.com
|
||
OBJECT_STORAGE_REGION=cn-east-1
|
||
OBJECT_STORAGE_BUCKET=atlas-prod-assets
|
||
OBJECT_STORAGE_FORCE_PATH_STYLE=true
|
||
OBJECT_STORAGE_ACCESS_KEY=填写生产对象存储凭据
|
||
OBJECT_STORAGE_SECRET_KEY=填写生产对象存储凭据
|
||
|
||
OZON_IMAGE_DOWNLOAD_ORIGIN=https://img.atlas.joeyone.cn
|
||
OZON_IMAGE_URL_TTL_SECONDS=604800
|
||
QINIU_ACCESS_KEY=填写生产私有下载签名凭据
|
||
QINIU_SECRET_KEY=填写生产私有下载签名凭据
|
||
OZON_PUBLISH_ENABLED=auto
|
||
```
|
||
|
||
开发联调配置替换为开发空间、开发凭据和 `https://img-dev.atlas.joeyone.cn`。`OZON_IMAGE_DOWNLOAD_ORIGIN` 同时用于 API 的图片预览、附件下载和 Worker 向 Ozon 交付图片;七牛私有空间的链接由服务端按用途签发短期下载凭证。上传仍使用 `OBJECT_STORAGE_ENDPOINT`。数据库素材身份继续记录 `storage_provider + bucket + object_key`,不保存签名 URL 作为素材主数据。
|
||
|
||
`OBJECT_STORAGE_BUCKET` 当前用于 S3 操作,因此应填七牛显示的 **S3 空间名**;如它与普通空间名不同,不可混用。自定义 CDN 域名绑定相应的实际空间。[七牛 S3 服务域名说明](https://developer.qiniu.com/kodo/4088/s3-access-domainname)
|
||
|
||
### 12.2 接入校验事项
|
||
|
||
证书配置完成后,还需确认应用与存储空间的联通性:
|
||
|
||
1. API 和 Worker 的 S3 客户端读取 `OBJECT_STORAGE_REGION`;它必须与七牛空间的区域及 endpoint 匹配。API 的七牛预览与附件下载使用绑定的 HTTPS 图片域名签发私有下载链接。
|
||
2. 需验证现有 S3 上传、HEAD/GET、图片域名私有下载和浏览器直传的七牛兼容性;上传 endpoint 的 CORS 要允许实际 Atlas 开发/生产网站 Origin、PUT/GET/HEAD 及预检请求中实际使用的头,不能拿 CDN 配置代替上传 CORS。
|
||
3. 发布代码拒绝 `local_minio` 或与当前 bucket 不一致的素材。原 MinIO 图片需要复制、校验并更新素材定位,或重新导入,不能仅切换配置。
|
||
4. 原有架构文件仍以普通本地开发使用 MinIO 为基线。本手册描述待实施的七牛联调操作,不自行宣布该基线已被替换;正式切换时应同步更新上游架构和交接文档。
|
||
5. 生产 `OZON_PUBLISH_ENABLED=auto` 默认不启用发布。完成七牛延迟抓图及真实店铺其他前置验收后,另行显式启用,不在证书维护步骤中顺便开启生产上架。
|
||
|
||
图片链接默认 7 天是现有应用设置,不是 Ozon 官方有效期保证。CDN 对 `publishing/` 的对象缓存可以存在,但空间生命周期不能提前删除仍在发布/重试/对账中的对象。
|
||
|
||
## 13. 日常维护、换密钥与回滚
|
||
|
||
### 查看任务
|
||
|
||
管理账号执行:
|
||
|
||
```bash
|
||
sudo systemctl list-timers atlas-qiniu-cert-renew.timer --all
|
||
sudo systemctl show atlas-qiniu-cert-renew.service -p Result -p ExecMainStatus
|
||
sudo journalctl -u atlas-qiniu-cert-renew.service --since '2 days ago' --no-pager
|
||
```
|
||
|
||
### 重试部署现有证书
|
||
|
||
如果正式证书已经签发,只有七牛部署失败,不需要再次申请证书:
|
||
|
||
```bash
|
||
sudo -iu atlas-cert
|
||
set -a
|
||
. /var/lib/atlas-cert/secrets.env
|
||
set +a
|
||
flock /var/lib/atlas-cert/renew.lock \
|
||
/var/lib/atlas-cert/.acme.sh/acme.sh \
|
||
--deploy -d "$CERT_MAIN_DOMAIN" --deploy-hook qiniu
|
||
exit
|
||
```
|
||
|
||
七牛重试成功后,运行以下命令也检查/部署 Nginx,不重新申请证书:
|
||
|
||
```bash
|
||
sudo systemctl start atlas-qiniu-cert-renew.service
|
||
```
|
||
|
||
如果导出文件丢失,先在 `atlas-cert` 会话重新执行第 8.3 节的 `--install-cert`。部署之后按第 10.2 节再次检查网络实际证书,七牛配置传播期间部分节点可能仍返回旧证书。
|
||
|
||
### 换 DNS/七牛密钥
|
||
|
||
1. 保留旧密钥,在控制台创建权限正确的新密钥。
|
||
2. 停止 timer,并检查/等待正在运行的 service 完成。
|
||
3. 编辑 `secrets.env`;DNS 凭据还可能缓存为 `account.conf` 中的 `SAVED_Tencent_SecretId` / `SAVED_Tencent_SecretKey`,七牛 hook 凭据缓存于域名配置。部分缓存会优先于新的 shell 环境值,不能只改一个文件就宣告完成轮换。
|
||
4. 在受控编辑器中同步缓存配置或删除旧的对应缓存键,让下次调用重新保存;不要输出整份配置到日志。备份也必须保留 600 权限。
|
||
5. 七牛凭据用上一段的 `--deploy` 验证;DNS 新凭据用独立 staging 配置目录重新做 DNS 验证,正常生产续期时确认保存新值。
|
||
6. 再次启动 timer,确认任务/通知和网络证书正常后,禁用并删除旧密钥。
|
||
|
||
```bash
|
||
sudo systemctl stop atlas-qiniu-cert-renew.timer
|
||
sudo systemctl is-active atlas-qiniu-cert-renew.service
|
||
```
|
||
|
||
如果 service 正在执行,先等待完成,不同时手工改凭据。轮换结束:
|
||
|
||
```bash
|
||
sudo systemctl start atlas-qiniu-cert-renew.timer
|
||
```
|
||
|
||
### 回滚
|
||
|
||
保留原有效证书及七牛证书 ID、Nginx 旧版本目录,直到新证书在四个域名、多网络测试均通过。发生新证书部署问题时,可暂停 timer,在七牛控制台将受影响域名重新绑定原有效证书;确认网络实际证书后排查。Nginx 需要回滚时,由管理账号将 `/etc/nginx/tls/atlas/current` 链接恢复到原有效版本,执行 `nginx -t` 后重载,并重新核验网站证书;同步移除 `deployed-fingerprint`,修复后才恢复定时任务,避免记录与实际部署不一致。原证书已经过期时不能回滚到它,应部署新正式证书。
|
||
|
||
### 备份与迁移维护服务器
|
||
|
||
加密备份整个 `/var/lib/atlas-cert`(含 ACME 账号、证书、私钥、缓存凭据)、`/etc/nginx/tls/atlas`、root 部署脚本、两个网站的 Nginx 配置和两个 systemd 单元,限制备份读取权限。换机器时先在旧机停 timer,恢复目录与账号权限,再在新机部署单元和做一次续期检查、证书部署/网络检查,避免两台机器同时操作同一证书。
|
||
|
||
## 14. 常见故障
|
||
|
||
| 现象 | 优先检查 | 处理 |
|
||
|---|---|---|
|
||
| DNS 验证失败 / 找不到根域 | 实际 NS、DNSPod 账号归属、四个操作权限 | 确认正确插件和域名级资源;不要扩大到主账号权限 |
|
||
| `Tencent_SecretId` 未配置 | 变量大小写、配置文件权限、systemd 用户 | 确认环境文件已加载,不使用 `DP_Id` 代替 |
|
||
| TXT 验证超时 | DNS 传播、权威 DNS、DNSSEC、CAA、出站网络 | staging 中排查,再申请正式证书 |
|
||
| 七牛 `no such domain` / 612 | 域名是否存在于该 AK 所属 CDN 账号、是否用了源站域名、前导点 | 填准确 CDN 域名,移除前导点,不填写 URL |
|
||
| 首次更新 HTTPS 失败 | 两个域名是否均已开启 HTTPS | 先完成控制台首次绑定,再部署 hook |
|
||
| 证书已上传但图片域名仍旧证书 | 两域名绑定、配置传播、当前 CDN 节点 | 检查两个域名而非只看证书列表,等待传播并多网络核验 |
|
||
| TLS 正常但图片 401/403 | 链接过期、签名、服务器时间、Referer/IP/UA 限制 | 检查图片授权,不重新申请 HTTPS 证书 |
|
||
| 已过期链接仍能下载 | 私有回源鉴权和缓存命中路径 | 修正鉴权,重跑第 11 节,不改 bucket 为公开 |
|
||
| 网站仍返回旧证书 | Nginx 导出目录、部署脚本、`nginx -t`、service 状态 | 修复导出/配置后重跑 service,核验两个网站证书 |
|
||
| 本地证书新、七牛证书旧 | hook 调用失败、AK 权限、目标域名列表 | 重试 `--deploy`,不强制重复签发 |
|
||
| systemd 执行后 inactive | oneshot 已正常结束 | 看 timer、Result 和退出码 |
|
||
| 没收到邮件 | SMTP 授权码、From、端口出站、收件箱 | 重做通知配置测试,检查邮箱服务商要求 |
|
||
| 图片签名链接 404 | 对象是否在正确空间、key 编码、是否被提前清理 | 检查对象身份和保留策略 |
|
||
| 应用 S3 访问失败 | region、endpoint、S3 空间名、对象权限 | 按第 12 节核对应用配置和存储空间权限 |
|
||
|
||
排错时只提供脱敏后的错误码、域名、时间和请求 ID;不提供 SK、证书私钥、完整授权 URL 或完整账号配置文件。
|
||
|
||
## 15. DNS 不在 DNSPod、或需要其他证书形式
|
||
|
||
### DNS 托管商不同
|
||
|
||
腾讯云服务器可以使用任意受支持 DNS 服务商的 API。仅替换第 5 节凭据和第 6~7 节的 `--dns` 插件,七牛部署和 systemd 流程不变:
|
||
|
||
| DNS 实际托管商 | acme.sh 插件 | 凭据说明 |
|
||
|---|---|---|
|
||
| 腾讯云 DNSPod 新版 API | `dns_tencent` | `Tencent_SecretId`、`Tencent_SecretKey` |
|
||
| DNSPod 旧版 API | `dns_dp` | `DP_Id`、`DP_Key`;不是腾讯云 SecretId/SecretKey |
|
||
| 阿里云 DNS | `dns_ali` | 按该插件文档配置对应凭据 |
|
||
| Cloudflare DNS | `dns_cf` | 按该插件文档使用限定 DNS 权限的 API token |
|
||
|
||
不要仅因为服务器在腾讯云就迁移域名 DNS。其他插件的最新变量名和权限参考 [acme.sh DNS API 指南](https://github.com/acmesh-official/acme.sh/wiki/dnsapi)及 [DNS API 指南第二部分](https://github.com/acmesh-official/acme.sh/wiki/dnsapi2)。
|
||
|
||
### 扩展 Atlas 域名时保持同一层级
|
||
|
||
主流程已使用 `atlas.joeyone.cn` + `*.atlas.joeyone.cn`。未来增加 `api.atlas.joeyone.cn`、`staging.atlas.joeyone.cn` 或 `img-staging.atlas.joeyone.cn`,证书覆盖范围无需改变,但仍要配置 DNS、对应服务以及证书部署。新增图片域名还要绑定独立环境空间,并加入 `QINIU_CDN_DOMAIN` 和监控列表。
|
||
|
||
若使用 `img.dev.atlas.joeyone.cn` 等更深层域名,需要额外 SAN 或新的通配符,不适合当前四域名共用一张证书的命名目标。`--deploy -d`、`--install-cert -d` 始终使用证书主域名 `atlas.joeyone.cn`,不能拿某个图片域名当证书身份。
|
||
|
||
### 开发生产使用不同七牛账号
|
||
|
||
需要每账号独立配置目录、凭据和部署任务,分别申请/维护证书更容易管理权限。本手册集中任务适用于同一七牛账号下、由同一维护者管理的两个域名;不把共享证书当作共享存储权限的理由。
|
||
|
||
## 16. 完成验收清单
|
||
|
||
- [ ] 两个空间都是私有,生产与开发数据/应用凭据隔离。
|
||
- [ ] 两个下载域名是七牛 CDN 域名,分别指向正确空间,CNAME 已生效。
|
||
- [ ] 两个域名均启用私有空间回源鉴权,未添加与现有签名协议冲突的限制。
|
||
- [x] DNS-01 staging 验证及测试证书签发成功(2026-10-03)。
|
||
- [ ] 临时 TXT 已清理,两个图片域名 CNAME 保持正确。
|
||
- [x] 正式 SAN 含 `atlas.joeyone.cn` 与 `*.atlas.joeyone.cn`,覆盖四个域名;颁发者及有效期已检查(2026-10-03)。
|
||
- [ ] 两个网站 A 记录正确,Nginx 分别路由到对应环境,证书导出、配置检查和重载成功。
|
||
- [x] 七牛 hook 首次部署对两个图片域名均返回成功(2026-10-03 11:26:12,北京时间)。
|
||
- [x] 两个图片域名的实际网络证书已核验更新(2026-10-03,当前探测节点的颁发者及有效期与本次正式证书一致,两个域名指纹相同)。
|
||
- [ ] systemd timer 启用,手工触发 service 成功,七牛及 Nginx 均完成部署;没有另一个 cron/服务器并发维护。
|
||
- [ ] 当前 1Panel 阶段:先启用仅续期、七牛部署及 PEM 导出的基础 timer,手工触发成功;应用上线后补齐网站同步,再验收上一项完整链路。
|
||
- [ ] 故障/实际续期通知已收到测试消息,四个域名已纳入独立到期监控。
|
||
- [ ] 两空间测试图片均通过有效签名、无签名、缓存后无签名、过期签名测试。
|
||
- [ ] 权限受控的加密备份和旧有效证书回滚方式已准备。
|
||
- [ ] 应用 S3 region、上传与图片域名的私有下载均已验证,未把证书部署成功当作 Ozon 上架验收成功。
|
||
|
||
## 17. 项目与官方参考
|
||
|
||
- [项目对象存储概念与身份边界](./object-storage-object-key.md)
|
||
- [项目技术栈与环境边界](../architecture/technology-and-deployment.md)
|
||
- [七牛 SSL FAQ:证书 API 与源站域名限制](https://developer.qiniu.com/fusion/kb/3905/ssl-certificate-faq?category=kb)
|
||
- [七牛私有空间 CDN 回源鉴权](https://developer.qiniu.com/fusion/3930/back-to-the-source-authentication)
|
||
- [七牛私有下载 URL](https://developer.qiniu.com/kodo/1656/download-private)
|
||
- [腾讯云子账号 API 密钥管理](https://cloud.tencent.com/document/product/598/37140)
|
||
- [腾讯云 DNSPod 可授权资源类型](https://cloud.tencent.com/document/product/302/105719)
|
||
- [acme.sh 3.1.6 发行说明](https://github.com/acmesh-official/acme.sh/releases/tag/3.1.6)
|
||
- [Nginx HTTPS 配置](https://nginx.org/en/docs/http/configuring_https_servers.html)
|
||
- [DNSPod 泛解析与明确记录匹配](https://cloud.tencent.com/document/product/302/9073)
|
||
- [acme.sh 项目与安装说明](https://github.com/acmesh-official/acme.sh)
|
||
- [Let's Encrypt DNS-01 验证](https://letsencrypt.org/docs/challenge-types/)
|
||
|
||
云平台界面和接口可能调整;操作时以实际控制台和上列官方文档为准。本文脚本需在你的真实账号做首次验收,不能仅靠复制成功就认为完成续期闭环。
|