自建免费 Docker 镜像加速:基于 Cloudflare Worker 的零成本方案

在公众号发送
镜像加速获取代码和更详细内容。【cf账号用小号!用小号!用小号!原因看置顶评论】
如果你在国内用过 Docker,可能经常遇到过这样的场景:
-
•
docker pull nginx:latest卡在Waiting for response from registry-1.docker.io然后超时; -
• 拉到一半失败,提示
TLS handshake timeout或no such host; -
• 用过几个公共镜像加速器,要么陆续失效,要么限速严重,要么跑路。
本质上,这是因为 registry-1.docker.io 这台主机在国内的网络环境里既不友好、也不稳定。常见的应对方式(改 DNS、装代理客户端、用别人的镜像站)都各有痛点。
这里介绍一种自建、免费、几乎零运维的方案:用 Cloudflare Worker 反代 Docker Hub,部署在你自己的子域名下,5 分钟内就能用上。整套方案不依赖任何云主机。
这个方案的核心优势
-
• 完全免费:Cloudflare Workers 免费版每天 10 万次请求,对个人 / 小团队日常
docker pull绰绰有余。 -
• 零服务器:不需要买 VPS、不需要装 Nginx、不需要维护证书。Cloudflare Worker 本身就是全球边缘部署。
-
• 极其轻量:核心代码全在一个worker.js中,部署命令就一条
npx wrangler deploy或者直接粘贴代码到worker就完事。 -
• 支持私有镜像:内置
docker login流程透传,凭据会转交给官方auth.docker.io校验,私有仓库照常使用。 -
• 缓存友好:对 blob(镜像层)启用 Cloudflare Cache API,二次拉取更快、更省流量;同时做了权限校验,私有层不会因为缓存被越权命中。
-
• 可随时迁移:域名被针对?换个子域名重新部署即可,迁移成本极低。
唯一的硬性要求:你需要一个自己的域名(哪怕是很便宜的那种),并且把它的 DNS 托管到 Cloudflare。
另外注意:国内
*.workers.dev默认域名是访问不了的(被 DNS 污染 + SNI 阻断),所以必须绑定一个自己的域名。这是这个方案里唯一的“门槛”。
原理简述
Docker 客户端拉镜像时,会访问两个官方域名:
用途 官方域名 获取认证 token auth.docker.io 获取 manifest 和 blob(镜像层) registry-1.docker.io
我们的 Worker 部署在自己的域名下(比如 docker.yourdomain.com),根据请求路径自动分流到这两个官方主机。
有几点工程上的“坑”是必须处理的,否则方案跑不通:
-
- 认证响应头
Www-Authenticate必须改写:官方返回的认证地址是auth.docker.io,如果不改成你自己的域名,客户端在认证阶段会绕过你直连官方。
- 认证响应头
-
- blob 的 307 重定向不能甩给客户端:官方 blob 实际存在
production.cloudflare.docker.com,这个域名在国内被墙得相当彻底,客户端拿到的重定向后直连必失败。所以 Worker 必须自己follow这个重定向、把内容代理回来。
- blob 的 307 重定向不能甩给客户端:官方 blob 实际存在
-
- 缓存不能无脑开:因为公私镜像的 blob 请求都长一个样(都带
Bearer),如果缓存命中就立刻返回,私有镜像的层会被任何拿到 URL 的人读到。所以本方案在缓存命中时,会先用调用方自己的凭据向官方发一次HEAD鉴权:有权限才返回缓存,无权限就走正常回源。
- 缓存不能无脑开:因为公私镜像的 blob 请求都长一个样(都带
部署教程
前置条件
-
• 一个自己的域名,并已把 DNS 托管到 Cloudflare(注册 Cloudflare → 添加站点 → 把 NS 记录指过去,几分钟就能生效)。
-
• 本机装了 Node.js(
npx随 npm 提供,无需全局安装任何东西)。
第一步:登录 Cloudflare
npx wrangler login浏览器弹出授权页面,确认即可。
第二步:配置自定义域名
编辑项目里的 src/wrangler.toml,把 docker.example.com 换成你自己的子域名,并取消 routes 段的注释:
routes = [
{ pattern = "docker.yourdomain.com", custom_domain = true }
]custom_domain = true 会让 wrangler 在部署时自动帮你创建 DNS 记录 + 签发证书,不用去 Dashboard 手动加。
第三步:部署
在项目根目录执行:
npx wrangler deploy -c src/wrangler.toml看到输出里出现 https://docker.yourdomain.com 就代表部署成功。
第四步:验证
curl -I https://docker.yourdomain.com/v2/应该返回 401 且响应头里有 Www-Authenticate,这说明反代链路和认证改写都正常生效了。
部署后想看实时日志,调试问题:
npx wrangler tail -c src/wrangler.toml
使用教程
下面把 docker.yourdomain.com 全部替换为你实际绑定的子域名。
方式 A:配成 Docker 镜像加速器(推荐,命令完全不用改)
编辑 /etc/docker/daemon.json(没有就新建):
{
"registry-mirrors": ["https://docker.yourdomain.com"]
}重启 Docker 生效:
sudo systemctl daemon-reload
sudo systemctl restart docker之后照常拉镜像即可:
docker pull nginx:latest
docker pull redis:7Docker 客户端会自动通过你的加速地址去拉,命令不需要任何修改。
这个方式对官方仓库(
docker.io)的公有镜像最省事。
方式 B:把域名当作 registry 前缀直接拉(公有 / 私有都能用)
不用改 daemon.json,在镜像名前面拼上你的域名:
# 公有官方镜像(library 命名空间要写全)
docker pull docker.yourdomain.com/library/nginx:latest
# 公有第三方镜像
docker pull docker.yourdomain.com/bitnami/redis:latest这种方式对公有和私有镜像都生效,并且能带上登录凭据,是后面拉私有镜像的基础写法。
拉取私有镜像
私有镜像必须先登录。对你的代理域名执行 docker login:
docker login docker.yourdomain.com
# Username: 你的 Docker Hub 用户名
# Password: 你的 Docker Hub Access Token(推荐)或密码登录后就可以拉自己的私有仓库了:
docker pull docker.yourdomain.com/yourname/private-app:latest背后发生的事情是:你的账号密码会先被 Worker 转发给官方 auth.docker.io 校验,拿到带权限的 token 后再走拉取流程;缓存层也会用这个 token 做鉴权,私有层不会因为缓存被无权限者读到。
登出:
docker logout docker.yourdomain.com
常见疑问
Q:workers.dev 默认域名不能直接用吗?
A:不能。国内 *.workers.dev 被 DNS 污染 + SNI 阻断,所以这个方案默认关掉了 workers.dev,必须绑自定义域名。
Q:缓存会不会把私有镜像的层泄露给别人?
A:不会。缓存命中时 Worker 会用调用方自己的 Authorization 向官方发一次 HEAD 鉴权,无权限直接放弃这次命中、走回源,所以不会越权。
Q:免费额度够用吗?
A:Cloudflare Workers 免费版每天 10 万次请求。日常 docker pull 一次镜像通常只产生几个到几十个请求(manifest + 各层 blob),个人 / 小团队日常使用完全够。流量大的话再考虑升级付费版,或者加一层访问控制 header,避免被陌生人白嫖。
Q:支持 ghcr.io、gcr.io、quay.io 这些第三方 registry 吗?
A:本方案只反代 Docker Hub(registry-1.docker.io + auth.docker.io)。如果需要其他 registry,可以在 Worker 里加对应的分支路由。