Docker Pull 超时?自建镜像加速器终极指南#
使用 Docker 时,经常遇到以下报错
Error response from daemon: Get "https://registry-1.docker.io/v2/":
net/http: TLS handshake timeout或者:
error pulling image configuration: download failed after attempts=6:
dial tcp 54.198.211.102:443: i/o timeout在国内网络环境下,docker pull 几乎必然超时。
公共镜像站要么已失效、要么严重限速,自建加速器才是长久之计。
本文提供两种方案,适用于不同场景。
如果你有一台海外 VPS(如 搬瓦工 或 DMIT),10 分钟即可搭建专属加速器。
0. 准备环境#
- 一台海外 VPS
- 一个域名(示例
docker.yourdomain.com),A 记录解析到 VPS - 80/443 端口可访问(签证书/HTTPS 需要)
建议先在 VPS 上设置环境变量,后续命令会自动引用:
DOMAIN="docker.yourdomain.com"
EMAIL="your@email.com"验证域名解析:
getent hosts "$DOMAIN" || true为什么不直接用代理?#
如果已有 socks5/http 代理,可能会问:直接给 Docker 配代理不行吗?
可以,但镜像加速器通常更省心:
| 对比项 | 镜像加速器 | Docker 配代理 |
|---|---|---|
| 配置难度 | 改一行 JSON | 需配 systemd 环境变量 |
| 兼容性 | Docker 原生支持 | buildx/compose 有时不走代理 |
| 缓存 | 可选开启本地缓存 | 无缓存,每次重新下载 |
| 团队共享 | 一个 URL 全员用 | 每台机器配代理 |
如何选择:
- 单机 + 已有代理 + 偶尔使用 → 直接配置代理即可
- 多机 / 频繁拉镜像 / CI/CD 场景 → 建议搭建加速器
服务端配置:Nginx 反向代理(海外 VPS)#
1. 安装 Nginx 并放行端口#
根据你的发行版选择对应命令:
Debian / Ubuntu:
sudo apt update
sudo apt install -y nginx curl ca-certificates socat
sudo systemctl enable --now nginx
# 放行 80/443 端口(如果用 ufw)
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp || trueCentOS / RHEL:
sudo yum install -y epel-release
sudo yum install -y nginx curl ca-certificates socat
sudo systemctl enable --now nginx
# 放行 80/443 端口(如果用 firewalld)
sudo firewall-cmd --permanent --add-service=http && sudo firewall-cmd --permanent --add-service=https && sudo firewall-cmd --reload || true注意:云服务器还需在控制台安全组中放行 80/443 端口。
2. 申请 HTTPS 证书(acme.sh / Let’s Encrypt)#
此处使用 standalone 模式签发证书,该模式会临时占用 80 端口,因此需要先停止 Nginx。
curl https://get.acme.sh | sh -s email="$EMAIL"
sudo systemctl stop nginx
~/.acme.sh/acme.sh --issue -d "$DOMAIN" --standalone
sudo mkdir -p /etc/nginx/ssl
~/.acme.sh/acme.sh --install-cert -d "$DOMAIN" --key-file "/etc/nginx/ssl/${DOMAIN}.key" --fullchain-file "/etc/nginx/ssl/${DOMAIN}.cer" --reloadcmd "systemctl restart nginx >/dev/null 2>&1 || true"
sudo systemctl start nginx3. 写入 Nginx 配置(整段复制执行)#
A) 创建 map 配置(放到 conf.d 目录,避免修改 nginx.conf)
sudo tee /etc/nginx/conf.d/00-docker-mirror-map.conf >/dev/null <<'EOF'
map $upstream_http_www_authenticate $docker_www_authenticate {
default $upstream_http_www_authenticate;
~^Bearer\s+realm="https://auth\.docker\.io/token"(.*)$ "Bearer realm=\"https://$host/token\"$1";
}
EOFB) 创建站点配置(先写入模板,再替换域名占位符)
sudo tee /etc/nginx/conf.d/10-docker-mirror.conf >/dev/null <<'EOF'
server {
listen 80;
server_name __DOMAIN__;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name __DOMAIN__;
ssl_certificate /etc/nginx/ssl/__DOMAIN__.cer;
ssl_certificate_key /etc/nginx/ssl/__DOMAIN__.key;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
client_max_body_size 0;
# token:让客户端访问 https://你的域名/token 获取 token
location = /token {
proxy_pass https://auth.docker.io/token$is_args$args;
proxy_ssl_server_name on;
proxy_set_header Host auth.docker.io;
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;
}
# registry:反代 Docker Hub Registry API
location / {
proxy_pass https://registry-1.docker.io;
proxy_ssl_server_name on;
proxy_set_header Host registry-1.docker.io;
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;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
proxy_buffering off;
proxy_request_buffering off;
# 把 Docker Hub CDN 跳转改成你的域名,客户端会继续请求你的反代
proxy_redirect https://production.cloudflare.docker.com https://$host;
proxy_hide_header WWW-Authenticate;
add_header WWW-Authenticate $docker_www_authenticate always;
}
# 接住上面的跳转(/registry-v2/...),继续转发到 Docker Hub CDN
location ^~ /registry-v2/ {
proxy_pass https://production.cloudflare.docker.com;
proxy_ssl_server_name on;
proxy_set_header Host production.cloudflare.docker.com;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
proxy_buffering off;
proxy_request_buffering off;
}
}
EOF
sudo sed -i "s/__DOMAIN__/${DOMAIN}/g" /etc/nginx/conf.d/10-docker-mirror.conf配置要点:
- Docker 拉取镜像前会访问
auth.docker.io/token获取认证 token;此处通过realm改写 +/token反代,避免国内直连auth.docker.io超时 - 拉取 blob 时可能 307/302 跳转到
production.cloudflare.docker.com;此处将跳转地址改为你的域名,再由 Nginx 继续转发
C) 测试配置并重载
sudo nginx -t
sudo systemctl reload nginx若
nginx -t报错 “map directive is not allowed here”,说明你的发行版conf.d目录不在http {}作用域内:将00-docker-mirror-map.conf的内容移到nginx.conf的http {}块中即可。
4. 验证服务端#
在 VPS 上执行以下命令,验证 Nginx 反代是否正常工作:
curl -I "https://${DOMAIN}/v2/"
curl -s -I "https://${DOMAIN}/v2/" | grep -i www-authenticate || true
curl -s "https://${DOMAIN}/token?service=registry.docker.io&scope=repository:library/alpine:pull" | head -c 120; echo预期结果:
- 第一条命令返回
HTTP/2 401(正常,表示未认证) - 第二条命令返回的 WWW-Authenticate 头中包含
realm="https://你的域名/token" - 第三条命令返回 JSON 格式的 token 数据
服务端验证通过后,继续进行下一节"客户端配置"。
客户端配置#
服务端配置完成后,在需要拉取镜像的客户端机器上设置 registry-mirrors。
Docker Desktop (Windows / macOS)#
- 打开 Docker Desktop → Settings(设置)
- 左侧选择 Docker Engine
- 在 JSON 配置中添加
registry-mirrors:
{
"registry-mirrors": ["https://docker.yourdomain.com"]
}将
docker.yourdomain.com替换为你的实际域名。如果已有其他配置项,只需添加registry-mirrors这一行即可。
- 点击 Apply & Restart
验证配置是否生效:
docker info | findstr -i "Registry Mirrors"或在 macOS 终端执行:
docker info | grep -A 5 "Registry Mirrors"Linux#
1) 修改 /etc/docker/daemon.json#
DOMAIN="docker.yourdomain.com" # 改成你的域名
sudo mkdir -p /etc/docker
# 如果文件不存在,创建新文件
if [ ! -f /etc/docker/daemon.json ]; then
echo '{}' | sudo tee /etc/docker/daemon.json >/dev/null
fi
# 备份并添加 registry-mirrors(保留现有配置)
sudo cp -a /etc/docker/daemon.json "/etc/docker/daemon.json.bak.$(date +%F_%H%M%S)"
sudo cat /etc/docker/daemon.json | python3 -c "
import sys, json
d = json.load(sys.stdin)
d['registry-mirrors'] = ['https://$DOMAIN']
print(json.dumps(d, indent=2))
" | sudo tee /etc/docker/daemon.json >/dev/null如果没有安装 python3,可手动编辑
/etc/docker/daemon.json,添加"registry-mirrors": ["https://你的域名"]。
2) 重启 Docker 并验证#
sudo systemctl daemon-reload
sudo systemctl restart docker
docker info | grep -A 5 "Registry Mirrors" || true拉取测试(所有平台通用)#
docker rmi alpine:latest nginx:alpine 2>/dev/null || true
docker pull alpine:latest
docker pull nginx:alpine同时可在海外 VPS 上查看 Nginx 访问日志,确认请求确实经过了你的反代:
sudo tail -f /var/log/nginx/access.log可选:Registry 缓存扩展#
如果有多台机器或 CI/CD 环境频繁拉取镜像,可以在 Nginx 反代基础上增加一层 Registry 缓存。
主要特点:
- 首次拉取:海外 VPS 从 Docker Hub 拉取并缓存到本地
- 后续拉取:直接从本地缓存读取(多机/CI 场景效果显著)
- 注意事项:缓存会持续增长,需要合理规划磁盘空间并定期清理
1. 安装 Docker(如果海外 VPS 尚未安装)#
curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker2. 部署 Registry(Pull-through Cache 模式)#
sudo mkdir -p /opt/docker-mirror创建 docker-compose.yml 配置文件:
sudo tee /opt/docker-mirror/docker-compose.yml >/dev/null <<'EOF'
version: "3"
services:
registry:
image: registry:2
container_name: docker-mirror
restart: always
ports:
- "127.0.0.1:5000:5000"
environment:
REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io
REGISTRY_STORAGE_DELETE_ENABLED: "true"
# 可选:绑定 Docker Hub 账号以减少 rate limit(推荐用 PAT)
# REGISTRY_PROXY_USERNAME: your_dockerhub_user
# REGISTRY_PROXY_PASSWORD: your_dockerhub_pat
volumes:
- ./registry-data:/var/lib/registry
EOF启动服务:
cd /opt/docker-mirror
docker compose up -d || docker-compose up -d
docker ps | grep docker-mirror3. 修改 Nginx 配置指向本地 Registry#
将之前直接反代 Docker Hub 的配置改为指向本地 Registry:
sudo tee /etc/nginx/conf.d/10-docker-mirror.conf >/dev/null <<'EOF'
server {
listen 80;
server_name __DOMAIN__;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name __DOMAIN__;
ssl_certificate /etc/nginx/ssl/__DOMAIN__.cer;
ssl_certificate_key /etc/nginx/ssl/__DOMAIN__.key;
client_max_body_size 0;
location / {
proxy_pass http://127.0.0.1:5000;
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;
proxy_read_timeout 900;
}
}
EOF
sudo sed -i "s/__DOMAIN__/${DOMAIN}/g" /etc/nginx/conf.d/10-docker-mirror.conf
sudo rm -f /etc/nginx/conf.d/00-docker-mirror-map.conf
sudo nginx -t && sudo systemctl reload nginx4. 磁盘空间管理#
查看缓存大小:
du -sh /opt/docker-mirror/registry-data || true执行垃圾回收(GC)清理未使用的镜像层(建议在低峰期执行):
# 先创建 GC 配置文件
sudo tee /opt/docker-mirror/gc-config.yml >/dev/null <<'EOF'
version: 0.1
storage:
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
EOF
# 执行 GC
docker stop docker-mirror
docker run --rm \
-v /opt/docker-mirror/registry-data:/var/lib/registry \
-v /opt/docker-mirror/gc-config.yml:/etc/docker/registry/config.yml \
registry:2 bin/registry garbage-collect --delete-untagged /etc/docker/registry/config.yml
docker start docker-mirror设置每周定时 GC(示例:每周日 03:00 执行),添加到 crontab:
(crontab -l 2>/dev/null; echo "0 3 * * 0 docker stop docker-mirror && docker run --rm -v /opt/docker-mirror/registry-data:/var/lib/registry -v /opt/docker-mirror/gc-config.yml:/etc/docker/registry/config.yml registry:2 bin/registry garbage-collect --delete-untagged /etc/docker/registry/config.yml && docker start docker-mirror") | crontab -5. 验证缓存效果#
docker pull alpine:latest
docker rmi alpine:latest 2>/dev/null || true
time docker pull alpine:latest # 第二次应该更快常见问题(FAQ)#
Q: 配置后还是超时?
A: 请依次排查以下几点:
- 域名是否解析正确:
getent hosts $DOMAIN - VPS 的 80/443 端口是否放行(检查安全组和防火墙)
- 服务端能否正常访问:
curl -I https://$DOMAIN/v2/ - Nginx 日志中是否有请求记录:
tail -f /var/log/nginx/access.log
Q: WWW-Authenticate 还是指向 auth.docker.io?
A: 请确认 00-docker-mirror-map.conf 已被正确加载,且位于 http {} 作用域内。
Q: 为什么我配置了 mirror 还是显示 403 Forbidden?
A: 可能是海外 VPS 的 IP 触发了 Docker Hub 的速率限制(Rate Limit)。建议在 docker-compose.yml 中配置 Docker Hub 账号和 Personal Access Token(PAT)以提高配额。
Q: 如果开启了 Registry 缓存,磁盘占满怎么办?
A: 首先使用 du -sh /opt/docker-mirror/registry-data 查看缓存占用情况,然后按照"Registry 缓存扩展"章节的说明执行 GC 清理,并制定合理的镜像清理策略。
总结#
| 使用场景 | 推荐配置 |
|---|---|
| 单机使用 / 磁盘空间有限 / 快速部署 | Nginx 反代(基础配置) |
| 多台机器 / 团队协作 / CI/CD 高频拉取 | Nginx 反代 + Registry 缓存扩展 |
安全提示:自建加速器务必启用 HTTPS,且不要在社交媒体公开域名,以延长服务可用时间。
相关推荐:搭建加速器需要一台海外 VPS,可参考我们的 高性价比 VPS 推荐,CN2 GIA 线路对国内加速效果最佳。