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 || true

CentOS / 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 nginx

3. 写入 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";
}
EOF

B) 创建站点配置(先写入模板,再替换域名占位符)

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.confhttp {} 块中即可。

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)#

  1. 打开 Docker Desktop → Settings(设置)
  2. 左侧选择 Docker Engine
  3. 在 JSON 配置中添加 registry-mirrors
{
  "registry-mirrors": ["https://docker.yourdomain.com"]
}

docker.yourdomain.com 替换为你的实际域名。如果已有其他配置项,只需添加 registry-mirrors 这一行即可。

  1. 点击 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 docker

2. 部署 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-mirror

3. 修改 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 nginx

4. 磁盘空间管理#

查看缓存大小:

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: 请依次排查以下几点:

  1. 域名是否解析正确:getent hosts $DOMAIN
  2. VPS 的 80/443 端口是否放行(检查安全组和防火墙)
  3. 服务端能否正常访问:curl -I https://$DOMAIN/v2/
  4. 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 线路对国内加速效果最佳。