使用 ddns-go 与 acme.sh 实现群晖 NAS 动态解析与 SSL 证书全自动续期部署
前言:架构分工与避坑认知
在家庭宽带环境下通过公网安全访问 NAS,必须由两个核心组件协同工作:
flowchart LR
subgraph Access["外网访问"]
Client["外网访客 / 客户端"]
end
subgraph Cloud["云端托管"]
CF["Cloudflare DNS<br/>(权威解析)"]
end
subgraph Synology["群晖 NAS (家庭宽带)"]
direction TB
DDNS["ddns-go (动态解析)"]
NAS["群晖 NAS (Nginx 反代)"]
ACME["acme.sh (证书自动化)"]
end
Client -->|"1. 查询解析"| CF
Client ==>|"2. HTTPS 直连"| NAS
DDNS -->|"实时同步 IP"| CF
ACME -->|"DNS-01 验证"| CF
ACME ==>|"3. 部署证书"| NASddns-go(动态域名解析):家庭宽带公网 IP 是动态变化的。ddns-go负责实时探测本地公网 IP 并同步更新 Cloudflare DNS 记录,保证域名始终指向正确的家宽地址。acme.sh(SSL 证书自动化):负责通过 DNS API 自动申请公网受信任的 Let’s Encrypt 泛域名证书,保证数据传输加密且浏览器不报安全警告。
常见大坑:为什么 Cloudflare Origin 证书会报“不安全”?
Cloudflare 控制台生成的 15 年期 Origin CA 证书 仅供 Cloudflare 边缘节点到源站之间加密(需开启橙色小云朵 CDN 代理)。
- 如果你的访问带了自定义高位端口(例如
50001等非 Cloudflare 免费 CDN 支持的端口),流量是直连 NAS 的; - 此时浏览器直接与 NAS 握手,收到不受信任的 Origin 证书就会立刻弹出 “您的连接不是私密连接 / 证书不受信任” 的警告;
- 正解:直连必须使用 Let’s Encrypt 或 ZeroSSL 签发的公网证书。
1. 准备条件与获取 Cloudflare API Token
1.1 准备条件
- 自己的域名已托管在 Cloudflare(例如
yourdomain.com)。 - 家庭宽带具备公网 IPv4 或 IPv6,路由器已做好端口映射(NAT)。
- 群晖开启 SSH 终端功能。
1.2 创建 Cloudflare API Token
为了让 ddns-go 和 acme.sh 能够自动修改 DNS 记录:
- 登录 Cloudflare 控制台。
- 点击右上角头像 -> 我的个人资料 -> API 令牌 -> 创建令牌。
- 选择 编辑区域 DNS (Edit zone DNS) 模板。
- 权限确认包含:
区域 - DNS - 编辑区域 - 区域 - 读取
- 资源范围选择目标域名(例如
yourdomain.com)。 - 生成后妥善复制保存该 Token。
2. 第一步:部署 ddns-go 实现动态解析
推荐使用 Docker(Container Manager)快速部署 ddns-go:
1 | docker run -d \ |
配置 ddns-go
- 浏览器打开
http://<NAS局域网IP>:9876。 - DNS 服务商选择 Cloudflare,填入刚刚生成的 API Token。
- 在 IPv4 / IPv6 域名配置处填写你要解析的二级域名,例如:
1
nas.yourdomain.com
- 点击保存,观察日志提示
[Cloudflare] 添加/更新成功即可。此时域名解析已打通。
3. 第二步:环境配置与安装 acme.sh
通过 SSH 登录群晖,进行 acme.sh 的安装与初始化。
3.1 一键安装(避坑:无 crontab 报错)
群晖默认普通用户没有 crontab,直接安装可能会提示 Pre-check failed。需追加 --force 参数:
1 | curl https://get.acme.sh | sh -s email=your@example.com --force |
3.2 切换默认 CA 机构为 Let’s Encrypt
acme.sh 默认使用 ZeroSSL,国内网络连接其 API 容易出现 curl error code: 7 超时。推荐切换为连通性更好的 Let’s Encrypt:
1 | ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt |
4. 第三步:申请 Let’s Encrypt 泛域名证书
导入 Cloudflare API Token,并发起申请(同时覆盖根域名和全部二级泛域名):
1 | # 导入 API Token (临时环境变量,脚本会自动持久化到配置中) |
[!NOTE]
脚本会自动调用 Cloudflare API 创建两条_acme-challengeTXT 记录,等待 20~60 秒 DNS 生效后完成验证,验证通过后自动删除临时 TXT 记录。最后输出Cert success即表示证书申请成功!
5. 第四步:全自动续期与部署(群晖任务计划零凭据方案)
很多教程推荐使用管理员账号的 API Deploy Hook,但这存在在配置文件中明文暴露管理员密码的安全隐患。
更推荐的方案是:利用群晖任务计划的原生 root 权限,在本地执行自动更新、文件覆盖与 Nginx 重载。
5.1 创建自动部署脚本
在群晖上创建自动化脚本 /var/services/homes/你的用户名/.acme.sh/renew_and_deploy.sh:
1 |
|
赋予脚本执行权限:
1 | chmod +x ~/.acme.sh/renew_and_deploy.sh |
5.2 首次手动导入证书(建立关联)
首次需要先在 DSM 控制面板建立映射关系:
- 打开群晖 【控制面板】 -> 【安全性】 -> 【证书】。
- 点击 【新增】 -> 【添加新证书】 -> 【导入证书】,勾选 【设为默认证书】:
- 私钥:上传
ssl_certs/privkey.pem - 证书:上传
ssl_certs/cert.pem - 中间证书:上传
ssl_certs/chain.pem
- 私钥:上传
- 点击 【设置】,将系统默认以及各个反向代理服务(如 Vaultwarden / DSM)全部选为此证书。
5.3 在群晖「任务计划」中添加定时任务
- 打开群晖 【控制面板】 -> 【任务计划】。
- 【新增】 -> 【计划的任务】 -> 【用户定义的脚本】:
- 常规设置:任务名称填
Auto_Renew_SSL,用户账号必须选择root。 - 排程:设置为每周运行一次或每月 1 日运行。
- 任务设置 -> 用户定义的脚本:
1
bash /var/services/homes/你的用户名/.acme.sh/renew_and_deploy.sh
- 常规设置:任务名称填
- 点击确定保存。从此每当证书快到期时,脚本会自动续期、覆写群晖系统证书并平滑重载 Nginx,再也无需人工干预!
6. 常见问题 (Q&A)
Q1: 既然申请了泛域名证书,ddns-go 是不是可以关掉了?
解答:绝对不能关!
ddns-go负责把变动的宽带 IP 告诉 Cloudflare(指路);acme.sh负责让连接具备合法加密证书(通行证)。两者各司其职,缺一不可。
Q2: 为什么以后泛域名下的新子域名不用重新申请证书?
解答:因为申请时包含了
*.yourdomain.com。未来只要在群晖反向代理或 Docker 里新增任何二级子域名服务(如photos.yourdomain.com、vault.yourdomain.com),直接复用该证书即可,立即可用。
Q3: 证书到期前多久会自动续订?
解答:Let’s Encrypt 证书有效期为 90 天。
acme.sh默认会在证书到期前 30 天内自动触发续签流程,保证证书永久处于有效状态。