自建 GitHub 加速服务:从 CF Workers 迁移到 VPS 部署 hubproxy + Caddy
docker hubproxy caddy github-proxy vps reverse-proxy之前用的 gh-proxy,基于 Cloudflare Workers 搭建。现在换了新域名 1s.gs,改用 hubproxy 部署在自己的 VPS 上,完全自托管,不再依赖第三方服务。
架构
用户 → 1s.gs → Caddy (:80/:443) → hubproxy (:5000)
↕
hubproxy_net Docker 网络
- Caddy 负责 HTTPS 和反代
- hubproxy 不暴露端口,仅通过 Docker 内部网络通信
- 旧域名
github-proxy.top显示迁移提示页,3 秒后跳转到新域名
步骤
1. 部署 hubproxy
mkdir -p /opt/services/hubproxy
/opt/services/hubproxy/docker-compose.yml:
services:
hubproxy:
image: ghcr.io/sky22333/hubproxy:latest
container_name: hubproxy
restart: always
volumes:
- ./config.toml:/app/config.toml:ro
networks:
- hubproxy_net
networks:
hubproxy_net:
external: true
/opt/services/hubproxy/config.toml:
⚠️ 必须配置!hubproxy 默认安全白名单只允许
172.17.0.0/16(Docker 默认 bridge),而自定义 Docker 网络是172.18.0.0/16,不加白名单会被 403 拦截。
[security]
whiteList = ["127.0.0.1", "172.17.0.0/16", "172.18.0.0/16", "你的公网IP"]
2. 部署 Caddy
mkdir -p /opt/services/caddy
/opt/services/caddy/docker-compose.yml:
services:
caddy:
image: caddy:2-alpine
container_name: caddy-hubproxy
restart: always
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy_data:/data
- ./caddy_config:/config
networks:
- hubproxy_net
networks:
hubproxy_net:
external: true
3. Caddyfile
完整配置(双域名):
github-proxy.top {
header Content-Type "text/html; charset=utf-8"
@root path /
handle @root {
respond / "..." 200
header / Refresh "3; url=https://1s.gs"
}
handle {
respond * "..." 200
header * Refresh "3; url=https://1s.gs{uri}"
}
}
1s.gs {
reverse_proxy hubproxy:5000 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
respond中的 HTML 是渐变紫背景的迁移提示页,包含"这个域名快退休了"、“1s.gs"可长按复制、收藏按钮、3 秒自动跳转。
启动:
docker network create hubproxy_net
cd /opt/services/hubproxy && docker compose up -d
cd /opt/services/caddy && docker compose up -d
踩坑记录
坑 1:hubproxy 返回 403
原因: hubproxy 的安全白名单默认只包含 172.17.0.0/16,自定义 Docker 网络 hubproxy_net 是 172.18.0.0/16,不在白名单内。
解决: 在 config.toml 中把自定义网络网段和公网 IP 加入白名单。
坑 2:{remote} 带端口号
原因: Caddy 的 {remote} 变量包含端口号(如 1.2.3.4:55612),hubproxy 拿这个做安全匹配时白名单中的纯 IP 对不上。
解决: 改用 {remote_host},只传纯 IP 不带端口:
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
坑 3:Docker Compose v5 网络语法
Compose v5 不再支持在 service 内联写法 external: true,需要在顶级 networks: 块声明:
# ❌ 旧写法
services:
xxx:
networks:
hubproxy_net:
external: true
# ✅ 正确写法
services:
xxx:
networks:
- hubproxy_net
networks:
hubproxy_net:
external: true
坑 4:Caddy respond 返回 text/plain
原因: Caddy 的 respond 指令默认 Content-Type 是 text/plain,浏览器按纯文本渲染 HTML。
解决: 用 file_server 服务静态 HTML 文件,或确保 respond 配合 header 设置正确的 Content-Type。
效果
https://1s.gs→ hubproxy 自带前端页面https://1s.gs/https://github.com/user/repo/...→ 正常加速代理https://github-proxy.top→ 渐变紫提示页,3 秒后跳转新域名