Aliyun OSS 静态站点自动化 HTTPS 证书续期 链接到标题
背景 链接到标题
阿里云免费 SSL 证书配额耗尽,无法通过 API 申请新证书。OSS 自定义域名的 HTTPS 证书绑定只能通过控制台手动操作,无法自动化。
目标:实现免费证书的全自动管理,包括申请、续期和部署。
架构 链接到标题
客户端 → DNS(CNAME) → 阿里云 CDN(HTTPS 终止) → OSS 源站
↑
部署节点 certbot
cert.pem → SetCdnDomainSSLCertificate
流量路径:
- 用户访问
https://www.example.com - DNS 解析到 CDN CNAME(
www.example.com.w.kunlunaq.com) - CDN 边缘节点处理 HTTPS,证书由
SetCdnDomainSSLCertificate管理 - CDN 回源到 OSS bucket(
example-bucket.oss-cn-beijing.aliyuncs.com)
关键发现:www.example.com 在阿里云系统中已是 CDN 域名,只是 DNS CNAME 未指向 CDN,导致流量直连 OSS 绕过 CDN。
实施步骤 链接到标题
环境准备 链接到标题
- 部署节点:Ubuntu 22.04,有公网访问
- 安装 aliyun CLI(v3.4.10)
- 安装 certbot(snap 安装,v5.7.0)
- 配置 aliyun CLI 凭据(AccessKey 需 AlidnsFullAccess 权限)
三个脚本 链接到标题
1. certbot-auth.sh — DNS-01 验证时添加 TXT 记录
#!/bin/bash
source /home/ecs-user/traefik/.env
aliyun alidns AddDomainRecord \
--DomainName example.com \
--RR _acme-challenge.www \
--Type TXT \
--Value "$CERTBOT_VALIDATION" \
--TTL 600
sleep 120
注意事项:
- 阿里云 DNS 最小 TTL 为 600 秒,不能设更低
- sleep 120 秒等待 DNS propagation(实际效果取决于 DNS 服务商刷新速度)
2. certbot-cleanup.sh — 验证后清理 TXT 记录
#!/bin/bash
source /home/ecs-user/traefik/.env
RECORD_ID=$(aliyun alidns DescribeDomainRecords \
--DomainName example.com \
--RRKeyWord _acme-challenge.www \
--TypeKeyWord TXT \
--ValueKeyWord "$CERTBOT_VALIDATION" 2>/dev/null | \
python3 -c 'import json,sys; d=json.load(sys.stdin); rs=d.get("DomainRecords",{}).get("Record",[]); print(rs[0]["RecordId"] if rs else "")')
if [[ -n "$RECORD_ID" ]]; then
aliyun alidns DeleteDomainRecord --RecordId "$RECORD_ID"
fi
3. certbot-deploy.sh — 证书续期后部署到 CDN
#!/bin/bash
if [[ "$RENEWED_DOMAINS" == *"www.example.com"* ]]; then
source /home/ecs-user/traefik/.env
aliyun cdn SetCdnDomainSSLCertificate \
--DomainName www.example.com \
--SSLProtocol on \
--CertType upload \
--SSLPub "$(cat "$RENEWED_LINEAGE/fullchain.pem")" \
--SSLPri "$(cat "$RENEWED_LINEAGE/privkey.pem")" \
--CertName "example-le-$(date +%Y%m%d)"
fi
首次签发 链接到标题
sudo certbot certonly \
--authenticator manual \
--preferred-challenges dns \
--manual-auth-hook /usr/local/bin/certbot-auth.sh \
--manual-cleanup-hook /usr/local/bin/certbot-cleanup.sh \
--deploy-hook /usr/local/bin/certbot-deploy.sh \
-d www.example.com \
--email user@example.com \
--agree-tos --no-eff-email
证书存放于 /etc/letsencrypt/live/www.example.com/,有效期为 90 天。
DNS 切换 链接到标题
将 www.example.com 的 CNAME 从 OSS 域名改为 CDN CNAME:
aliyun alidns DeleteDomainRecord --RecordId <旧记录ID>
aliyun alidns AddDomainRecord \
--DomainName example.com \
--RR www \
--Type CNAME \
--Value "www.example.com.w.kunlunaq.com" \
--TTL 600
切换后约 5-10 分钟生效(TTL 600 秒)。
自动续期 链接到标题
Certbot snap 包自带 systemd timer,每天自动检查续期:
systemctl list-timers | grep certbot
# snap.certbot.renew.timer
续期流程:
- 添加
_acme-challenge.wwwTXT 记录 - Let’s Encrypt 验证
- 清理 TXT 记录
- 调用
SetCdnDomainSSLCertificate更新 CDN 证书
无需额外 cron 配置,certbot 会自动处理。
验证 链接到标题
# 查看证书
sudo openssl x509 -in /etc/letsencrypt/live/www.example.com/cert.pem -noout -subject -issuer -dates
# 验证 HTTPS
curl -I https://www.example.com
echo | openssl s_client -connect www.example.com:443 -servername www.example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates
问题排查 链接到标题
| 问题 | 原因 | 解决 |
|---|---|---|
| region can’t be empty | certbot hook 以 root 运行,但 aliyun CLI 配置在用户目录 | 将配置复制到 /root/.aliyun/ 或在 hook 中 source 用户凭据 |
| QuotaExceeded.TTL | DNS TTL 设得太低(<600) | TTL 改为 600 或更高 |
| InvalidParameter Value | TXT 记录值格式问题 | 检查引号转义,确保值正确传递 |
| too many failed authorizations | Let’s Encrypt 每小时限 5 次失败 | 等待 1 小时后重试 |
| SERVFAIL | DNS 未及时刷新 | 增加 sleep 时间或检查 DNS 服务商 |