流式转发,零层缓存
镜像层边下边转,不落盘,不必为缓存预留磁盘空间。
只做一件事:把拉取请求转发给对应的上游仓库,不囤镜像,也不管容器。
| 定位 | 多上游 Docker Registry 加速代理,自己的服务器、自己的域名 |
|---|---|
| 缓存 | 不缓存镜像层,流式转发;磁盘里只有 SQLite 元数据(拉取记录) |
| 入口 | 一个域名:Docker Hub 走 registry-mirrors,其他上游用路径前缀 |
| 管理 | 内置统计网页;没有 Docker socket,也没有容器管理 |
| 技术 | Go 编写,Docker Compose 部署,MIT 开源 |
镜像层边下边转,不落盘,不必为缓存预留磁盘空间。
Docker Hub 通过 registry-mirrors 保持原镜像名;ghcr.io、quay.io 等在域名后加路径前缀。
Docker Hub、GHCR、Quay、GCR、registry.k8s.io、MCR、NVCR、Elastic、公共 ECR,可以关闭,也能自己加。
分析看板、上游仓库分析、镜像列表和事件记录,支持亮色与暗色主题。
默认匿名拉取公开镜像;填上各上游的用户名和令牌,就能拉私有镜像,或避开 Docker Hub 的限流。
可以开启 pull_auth,只有 docker login 过本代理的客户端才能拉取,避免被陌生人蹭用。
数据面默认只监听 127.0.0.1:5000,由 TLS 反代对外发布;管理面 :5001 默认不对公网开放。
不挂载 docker.sock,也不管理任何容器,权限边界一目了然。
以 MIT 协议开源,中英文 README、安装指南和排障文档都在 GitHub 上。
在域名后面加上对应的路径前缀,代理会据此选择上游,并在转发前去掉前缀。
| 上游 | 路径前缀 | 拉取示例 |
|---|---|---|
| Docker Hub | docker.io,另可用 mirrors(无前缀) | docker pull nginx |
| GHCR | ghcr.io | docker pull reg.example.com/ghcr.io/owner/app:tag |
| Quay.io | quay.io | docker pull reg.example.com/quay.io/org/img:tag |
| GCR | gcr.io | docker pull reg.example.com/gcr.io/project/img:tag |
| Kubernetes | registry.k8s.io、k8s.gcr.io | docker pull reg.example.com/registry.k8s.io/pause:3.9 |
| Microsoft MCR | mcr.microsoft.com | docker pull reg.example.com/mcr.microsoft.com/... |
| NVIDIA NGC | nvcr.io | docker pull reg.example.com/nvcr.io/... |
| Elastic | docker.elastic.co | docker pull reg.example.com/docker.elastic.co/... |
| AWS 公共 ECR | public.ecr.aws | docker pull reg.example.com/public.ecr.aws/... |
说明:表中的 reg.example.com 只是示例,请换成你自己的域名。上游默认匿名拉取;需要私有镜像或想避开限流时,在 .env 里填对应的用户名和令牌。不需要的上游把 enabled 设为 false 即可关闭。
克隆仓库,填好环境变量,一条 Docker Compose 命令启动,镜像直接从 GHCR 拉取。
域名解析到代理机,把它写进 .env 的 PROXY_DOMAIN,再用 Caddy 或 Nginx 反代到 127.0.0.1:5000。
Docker Hub 在 daemon.json 里加一行 mirror;其他仓库在镜像名前加你的域名。
下面的 reg.example.com 都换成你自己的域名。
镜像名完全不用改。把下面的 JSON 写进 /etc/docker/daemon.json:
{
"registry-mirrors": ["https://reg.example.com"]
}systemctl restart docker # Linux docker pull nginx:alpine
如果入口是纯 HTTP,还需要把它加进 insecure-registries。
在同一个域名后面加上上游的前缀:
docker pull reg.example.com/ghcr.io/owner/app:tag docker pull reg.example.com/quay.io/prometheus/prometheus:latest docker pull reg.example.com/registry.k8s.io/pause:3.9
代理按前缀选择上游,并在请求真实仓库前去掉前缀。
不要用 /etc/hosts 把 ghcr.io 这类官方域名劫持到代理上,证书对不上会导致 TLS 失败。
需要 64 位 Linux 主机(或本机 Docker Desktop)、Docker 与 Docker Compose v2,以及能访问上游仓库的出站 HTTPS。
克隆仓库并进入目录,后面的命令都在这个目录里执行。
git clone https://github.com/AlexWuYh/easy-docker-proxy.git cd easy-docker-proxy
复制模板,生成随机的管理令牌和统计页密码,并把你的入口域名写进 PROXY_DOMAIN(不带 https://)。统计页账号默认是 admin,密码就是 PROXY_WEB_PASSWORD。
cp .env.example .env # 生成随机的管理令牌和统计页密码 EDP_ADMIN_TOKEN="$(openssl rand -hex 32)" EDP_WEB_PASSWORD="$(openssl rand -base64 24 | tr -d '\n')" # 写入 .env(PROXY_DOMAIN 换成你的真实域名) sed -i.bak -e "s|^PROXY_ADMIN_TOKEN=.*|PROXY_ADMIN_TOKEN=$EDP_ADMIN_TOKEN|" \ -e "s|^PROXY_WEB_PASSWORD=.*|PROXY_WEB_PASSWORD=$EDP_WEB_PASSWORD|" \ -e "s|^PROXY_DOMAIN=.*|PROXY_DOMAIN=你的真实域名|" .env rm -f .env.bak # 清掉当前终端里的明文变量 unset EDP_ADMIN_TOKEN EDP_WEB_PASSWORD
.env 不会执行 $(...),所以随机值要先在 shell 里生成再写入。数据面端口被占用时,可以再设 PROXY_PORT(默认 5000);想固定镜像版本,设 PROXY_IMAGE。
直接复制模板即可。dockerhub 的 hosts 已写成 ${PROXY_DOMAIN},由上一步 .env 里的域名展开,不用再手改 YAML。
cp configs/config.docker.yaml configs/config.yaml
registries:
- name: dockerhub
hosts:
- "${PROXY_DOMAIN:-reg.example.com}" # 取自 .env 的 PROXY_DOMAIN
path_prefixes:
- "docker.io"在仓库根目录执行。默认拉取 CI 发布的多架构镜像 ghcr.io/alexwuyh/easy-docker-proxy:latest(amd64 / arm64);想用本地源码构建,在命令末尾加 --build。
docker compose --env-file .env -f deploy/docker-compose.yaml up -d
用入口域名作为 Host 访问数据面,返回 200 就说明代理已就绪。
set -a; . ./.env; set +a
curl -sS -o /dev/null -w '%{http_code}\n' \
-H "Host: $PROXY_DOMAIN" "http://127.0.0.1:${PROXY_PORT:-5000}/v2/"以后升级到新镜像:
docker compose --env-file .env -f deploy/docker-compose.yaml pull docker compose --env-file .env -f deploy/docker-compose.yaml up -d
| 数据面 | 默认只在主机 127.0.0.1:5000 监听(可用 PROXY_PORT 修改),通过 TLS 反代对外发布 |
|---|---|
| 管理面 | :5001,默认不对公网开放 |
| HTTPS | 推荐用已有的 Caddy 反代到 127.0.0.1:5000(端口与 PROXY_PORT 一致);没有现成 Caddy 时可加 --profile edge 使用自带的,站点名取自 PROXY_DOMAIN |
| 统计页 | 把 127.0.0.1:5001 映射出来,浏览器直接访问即可 |
域名要自己准备:文档里的 reg.example.com 只是示例。先注册域名,把 A / AAAA(或 CNAME)解析到代理机,再把真实域名写进 .env 的 PROXY_DOMAIN 和 Caddy / Nginx。解析生效前,客户端会拉取失败。