Cdn该怎么套?我来教你
自建 CDN 完整配置指南
💡 核心结论:自建 CDN 套域名并启用 HTTPS,完整链路是——添加站点 → 配置 CNAME 解析 → 申请 SSL 证书 → 部署证书 → 配置强制跳转 → 按需开启 HSTS → 建立刷新预热机制。自建 CDN 和商用 CDN 最大的区别在于:证书要自己申请、缓存要自己管、回源要自己配,没有一键托管。
📋前置准备
自建 CDN 的系统构成
自建 CDN 通常由三部分组成:边缘节点(运行 Nginx / OpenResty / Varnish + 缓存模块)、调度系统(DNS 智能解析或 Anycast)、源站(你的博客服务器)。你需要自己维护边缘节点的缓存策略、证书和回源配置。
域名与备案
使用国外边缘节点不需要 ICP 备案。DNS 解析托管到 Cloudflare、DNSPod 或自建 DNS 都可以。如果是国内节点,加速域名必须完成 ICP 备案。
证书来源选择
| 方案 | 免费额度 | 有效期 | 泛域名 | 管理方式 |
|---|---|---|---|---|
| Let's Encrypt 推荐 | 无限制 | 90 天 | ✅ 支持 | 命令行(acme.sh) |
| ZeroSSL | 每账号 3 张 | 90 天 | ❌ 免费版不支持 | 图形界面 + API |
| Buypass | 免费 | 180 天 | 不支持 | 命令行 / API |
| 商业证书 | 付费 | 1 年 | 取决于类型 | 控制台 |
📌 自建 CDN 推荐方案:用 Let's Encrypt + acme.sh 申请泛域名证书,配合 --install-cert 钩子自动部署到所有边缘节点。免费、自动续期、支持泛域名,是自建 CDN 的最优解。
1添加站点 / 加速域名
在自建 CDN 的管理面板中添加站点。不同面板(如 Nginx Proxy Manager、宝塔 CDN 插件、自研面板)叫法不同,核心是配置加速域名和源站地址。
加速域名填什么
建议单独分配一个二级域名承载 CDN 加速,如 cdn.yourdomain.com 或 static.yourdomain.com,主域名留给业务入口。好处是隔离风险,CDN 出问题时不会波及主站。
源站配置
源站是单台服务器填 IP,负载均衡架构填域名更灵活。回源协议初期可选 HTTP,后续改为 HTTPS 实现全链路加密。
格式类似 cdn.yourdomain.com.edge-node-01.yourcdn.com。如果是自建 DNS 调度,可能直接是一个 A 记录指向边缘节点 IP。这是下一步解析的关键。
2申请 SSL 证书
Let's Encrypt(acme.sh 方案)自建 CDN 首选
安装 acme.sh 一条命令:
curl https://get.acme.sh | sh -s email=你的邮箱@example.com
用 DNS 验证方式签发泛域名证书(以 Cloudflare DNS 为例):
export CF_Token="你的Cloudflare_API_Token"
export CF_Account_ID="你的Cloudflare_Account_ID"
acme.sh --issue --dns dns_cf -d yourdomain.com -d *.yourdomain.com
📌 为什么自建 CDN 推荐 DNS 验证?DNS 验证不需要边缘节点开放 80 端口,证书签发在本地完成后再分发到各节点。对于多节点自建 CDN,这是唯一可行的方式。
证书文件位置:申请成功后,证书在 ~/.acme.sh/yourdomain.com/ 目录下。部署到边缘节点时需要的是:
fullchain.cer——包含服务器证书和中间证书的完整链yourdomain.com.key——私钥文件
自动部署到边缘节点
用 acme.sh 的 --install-cert 钩子,证书续期后自动复制到 Nginx 目录并重载:
acme.sh --install-cert -d yourdomain.com \
--key-file /etc/nginx/ssl/yourdomain.com.key \
--fullchain-file /etc/nginx/ssl/yourdomain.com.fullchain.cer \
--reloadcmd "nginx -s reload"
如果有多个边缘节点,可以配合 Ansible / rsync 批量分发证书文件。
ZeroSSL
访问 zerossl.com,输入域名,注册账号后按引导完成验证。支持文件验证、DNS 验证、邮箱验证三种方式。
⚠️ ZeroSSL 免费版限制:每个账号限 3 张免费证书,且不包含泛域名。自建 CDN 通常需要泛域名证书来覆盖多个子域名,所以更推荐 Let's Encrypt。
3配置 CNAME 解析
进入 DNS 解析控制台(Cloudflare、DNSPod 或自建 DNS),添加一条 CNAME 记录:
- 主机记录:加速
cdn.yourdomain.com就填cdn;加速主域名填@ - 记录类型:选择
CNAME - 记录值:粘贴 CDN 分配的 CNAME 地址
- TTL:保持默认
🚫 关键注意:CNAME 记录不能与 A 记录共存。如果之前给该主机记录配置过 A 记录指向服务器 IP,必须先删除 A 记录,否则解析冲突,CDN 不生效。这是自建 CDN 新手最常踩的坑。
验证是否生效:
dig cdn.yourdomain.com CNAME +short
4部署 SSL 证书到边缘节点
自建 CDN 没有「一键上传证书」的按钮,你需要手动把证书文件放到每个边缘节点,并在 Nginx / OpenResty 配置中引用。
Nginx 配置示例
server {
listen 443 ssl http2;
server_name cdn.yourdomain.com;
ssl_certificate /etc/nginx/ssl/yourdomain.com.fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/yourdomain.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
proxy_pass http://源站IP:端口;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
最容易踩的坑:证书链不完整
很多「HTTPS 配置看起来成功了,浏览器却报不安全」的问题,根源都在这里。
SSL 证书通常包含服务器证书、中间证书、根证书组成的证书链。如果只配置了服务器证书,浏览器可能无法验证证书来源,Chrome 会直接阻断访问。
Nginx 的 ssl_certificate 指令指向的文件必须包含服务器证书和中间证书。用 acme.sh 时,fullchain.cer 就是完整链版本,直接用。不要用 cert.pem(只有服务器证书)。
验证证书链是否完整:
openssl s_client -connect cdn.yourdomain.com:443 -servername cdn.yourdomain.com
如果输出中 Verify return code 为 0 (ok),说明链完整。如果是 21 (unable to verify the first certificate),说明缺中间证书。
5强制跳转 HTTPS
这是最容易忽视但必须配置的一步。
配置 SSL 证书只是让 Nginx 具备处理 HTTPS 请求的能力,不会改变 HTTP 请求的处理方式。HTTP 到 HTTPS 的跳转需要单独配置。
Nginx 配置示例
server {
listen 80;
server_name cdn.yourdomain.com;
return 301 https://$host$request_uri;
}
🚫 重定向死循环:最容易踩的坑。如果开启强制跳转后访问报 ERR_TOO_MANY_REDIRECTS,通常是因为:源站也配置了 HTTP 到 HTTPS 跳转,但 CDN 以 HTTP 协议回源。此时 CDN 收到 HTTP 请求 → 跳转到 HTTPS → 回源时仍用 HTTP → 源站又要求跳转到 HTTPS → 循环。
解决方案(二选一)
- 方案一:关闭源站的 HTTP 强制跳转功能,统一由 CDN 处理跳转
- 方案二:修改 CDN 回源协议为 HTTPS 或 跟随请求协议,避免触发源站跳转
📌 自建 CDN 推荐方案二。回源协议设为 HTTPS,源站也配好证书,实现「用户到 CDN」和「CDN 到源站」全程加密。同时源站可以保留强制跳转作为兜底。
6HSTS 安全访问(进阶,慎开)
HSTS 是什么
HSTS(HTTP Strict Transport Security)是一种安全策略,开启后浏览器会缓存一个响应头,在缓存有效期内自动将所有 HTTP 请求转为 HTTPS,不再经过 HTTP 跳转这一步。
HSTS 与强制跳转的区别
强制跳转是服务端处理:浏览器发 HTTP → 服务器返回 301 → 浏览器再发 HTTPS。第一次 HTTP 请求仍然在网络上传输,有被劫持的风险。
HSTS是浏览器侧处理:浏览器发现请求是 HTTP → 浏览器直接转为 HTTPS 发出。HTTP 请求根本没有出现在网络上,彻底消除降级攻击风险。
Nginx 配置示例
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
🚫 HSTS 的致命风险(开之前必读):HSTS 配置后无法快速回退。HSTS 策略作用在客户端(浏览器),关闭 HSTS 后无法立即生效,需要用户手动刷新浏览器缓存。这意味着:如果开启 HSTS 后证书出了问题(过期、被吊销、配置错误),所有已经缓存过 HSTS 响应的用户将完全无法访问你的网站,浏览器会直接阻止连接,连“继续访问”的选项都不给。
必须遵守的规则
- 开启 HSTS 前,确保证书配置稳定且自动续期正常工作
- 不要为了测试而随便开启 HSTS
- 如果开启 HSTS 后关闭了 HTTPS 证书,必须同时关闭 HSTS 配置
- 过期时间不要设太长,初期建议
max-age=86400(1 天),确认稳定后再逐步延长到 31536000(1 年) - 强制跳转类型不能设为 HTTP,否则与 HSTS 冲突,会导致域名无法访问
⚠️ 自建 CDN 特别提醒:HSTS 头由边缘节点返回。如果你有多个边缘节点,必须确保所有节点都配置了相同的 HSTS 策略,否则用户在不同节点间切换时会遇到不一致的行为。
7缓存刷新与预热
核心概念
刷新(Refresh/Purge):向 CDN 节点下发缓存失效指令,将已缓存的资源标记为过期。用户再次请求时,CDN 回源获取最新资源并重新缓存。刷新会降低缓存命中率。
预热(Preload/Warm-up):CDN 节点主动从源站拉取资源并缓存。用户首次请求时可直接从 CDN 获取,无需回源。预热会提高缓存命中率。
什么时候用哪个
| 场景 | 操作 |
|---|---|
| 博客更新了文章,想让读者立即看到新内容 | 刷新对应文章 URL |
| 删除了违规/错误内容 | 刷新对应 URL |
| 首次接入 CDN,想加速热门文章 | 预热热门文章 URL |
| 发布大型资源(视频、安装包) | 预热,降低源站压力 |
| 更换了主题/静态资源 | 先刷新,再预热 |
自建 CDN 如何实现刷新预热
Nginx 缓存刷新
如果边缘节点用 Nginx 的 proxy_cache,刷新就是删除对应的缓存文件:
# 查找缓存文件
find /var/cache/nginx -type f -name "*yourdomain.com*"
# 删除指定缓存(按 URL 匹配)
grep -rl "cdn.yourdomain.com/article/123" /var/cache/nginx | xargs rm -f
# 重载 Nginx
nginx -s reload
OpenResty / Lua 缓存刷新
如果边缘节点用 OpenResty + lua-resty-cache,可以通过 ngx.shared.DICT 或 Redis 管理缓存键,提供 HTTP API 触发刷新:
# 通过 API 刷新单个 URL
curl -X POST "http://edge-node-01:8080/purge" \
-d "url=https://cdn.yourdomain.com/article/123"
预热实现
预热本质是主动发起请求让 CDN 回源并缓存。可以用脚本批量发起:
# 批量预热热门文章
for url in $(cat hot-urls.txt); do
curl -s -o /dev/null -w "%{http_code} %{url_effective}\n" "$url"
done
⚠️ 刷新预热的注意事项:
1. 大批量刷新会冲击源站。刷新后大量请求同时回源,源站带宽会突增。建议在流量低峰期操作。
2. 预热也是同理。大批量预热任务会让 CDN 节点同时回源拉取,源站带宽压力增大。根据源站带宽情况控制并发。
3. 刷新不是删除,是标记失效。CDN 不会实时删除缓存文件,只是标记为“过期”,用户下次请求时才回源获取新内容。
4. 如果缓存过期时间 < 5 分钟,不需要手动刷新。等它自然过期即可。
5. HTTP 和 HTTPS 共享缓存。只需要刷新或预热其中一种协议,不必两个都做。
自动化刷新预热
手动刷新适合低频场景。如果博客更新频繁,可以配置自动化:
- Git Hook 触发:博客部署完成后,通过 webhook 调用刷新 API
- CI/CD 集成:在 GitHub Actions / GitLab CI 中加入刷新步骤
- 定时任务:用 cron 定期预热热门文章
- 对象存储触发:文件上传到 OSS/COS 时自动触发刷新
8验证与排查
验证清单
- HTTPS 访问:用
https://cdn.yourdomain.com访问,地址栏显示安全锁 - 证书信息:点击锁图标,确认 CA 为 Let's Encrypt、在有效期内、域名匹配
- HTTP 跳转:用
http://cdn.yourdomain.com访问,应自动跳转到 HTTPS - CNAME 生效:
dig cdn.yourdomain.com CNAME +short返回 CDN 地址 - 混合内容:浏览器控制台无
Mixed Content警告 - 缓存验证:更新资源后,刷新 CDN,确认用户能获取最新内容
常见故障速查表
| 现象 | 大概率原因 |
|---|---|
| 浏览器标「不安全」但页面能打开 | 证书链不完整或未开强制跳转 |
ERR_TOO_MANY_REDIRECTS |
源站也配了强制跳转 + CDN 以 HTTP 回源 |
| 页面图片/样式加载失败 | 混合内容被浏览器阻止 |
| CNAME 配置后 CDN 不生效 | A 记录与 CNAME 冲突,需删除 A 记录 |
| 回源报 502 | CDN 回源协议设为 HTTPS 但源站不支持 |
| 裸域名证书报错 | 用了通配符证书但没单独配置裸域名 |
| 证书申请后 CDN 不识别 | 配置了不含中间证书的 cert.pem 而非 fullchain.pem |
| 用户看到旧内容 | 缓存未过期且未刷新,或刷新未生效 |
| HSTS 开启后网站打不开 | 证书问题,且浏览器已缓存 HSTS 无法回退 |
📝小结
完整流程:加域名 → 配 CNAME → 申请证书(Let's Encrypt / ZeroSSL)→ 部署 fullchain → 配强制跳转 → 按需开 HSTS(慎开)→ 建立刷新预热机制。
三个最关键的提醒:
- 强制跳转与回源协议必须匹配,否则重定向死循环
- HSTS 开之前确保证书稳定,开了就不好回头
- 刷新预热按需使用,大批量操作放在流量低峰期
📌 自建 CDN 的核心优势:完全掌控缓存策略、证书管理和回源逻辑。代价是需要自己维护边缘节点、自己处理证书续期、自己实现刷新预热。对于技术博客来说,这是一次性投入、长期受益的选择。