新增文档站

This commit is contained in:
sky22333
2026-07-13 06:42:37 +08:00
parent 320df5def5
commit 8382d9c553
54 changed files with 10226 additions and 276 deletions

51
.github/workflows/docs.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Docs 文档发布
on:
push:
branches: [main]
paths:
- 'docs/src/**'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: docs/package-lock.json
- name: Install dependencies
working-directory: docs
run: npm ci
- name: Build docs
working-directory: docs
run: npm run build
- uses: actions/upload-pages-artifact@v5
with:
path: docs/dist
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v5

5
.gitignore vendored
View File

@@ -22,5 +22,10 @@ web/pnpm-debug.log*
# Frontend build output embedded by Go # Frontend build output embedded by Go
src/dist/ src/dist/
# Docs site (docs/)
docs/node_modules/
docs/dist/
docs/.astro/
# Logs # Logs
*.log *.log

318
README.md
View File

@@ -1,38 +1,30 @@
# HubProxy # HubProxy
**Docker GitHub 加速代理服务器** **Docker GitHub 加速代理服务器**
一个轻量级、高性能的多功能代理服务,提供 Docker 镜像加速、GitHub 文件加速、下载离线镜像、在线搜索 Docker 镜像等功能 轻量级、高性能的多功能代理服务,单二进制部署,完全自托管
<p align="center">
<img src="https://count.getloli.com/get/@sky22333.hubproxy?theme=rule34" alt="Visitors">
</p>
## 特性 ## 特性
- 🐳 **Docker 镜像加速** - 支持 Docker Hub、GHCR、Quay 等多个镜像仓库加速,流式传输优化拉取速度。 - 🐳 **Docker 镜像加速** — 兼容 Registry API v2支持 Docker Hub、GHCR、Quay、GCR、registry.k8s.io流式传输Manifest / Token 缓存
- 🐳 **离线镜像包** - 支持下载离线镜像包,流式传输加防抖设计 - 📦 **离线镜像包** — 无需本地 Docker在线打包单镜像或批量 tar流式下载 + 防抖设计
- 📁 **GitHub 文件加速** - 加速 GitHub Release、Raw 文件下载,支持`api.github.com`,脚本嵌套加速等等 - 📁 **GitHub 文件加速** Release、Raw、Git Clone、`api.github.com``.sh` / `.ps1` 脚本内 URL 自动改写
- 🤖 **AI 模型库支持** - 支持 Hugging Face 模型下载加速 - 🤖 **Hugging Face 加速** — 模型文件与 LFS 大文件下载
- 🛡️ **智能限流** - IP 限流保护,防止滥用 - 🔍 **镜像搜索** — Web 界面与 API 搜索 Docker Hub 镜像、浏览标签
- 🚫 **仓库审计** - 强大的自定义黑名单白名单同时审计镜像仓库和GitHub仓库 - 🛡️ **智能限流** — 按真实客户端 IP 令牌桶限流IPv6 按 `/64`);可配置周期与配额
- 🔍 **镜像搜索** - 在线搜索 Docker 镜像 - 🚫 **仓库访问控制** — IP 黑白名单(限流豁免 / 封禁)+ 镜像 / GitHub 仓库黑白名单,支持通配符
- **轻量高效** - 基于 Go 语言,单二进制文件运行,资源占用低。 - 🌐 **上游 SOCKS5 代理** — 可选配置出站代理,适配特殊网络环境
- 🔧 **统一配置** - 统一配置管理,便于维护。 - 🖥️ **Web 界面** — 内置 Vue SPA镜像搜索、离线包下载、标签浏览
- 🛡️ **完全自托管** - 避免依赖免费第三方服务的不稳定性,例如`cloudflare`等等。 - **轻量高效** — Go 单二进制,支持 `deb` / `rpm` / `apk` 与 Docker 多架构镜像
- 🚀 **多服务统一加速** - 单个程序即可统一加速 Docker、GitHub、Hugging Face 等多种服务,简化部署与管理。 - 🔧 **统一配置**`config.toml` + 环境变量覆盖,开箱即用
- 🚀 **多服务统一加速** — 单个程序覆盖 Docker、GitHub、Hugging Face简化部署
## 详细文档 - ☁️ **完全自托管** — 不依赖第三方免费 CDN 代理,数据与带宽自主可控
[中文文档](https://zread.ai/sky22333/hubproxy)
[English](https://deepwiki.com/sky22333/hubproxy)
## 快速开始 ## 快速开始
### Docker部署推荐 ### Docker 部署(推荐)
```
```bash
docker run -d \ docker run -d \
--name hubproxy \ --name hubproxy \
-p 5000:5000 \ -p 5000:5000 \
@@ -40,265 +32,47 @@ docker run -d \
ghcr.io/sky22333/hubproxy ghcr.io/sky22333/hubproxy
``` ```
验证服务:
```bash
curl http://127.0.0.1:5000/ready
```
### 脚本安装 ### 脚本安装
自动识别系统与架构,从 GitHub Releases 下载对应的 `.deb``.rpm` `.apk` 安装包 自动识别 `amd64` / `arm64` `apt``dnf``apk` 等包管理器
```bash ```bash
curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install.sh | sh curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install.sh | sh
``` ```
安装包会自动安装并启动 `hubproxy` 服务。 安装后配置文件位于 `/etc/hubproxy/config.toml`服务自动启动
<details> ### 快速上手
<summary>服务管理命令</summary>
#### systemdDebian / Ubuntu / RHEL / CentOS / Fedora
```bash ```bash
# 查看状态 # Docker 镜像加速(将 yourdomain.com 换成你的 HubProxy 地址)
sudo systemctl status hubproxy docker pull yourdomain.com/library/nginx:latest
# 重启服务 # GitHub Release 加速(完整 URL 前缀)
sudo systemctl restart hubproxy curl -L -O "https://yourdomain.com/https://github.com/owner/repo/releases/download/v1.0.0/app.tar.gz"
# 查看实时日志
sudo journalctl -u hubproxy -f
# 编辑配置文件
sudo nano /etc/hubproxy/config.toml
# 卸载服务
sudo apt remove hubproxy
# 连配置一起清理
sudo apt purge hubproxy
``` ```
#### OpenRCAlpine Linux > **生产环境建议**:绑定自有域名,通过 Caddy / Nginx 反代并开启 HTTPS不要长期暴露裸 `http://IP:5000`。详见 [文档](https://sky22333.github.io/hubproxy/getting-started/quick-start/)。
```bash ## 文档
# 查看状态
sudo rc-service hubproxy status
# 重启服务 部署架构、完整配置、K8s / NAS、传输特性与 FAQ 见官方文档站(中英双语):
sudo rc-service hubproxy restart
# 查看实时日志 - [中文文档](https://sky22333.github.io/hubproxy/)
sudo tail -f /var/log/hubproxy.log - [English](https://sky22333.github.io/hubproxy/en/)
# 编辑配置文件
sudo vi /etc/hubproxy/config.toml
# 卸载
sudo apk del hubproxy
```
</details>
### 文件路径
- Linux 安装包配置文件:`/etc/hubproxy/config.toml`
- Linux 安装包二进制文件:`/usr/bin/hubproxy`
- systemd 服务文件:`/lib/systemd/system/hubproxy.service`
- Alpine OpenRC 服务文件:`/etc/init.d/hubproxy`
- Alpine 日志文件:`/var/log/hubproxy.log`
- Alpine 日志轮转配置:`/etc/logrotate.d/hubproxy`
## 使用方法
### Docker 镜像加速
```bash
# 原命令
docker pull nginx
# 使用加速
docker pull yourdomain.com/nginx
# ghcr加速
docker pull yourdomain.com/ghcr.io/sky22333/hubproxy
# 符合Docker Registry API v2标准的仓库都支持
```
当然也支持配置为全局镜像加速,在主机上新建(或编辑)`/etc/docker/daemon.json`
`"registry-mirrors"` 中加入域名:
```json
{
"registry-mirrors": [
"https://yourdomain.com"
]
}
```
若已设置其他加速地址,直接并列添加后保存,再执行 `sudo systemctl restart docker` 重启docker服务让配置生效。
### GitHub 文件加速
```bash
# 原链接
https://github.com/user/repo/releases/download/v1.0.0/file.tar.gz
# 加速链接
https://yourdomain.com/https://github.com/user/repo/releases/download/v1.0.0/file.tar.gz
# 加速下载仓库
git clone https://yourdomain.com/https://github.com/sky22333/hubproxy.git
```
## 配置
<details>
<summary>config.toml 配置说明</summary>
*此配置是默认配置,已经内置在程序中了*
```
[server]
host = "0.0.0.0"
# 监听端口
port = 5000
# Github文件大小限制字节默认2GB
fileSize = 2147483648
# HTTP/2 多路复用,提升下载速度
enableH2C = false
# 是否启用前端页面Vue SPA
enableFrontend = true
[rateLimit]
# 每个IP每周期允许的请求数(注意Docker镜像会有多个层会消耗多个次数)
requestLimit = 500
# 限流周期(小时)
periodHours = 3.0
[security]
# IP白名单支持单个IP或IP段
# 白名单中的IP不受限流限制
whiteList = [
"127.0.0.1",
"172.17.0.0/16",
"192.168.1.0/24"
]
# IP黑名单支持单个IP或IP段
# 黑名单中的IP将被直接拒绝访问
blackList = [
"192.168.100.1",
"192.168.100.0/24"
]
[access]
# 代理服务白名单支持GitHub仓库和Docker镜像支持通配符
# 只允许访问白名单中的仓库/镜像,为空时不限制
whiteList = []
# 代理服务黑名单支持GitHub仓库和Docker镜像支持通配符
# 禁止访问黑名单中的仓库/镜像
blackList = [
"baduser/malicious-repo",
"*/malicious-repo",
"baduser/*"
]
# 代理配置,支持有用户名/密码认证和无认证模式
# 无认证: socks5://127.0.0.1:1080
# 有认证: socks5://username:password@127.0.0.1:1080
# 留空不使用代理
proxy = ""
[download]
# 批量下载离线镜像数量限制
maxImages = 10
# Registry映射配置支持多种镜像仓库上游
[registries]
# GitHub Container Registry
[registries."ghcr.io"]
upstream = "ghcr.io"
authHost = "ghcr.io/token"
authType = "github"
enabled = true
# Google Container Registry
[registries."gcr.io"]
upstream = "gcr.io"
authHost = "gcr.io/v2/token"
authType = "google"
enabled = true
# Quay.io Container Registry
[registries."quay.io"]
upstream = "quay.io"
authHost = "quay.io/v2/auth"
authType = "quay"
enabled = true
# Kubernetes Container Registry
[registries."registry.k8s.io"]
upstream = "registry.k8s.io"
authHost = "registry.k8s.io"
authType = "anonymous"
enabled = true
[tokenCache]
# 是否启用缓存(同时控制Token和Manifest缓存)显著提升性能
enabled = true
# 默认缓存时间(分钟)
defaultTTL = "20m"
```
</details>
### 环境变量(可选)
支持通过环境变量覆盖部分配置,优先级高于`config.toml`,以下是默认值:
```
CONFIG_PATH=config.toml # 配置文件路径
SERVER_HOST=0.0.0.0 # 监听地址
SERVER_PORT=5000 # 监听端口
ENABLE_H2C=false # 是否启用 H2C
ENABLE_FRONTEND=true # 是否启用前端页面Vue SPA
MAX_FILE_SIZE=2147483648 # GitHub 文件大小限制(字节)
RATE_LIMIT=500 # 每周期请求数
RATE_PERIOD_HOURS=3 # 限流周期(小时)
IP_WHITELIST=127.0.0.1,192.168.1.0/24 # IP 白名单(逗号分隔)
IP_BLACKLIST=192.168.100.1,192.168.100.0/24 # IP 黑名单(逗号分隔)
MAX_IMAGES=10 # 批量下载镜像数量限制
ACCESS_PROXY= # 代理配置,例如 socks5://127.0.0.1:1080
```
为了IP限流能够正常运行反向代理需要传递IP头用来获取访客真实IP以caddy为例
```
example.com {
reverse_proxy {
to 127.0.0.1:5000
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
}
}
```
cloudflare CDN
```
example.com {
reverse_proxy 127.0.0.1:5000 {
header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
header_up X-Real-IP {http.request.header.CF-Connecting-IP}
header_up X-Forwarded-Proto https
header_up X-Forwarded-Host {host}
}
}
```
> 对于使用nginx反代的用户Github加速提示`无效输入`的问题可以参见[issues/62](https://github.com/sky22333/hubproxy/issues/62#issuecomment-3219572440)
## ⚠️ 免责声明 ## 界面预览
![demo](.github/demo/demo.png)
## 免责声明
- 本程序仅供学习交流使用,请勿用于非法用途 - 本程序仅供学习交流使用,请勿用于非法用途
- 使用本程序需遵守当地法律法规 - 使用本程序需遵守当地法律法规
@@ -306,12 +80,4 @@ example.com {
--- ---
<div align="center"> **如果这个项目对你有帮助,请给个 Star ⭐**
**⭐ 如果这个项目对你有帮助,请给个 Star⭐**
</div>
## 界面预览
![demo](.github/demo/demo.png)

3
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules/
dist/
.astro/

39
docs/README.md Normal file
View File

@@ -0,0 +1,39 @@
# HubProxy 文档站
基于 [Astro Starlight](https://starlight.astro.build/),默认中文,英文位于 `/en/`
## 本地开发
```bash
cd docs
npm install
npm run dev
```
访问 http://localhost:4321/hubproxy/GitHub Pages 子路径与线上一致)。
## 构建
```bash
npm run build # 输出到 dist/
npm run preview # 本地预览构建结果
```
## 目录
```
src/content/docs/ # 中文文档
src/content/docs/en/ # 英文文档
src/assets/ # logo、hero 等资源
public/favicon.svg # 浏览器标签页图标
src/styles/custom.css # 自定义样式
astro.config.mjs # Starlight 配置(含 base: /hubproxy/
```
## 贡献
1. 修改 `src/content/docs/` 中文页面,并同步 `en/` 镜像
2. 侧边栏结构见 `astro.config.mjs`
3. 向主仓库提交 PR
部署由 `.github/workflows/docs.yml` 自动发布至 GitHub Pages。

81
docs/astro.config.mjs Normal file
View File

@@ -0,0 +1,81 @@
import { defineConfig } from 'astro/config'
import starlight from '@astrojs/starlight'
export default defineConfig({
site: 'https://sky22333.github.io',
base: '/hubproxy/',
integrations: [
starlight({
title: 'HubProxy',
description: 'Docker 与 GitHub 加速代理服务文档',
defaultLocale: 'root',
locales: {
root: {
label: '简体中文',
lang: 'zh-CN',
},
en: {
label: 'English',
lang: 'en',
},
},
logo: {
alt: 'HubProxy',
src: './src/assets/logo.svg',
},
social: [
{
icon: 'github',
label: 'GitHub',
href: 'https://github.com/sky22333/hubproxy',
},
],
editLink: {
baseUrl: 'https://github.com/sky22333/hubproxy/edit/main/docs/',
},
sidebar: [
{
label: '简介',
translations: { en: 'Introduction' },
link: '/',
},
{
label: '快速开始',
translations: { en: 'Getting Started' },
collapsed: true,
items: [{ autogenerate: { directory: 'getting-started' } }],
},
{
label: '部署',
translations: { en: 'Deployment' },
collapsed: true,
items: [{ autogenerate: { directory: 'deployment' } }],
},
{
label: '使用指南',
translations: { en: 'Guides' },
collapsed: true,
items: [{ autogenerate: { directory: 'guides' } }],
},
{
label: '配置',
translations: { en: 'Configuration' },
collapsed: true,
items: [{ autogenerate: { directory: 'configuration' } }],
},
{
label: '安全',
translations: { en: 'Security' },
collapsed: true,
items: [{ autogenerate: { directory: 'security' } }],
},
{
label: '常见问题',
translations: { en: 'FAQ' },
link: '/faq/',
},
],
customCss: ['./src/styles/custom.css'],
}),
],
})

6883
docs/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
docs/package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "hubproxy-docs",
"private": true,
"type": "module",
"packageManager": "npm@11.12.1",
"engines": {
"node": ">=24"
},
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"dependencies": {
"@astrojs/starlight": "^0.41.3",
"astro": "^7.0.7",
"sharp": "^0.34.5"
}
}

12
docs/public/favicon.svg Normal file
View File

@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<linearGradient id="f-bg" x1="10" y1="6" x2="54" y2="58" gradientUnits="userSpaceOnUse">
<stop stop-color="#3b82f6"/>
<stop stop-color="#1d4ed8"/>
</linearGradient>
</defs>
<rect x="4" y="4" width="56" height="56" rx="16" fill="url(#f-bg)"/>
<rect x="28" y="18" width="8" height="28" rx="4" fill="#fff"/>
<path d="M16 32h8M48 32H40" stroke="#fff" stroke-width="3.5" stroke-linecap="round"/>
<path d="M20 27.5 24 32l-4 4.5M44 27.5 40 32l4 4.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 642 B

57
docs/src/assets/hero.svg Normal file
View File

@@ -0,0 +1,57 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 320" fill="none" role="img" aria-label="HubProxy">
<defs>
<linearGradient id="hero-bg" x1="0" y1="0" x2="480" y2="320" gradientUnits="userSpaceOnUse">
<stop stop-color="#eff6ff"/>
<stop stop-color="#f8fafc"/>
</linearGradient>
<linearGradient id="hero-icon" x1="180" y1="72" x2="300" y2="192" gradientUnits="userSpaceOnUse">
<stop stop-color="#3b82f6"/>
<stop stop-color="#1d4ed8"/>
</linearGradient>
<linearGradient id="hero-shine" x1="200" y1="88" x2="280" y2="168" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" stop-opacity="0.35"/>
<stop stop-color="#fff" stop-opacity="0"/>
</linearGradient>
<radialGradient id="hero-glow" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(240 130) rotate(90) scale(120 160)">
<stop stop-color="#3b82f6" stop-opacity="0.18"/>
<stop stop-color="#3b82f6" stop-opacity="0"/>
</radialGradient>
<filter id="hero-shadow" x="160" y="70" width="160" height="160" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feDropShadow dx="0" dy="10" stdDeviation="14" flood-color="#1d4ed8" flood-opacity="0.18"/>
</filter>
</defs>
<rect width="480" height="320" rx="28" fill="url(#hero-bg)"/>
<rect width="480" height="320" rx="28" fill="url(#hero-glow)"/>
<g opacity="0.35" stroke="#93c5fd" stroke-width="1.5">
<path d="M72 96h64M72 224h64M344 96h64M344 224h64"/>
<circle cx="72" cy="96" r="4" fill="#bfdbfe" stroke="none"/>
<circle cx="136" cy="96" r="4" fill="#bfdbfe" stroke="none"/>
<circle cx="344" cy="96" r="4" fill="#bfdbfe" stroke="none"/>
<circle cx="408" cy="96" r="4" fill="#bfdbfe" stroke="none"/>
<circle cx="72" cy="224" r="4" fill="#bfdbfe" stroke="none"/>
<circle cx="136" cy="224" r="4" fill="#bfdbfe" stroke="none"/>
<circle cx="344" cy="224" r="4" fill="#bfdbfe" stroke="none"/>
<circle cx="408" cy="224" r="4" fill="#bfdbfe" stroke="none"/>
</g>
<path d="M136 96C168 96 196 110 214 130M344 96C312 96 284 110 266 130" stroke="#93c5fd" stroke-width="2" stroke-linecap="round" stroke-dasharray="6 8" opacity="0.7"/>
<path d="M136 224C168 224 196 210 214 190M344 224C312 224 284 210 266 190" stroke="#93c5fd" stroke-width="2" stroke-linecap="round" stroke-dasharray="6 8" opacity="0.7"/>
<g filter="url(#hero-shadow)">
<rect x="192" y="82" width="96" height="96" rx="28" fill="url(#hero-icon)"/>
<rect x="192" y="82" width="96" height="96" rx="28" fill="url(#hero-shine)"/>
<rect x="234" y="104" width="12" height="52" rx="6" fill="#fff" fill-opacity="0.96"/>
<path d="M208 130h16" stroke="#fff" stroke-width="5" stroke-linecap="round"/>
<path d="M216 121l8 9-8 9" stroke="#fff" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M272 130h-16" stroke="#fff" stroke-width="5" stroke-linecap="round"/>
<path d="M264 121l-8 9 8 9" stroke="#fff" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="240" cy="92" r="4" fill="#fff" fill-opacity="0.55"/>
<circle cx="240" cy="168" r="4" fill="#fff" fill-opacity="0.55"/>
<path d="M240 96v6M240 162v6" stroke="#fff" stroke-width="2.5" stroke-linecap="round" stroke-opacity="0.45"/>
</g>
<text x="240" y="228" text-anchor="middle" fill="#0f172a" font-family="ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif" font-size="34" font-weight="700" letter-spacing="-0.02em">HubProxy</text>
<text x="240" y="258" text-anchor="middle" fill="#64748b" font-family="ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif" font-size="15" font-weight="500">Docker · GitHub · Registry Proxy</text>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

22
docs/src/assets/logo.svg Normal file
View File

@@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none" role="img" aria-label="HubProxy">
<defs>
<linearGradient id="hp-bg" x1="10" y1="6" x2="54" y2="58" gradientUnits="userSpaceOnUse">
<stop stop-color="#3b82f6"/>
<stop stop-color="#1d4ed8"/>
</linearGradient>
<linearGradient id="hp-shine" x1="20" y1="12" x2="44" y2="40" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" stop-opacity="0.28"/>
<stop stop-color="#fff" stop-opacity="0"/>
</linearGradient>
</defs>
<rect x="4" y="4" width="56" height="56" rx="16" fill="url(#hp-bg)"/>
<rect x="4" y="4" width="56" height="56" rx="16" fill="url(#hp-shine)"/>
<rect x="28" y="18" width="8" height="28" rx="4" fill="#fff" fill-opacity="0.95"/>
<path d="M16 32h8" stroke="#fff" stroke-width="3.5" stroke-linecap="round"/>
<path d="M20 27.5 24 32l-4 4.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M48 32H40" stroke="#fff" stroke-width="3.5" stroke-linecap="round"/>
<path d="M44 27.5 40 32l4 4.5" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="32" cy="14" r="2.5" fill="#fff" fill-opacity="0.55"/>
<circle cx="32" cy="50" r="2.5" fill="#fff" fill-opacity="0.55"/>
<path d="M32 16.5v4M32 43.5v4" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-opacity="0.45"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,7 @@
import { defineCollection } from 'astro:content'
import { docsLoader } from '@astrojs/starlight/loaders'
import { docsSchema } from '@astrojs/starlight/schema'
export const collections = {
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
}

View File

@@ -0,0 +1,46 @@
---
title: 环境变量
description: HubProxy 支持的环境变量说明。
---
环境变量在加载 `config.toml` 之后覆盖对应配置项。未列出的配置段(如 `[registries]`、`[tokenCache]`、`[access].whiteList`)只能通过配置文件修改。
## 全部变量
| 环境变量 | 对应配置 | 说明 |
|---------|---------|------|
| `CONFIG_PATH` | — | 配置文件路径,默认 `./config.toml` |
| `SERVER_HOST` | `[server].host` | 监听地址 |
| `SERVER_PORT` | `[server].port` | 监听端口 |
| `ENABLE_H2C` | `[server].enableH2C` | 启用 HTTP/2 Cleartext`true`/`false` |
| `ENABLE_FRONTEND` | `[server].enableFrontend` | 启用 Web 界面(`true`/`false` |
| `MAX_FILE_SIZE` | `[server].fileSize` | 单文件大小上限(字节) |
| `RATE_LIMIT` | `[rateLimit].requestLimit` | 每 IP 每周期请求数 |
| `RATE_PERIOD_HOURS` | `[rateLimit].periodHours` | 限流周期(小时) |
| `IP_WHITELIST` | `[security].whiteList` | 追加限流豁免 IP逗号分隔 |
| `IP_BLACKLIST` | `[security].blackList` | 追加封禁 IP逗号分隔 |
| `ACCESS_PROXY` | `[access].proxy` | 上游 SOCKS5 代理地址 |
| `MAX_IMAGES` | `[download].maxImages` | 批量离线镜像数量上限 |
## 示例
```bash
# systemd / 本地运行
CONFIG_PATH=/etc/hubproxy/config.toml ./hubproxy
# Docker 快速调参
docker run -d \
-e SERVER_PORT=5000 \
-e RATE_LIMIT=1000 \
-e IP_WHITELIST=10.0.0.0/8,192.168.1.100 \
-v ./config.toml:/app/config.toml:ro \
ghcr.io/sky22333/hubproxy
```
## 使用场景
| 场景 | 建议 |
|------|------|
| systemd 服务 | `CONFIG_PATH=/etc/hubproxy/config.toml`(服务文件已内置) |
| Docker | 挂载 `/app/config.toml`,临时参数用 `-e` |
| 开发调试 | `CONFIG_PATH=./src/config.toml go run .` |

View File

@@ -0,0 +1,106 @@
---
title: config.toml 参考
description: HubProxy 配置文件完整参考。
---
配置文件默认路径为工作目录下的 `config.toml`,可通过 `CONFIG_PATH` 环境变量覆盖。完整环境变量列表见 [环境变量](/configuration/environment/)。
## [server]
| 键 | 类型 | 默认值 | 说明 |
|----|------|--------|------|
| `host` | string | `0.0.0.0` | 监听地址 |
| `port` | int | `5000` | 监听端口 |
| `fileSize` | int | `2147483648` | 单文件大小上限(字节),影响 GitHub 代理与离线镜像 |
| `enableH2C` | bool | `false` | 启用 HTTP/2 Cleartext |
| `enableFrontend` | bool | `true` | 启用 Web 界面Vue SPA |
## [rateLimit]
| 键 | 类型 | 默认值 | 说明 |
|----|------|--------|------|
| `requestLimit` | int | `500` | 每 IP 每周期允许请求数 |
| `periodHours` | float | `3.0` | 限流周期(小时) |
IPv4 按完整 IP 计数IPv6 按 `/64` 网段计数。前端静态路由(`/`、`/images`、`/search`、`/assets/*`)不计入限流。
:::note
Docker 拉取一个镜像会请求多个 layer每个 HTTP 请求均消耗限流配额。
:::
## [security]
| 键 | 说明 |
|----|------|
| `whiteList` | 限流豁免 IP 列表(支持 CIDR单 IP 自动补 `/32` |
| `blackList` | 直接拒绝访问的 IP 列表403 |
:::note
`[security]` 黑白名单仅影响限流与 IP 封禁,**不**控制可代理的仓库。
:::
## [access]
| 键 | 说明 |
|----|------|
| `whiteList` | 允许代理的仓库/镜像(空=不限制) |
| `blackList` | 禁止代理的仓库/镜像 |
| `proxy` | 上游 SOCKS5 代理,如 `socks5://127.0.0.1:1080` 或 `socks5://user:pass@host:1080` |
仓库规则支持通配符,如 `owner/*`、`*/repo-name`。
## [download]
| 键 | 类型 | 默认值 | 说明 |
|----|------|--------|------|
| `maxImages` | int | `10` | 批量离线镜像数量上限 |
## [registries]
每个 Registry 条目:
| 键 | 说明 |
|----|------|
| `upstream` | 上游 Registry 地址 |
| `authHost` | 认证端点(用于匹配 token 请求) |
| `authType` | 认证类型标识(`anonymous`/`github`/`google`/`quay` |
| `enabled` | 是否启用 |
默认预置 `ghcr.io`、`gcr.io`、`quay.io`、`registry.k8s.io`。Docker Hub 固定走 `registry-1.docker.io`,不在此段配置。
:::note
当前版本对所有 Registry 均使用匿名拉取(`authn.Anonymous``authType` 仅用于标识认证端点类型,**尚未**实现 GitHub Token 或 Google 服务账号等私有仓库凭据。私有镜像仍需客户端自行携带认证。
:::
## [tokenCache]
| 键 | 类型 | 默认值 | 说明 |
|----|------|--------|------|
| `enabled` | bool | `true` | 启用 Token/Manifest 缓存 |
| `defaultTTL` | string | `"20m"` | 普通 tag 的 Manifest 默认缓存时间 |
Manifest 缓存 TTL 规则:
| 条件 | TTL |
|------|-----|
| digest`sha256:...` | 24 小时 |
| `latest` / `main` / `master` / `dev` / `develop` | 10 分钟 |
| 其他 tag | `[tokenCache].defaultTTL` |
上游 token 响应中的 `expires_in` 会用于 token 缓存(预留 5 分钟安全余量,最短 5 分钟)。
## HTTP 端点
| 路径 | 说明 |
|------|------|
| `GET /ready` | 健康检查,返回 `ready`、`version`、`uptime_sec` 等 |
| `GET /api/search?q=...` | Docker Hub 镜像搜索 |
| `GET /api/tags/:namespace/:name` | 镜像标签列表 |
| `GET /api/image/info?image=...` | 镜像元信息 |
| `GET /api/image/download?mode=prepare` | 申请单镜像离线包 token |
| `GET /api/image/download?token=...` | 下载单镜像 tar |
| `POST /api/image/batch?mode=prepare` | 申请批量离线包 token |
| `GET /api/image/batch?token=...` | 下载批量 tar |
| `ANY /v2/*` | Docker Registry API v2 代理 |
| `ANY /token*` | Docker 认证代理 |
| 其他路径 | GitHub / Hugging Face 等 URL 代理 |

View File

@@ -0,0 +1,45 @@
---
title: 推荐部署架构
description: 公网部署 HubProxy 的推荐拓扑与安全要求。
---
公网服务时,推荐始终通过反向代理暴露 HubProxy而不是将 `5000` 端口直接暴露到公网。
## 推荐拓扑
```
用户 → CDN可选→ Caddy/Nginx私网/本机)→ HubProxy:5000
```
| 组件 | 作用 |
|------|------|
| CDN | 可选,提供 TLS 与边缘加速 |
| 反向代理 | 终止 TLS、写入真实客户端 IP、隐藏后端端口 |
| HubProxy | 处理 Docker/GitHub 代理逻辑 |
## 必须满足的条件
1. **反代覆盖写** `X-Forwarded-For` / `X-Real-IP`(不要 append 客户端自带头)
2. **5000 不对公网开放**,仅允许反代访问
3. 公网服务建议配置 `[access].whiteList` 限制可代理的仓库
4. 反代覆盖写 `X-Forwarded-Host`(防止 `.sh` 脚本 Host 注入)
## 各场景对照
| 部署方式 | 每用户独立限流 | IP 防伪造 | 推荐度 |
|---------|---------------|----------|--------|
| CDN → 私网反代 → HubProxy | ✅ | ✅ | ⭐⭐⭐ |
| Docker 内 Caddy + HubProxy | ✅ | ✅ | ⭐⭐⭐ |
| 本机 Nginx → HubProxy | ✅ | ✅ | ⭐⭐⭐ |
| Cloudflare 直连 HubProxy | ❌ 共用 CDN IP | ✅ | ⚠️ |
| 公网直连 `0.0.0.0:5000` | ✅ | ✅ | ⚠️ 开放代理风险 |
## HTTP/3QUIC
Caddy 默认开启 HTTP/3 只影响「用户 → Caddy」段UDP。Caddy 回源 HubProxy 仍使用 TCP当前 IP 信任机制无需额外配置。
## 下一步
- [反向代理配置](/deployment/reverse-proxy/)
- [Docker 部署](/deployment/docker/)
- [安全概述](/security/overview/)

View File

@@ -0,0 +1,57 @@
---
title: Docker 部署
description: 使用 Docker 与 Docker Compose 部署 HubProxy。
---
## docker run
```bash
docker run -d \
--name hubproxy \
-p 5000:5000 \
--restart always \
-v ./src/config.toml:/app/config.toml:ro \
ghcr.io/sky22333/hubproxy
```
## Docker Compose
项目根目录提供 `docker-compose.yml`
```bash
docker compose up -d
```
默认挂载 `./src/config.toml` 到容器内 `/app/config.toml`。Compose 文件内已配置日志轮转(`200m × 3`),无需在 `docker run` 中重复设置。
:::caution
生产环境建议不要将 `5000` 直接映射到公网。更安全的做法是让 Caddy/Nginx 容器访问 HubProxy 内网地址。
:::
## 与反代配合
典型 Compose 结构:
```
caddy: 对外 443反代 hubproxy:5000
hubproxy: 仅内网暴露 5000不映射到宿主机公网
```
## 健康检查
容器镜像未内置 `HEALTHCHECK`,可手动验证:
```bash
curl http://127.0.0.1:5000/ready
```
## Compose 日志(可选)
若使用 Compose可在 `docker-compose.yml` 中配置:
| 参数 | 含义 |
|------|------|
| `max-size=200m` | 单个日志文件上限 |
| `max-file=3` | 保留 3 个文件,总量约 600MB |
`docker run` 未指定时 Docker 默认约 20MB 日志上限。

View File

@@ -0,0 +1,65 @@
---
title: 反向代理
description: 配置 Caddy 与 Nginx 反向代理,正确传递客户端真实 IP。
---
反向代理必须**覆盖写入**真实客户端 IPHubProxy 才能按用户独立限流并防止 IP 伪造。
## Caddy
### 基础反代
```txt
example.com {
reverse_proxy 127.0.0.1:5000 {
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
}
}
```
### Cloudflare CDN
```txt
example.com {
reverse_proxy 127.0.0.1:5000 {
header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
header_up X-Real-IP {http.request.header.CF-Connecting-IP}
header_up X-Forwarded-Proto https
header_up X-Forwarded-Host {host}
}
}
```
## Nginx
:::caution
避免使用 `proxy_add_x_forwarded_for`,它会 append 客户端自带的 `X-Forwarded-For`,可能导致 IP 解析错误。
:::
```nginx
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 $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
```
### GitHub 加速提示「无效输入」
若使用 Nginx 反代后 GitHub 加速异常,请参考 [issue #62](https://github.com/sky22333/hubproxy/issues/62#issuecomment-3219572440) 检查 `proxy_set_header Host` 等配置。
## 工作原理
HubProxy 仅当 TCP 连接来自可信私网/本机网段时,才信任转发头:
- `127.0.0.0/8`
- `10.0.0.0/8`
- `172.16.0.0/12`
- `192.168.0.0/16`
详见 [IP 信任机制](/security/ip-trust/)。

View File

@@ -0,0 +1,46 @@
---
title: Environment Variables
description: Environment variables supported by HubProxy.
---
Environment variables override config after `config.toml` is loaded. Sections not listed here (e.g. `[registries]`, `[tokenCache]`, `[access].whiteList`) can only be changed in the config file.
## All Variables
| Variable | Config key | Description |
|----------|-----------|-------------|
| `CONFIG_PATH` | — | Config file path, default `./config.toml` |
| `SERVER_HOST` | `[server].host` | Listen address |
| `SERVER_PORT` | `[server].port` | Listen port |
| `ENABLE_H2C` | `[server].enableH2C` | Enable HTTP/2 Cleartext (`true`/`false`) |
| `ENABLE_FRONTEND` | `[server].enableFrontend` | Enable web UI (`true`/`false`) |
| `MAX_FILE_SIZE` | `[server].fileSize` | Max single-file size (bytes) |
| `RATE_LIMIT` | `[rateLimit].requestLimit` | Requests per IP per period |
| `RATE_PERIOD_HOURS` | `[rateLimit].periodHours` | Rate limit period (hours) |
| `IP_WHITELIST` | `[security].whiteList` | Append rate-limit exempt IPs, comma-separated |
| `IP_BLACKLIST` | `[security].blackList` | Append blocked IPs, comma-separated |
| `ACCESS_PROXY` | `[access].proxy` | Upstream SOCKS5 proxy URL |
| `MAX_IMAGES` | `[download].maxImages` | Max images per batch offline download |
## Examples
```bash
# systemd / local
CONFIG_PATH=/etc/hubproxy/config.toml ./hubproxy
# Docker quick overrides
docker run -d \
-e SERVER_PORT=5000 \
-e RATE_LIMIT=1000 \
-e IP_WHITELIST=10.0.0.0/8,192.168.1.100 \
-v ./config.toml:/app/config.toml:ro \
ghcr.io/sky22333/hubproxy
```
## Use Cases
| Scenario | Recommendation |
|----------|----------------|
| systemd service | `CONFIG_PATH=/etc/hubproxy/config.toml` (built into service file) |
| Docker | Mount `/app/config.toml`, use `-e` for quick overrides |
| Local development | `CONFIG_PATH=./src/config.toml go run .` |

View File

@@ -0,0 +1,106 @@
---
title: config.toml Reference
description: Complete reference for the HubProxy configuration file.
---
Default config path is `./config.toml` in the working directory. Override with `CONFIG_PATH`. See [Environment Variables](/en/configuration/environment/) for the full env var list.
## [server]
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `host` | string | `0.0.0.0` | Listen address |
| `port` | int | `5000` | Listen port |
| `fileSize` | int | `2147483648` | Max single-file size (bytes), affects GitHub proxy and offline images |
| `enableH2C` | bool | `false` | Enable HTTP/2 Cleartext |
| `enableFrontend` | bool | `true` | Enable web UI (Vue SPA) |
## [rateLimit]
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `requestLimit` | int | `500` | Requests per IP per period |
| `periodHours` | float | `3.0` | Rate limit period (hours) |
IPv4 uses full addresses; IPv6 uses `/64` prefixes. Frontend static routes (`/`, `/images`, `/search`, `/assets/*`) are not rate-limited.
:::note
Pulling one Docker image triggers multiple layer requests — each HTTP request counts against the limit.
:::
## [security]
| Key | Description |
|-----|-------------|
| `whiteList` | Rate-limit exempt IPs (CIDR supported, single IPs auto-get `/32`) |
| `blackList` | Blocked IPs (403) |
:::note
`[security]` lists affect rate limiting only — they do **not** control which registries can be proxied.
:::
## [access]
| Key | Description |
|-----|-------------|
| `whiteList` | Allowed repos/images (empty = no restriction) |
| `blackList` | Blocked repos/images |
| `proxy` | Upstream SOCKS5 proxy, e.g. `socks5://127.0.0.1:1080` or `socks5://user:pass@host:1080` |
Wildcards supported: `owner/*`, `*/repo-name`.
## [download]
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `maxImages` | int | `10` | Max images per batch offline download |
## [registries]
Per-registry keys:
| Key | Description |
|-----|-------------|
| `upstream` | Upstream registry host |
| `authHost` | Auth endpoint (for token request matching) |
| `authType` | Auth type label (`anonymous` / `github` / `google` / `quay`) |
| `enabled` | Enable or disable |
Defaults include `ghcr.io`, `gcr.io`, `quay.io`, `registry.k8s.io`. Docker Hub always proxies to `registry-1.docker.io` and is not configured here.
:::note
All registries currently use anonymous pulls (`authn.Anonymous`). `authType` labels the auth endpoint only — **GitHub tokens and Google service accounts are not yet implemented**. Private images require client-side authentication.
:::
## [tokenCache]
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `enabled` | bool | `true` | Enable token/manifest cache |
| `defaultTTL` | string | `"20m"` | Default manifest cache TTL for ordinary tags |
Manifest cache TTL rules:
| Condition | TTL |
|-----------|-----|
| Digest (`sha256:...`) | 24 hours |
| `latest` / `main` / `master` / `dev` / `develop` | 10 minutes |
| Other tags | `[tokenCache].defaultTTL` |
Upstream token `expires_in` is used for token cache (5-minute safety margin, minimum 5 minutes).
## HTTP Endpoints
| Path | Description |
|------|-------------|
| `GET /ready` | Health check — returns `ready`, `version`, `uptime_sec`, etc. |
| `GET /api/search?q=...` | Docker Hub image search |
| `GET /api/tags/:namespace/:name` | Image tag list |
| `GET /api/image/info?image=...` | Image metadata |
| `GET /api/image/download?mode=prepare` | Request single-image offline token |
| `GET /api/image/download?token=...` | Download single-image tar |
| `POST /api/image/batch?mode=prepare` | Request batch offline token |
| `GET /api/image/batch?token=...` | Download batch tar |
| `ANY /v2/*` | Docker Registry API v2 proxy |
| `ANY /token*` | Docker auth proxy |
| Other paths | GitHub / Hugging Face URL proxy |

View File

@@ -0,0 +1,45 @@
---
title: Recommended Architecture
description: Recommended topology and security requirements for public HubProxy deployments.
---
For public-facing deployments, always expose HubProxy through a reverse proxy instead of publishing port `5000` directly.
## Recommended Topology
```
Users → CDN (optional) → Caddy/Nginx (private/local) → HubProxy:5000
```
| Component | Role |
|-----------|------|
| CDN | Optional TLS termination and edge caching |
| Reverse proxy | TLS, real client IP injection, hide backend port |
| HubProxy | Docker/GitHub proxy logic |
## Requirements
1. Reverse proxy must **overwrite** `X-Forwarded-For` / `X-Real-IP` (never append client-supplied headers)
2. Port **5000 must not be public** — only the reverse proxy should reach it
3. Configure `[access].whiteList` for public services to restrict proxied registries
4. Overwrite `X-Forwarded-Host` to prevent Host injection in `.sh` scripts
## Scenario Comparison
| Deployment | Per-user rate limit | IP spoof protection | Rating |
|------------|--------------------|--------------------|--------|
| CDN → private proxy → HubProxy | ✅ | ✅ | ⭐⭐⭐ |
| Docker Caddy + HubProxy | ✅ | ✅ | ⭐⭐⭐ |
| Local Nginx → HubProxy | ✅ | ✅ | ⭐⭐⭐ |
| Cloudflare direct to HubProxy | ❌ shared CDN IP | ✅ | ⚠️ |
| Public `0.0.0.0:5000` | ✅ | ✅ | ⚠️ open proxy risk |
## HTTP/3 (QUIC)
Caddy's HTTP/3 only affects the user → Caddy segment (UDP). Caddy still uses TCP to reach HubProxy — no extra IP trust configuration needed.
## Next Steps
- [Reverse Proxy](/en/deployment/reverse-proxy/)
- [Docker Deployment](/en/deployment/docker/)
- [Security Overview](/en/security/overview/)

View File

@@ -0,0 +1,57 @@
---
title: Docker Deployment
description: Deploy HubProxy with Docker and Docker Compose.
---
## docker run
```bash
docker run -d \
--name hubproxy \
-p 5000:5000 \
--restart always \
-v ./src/config.toml:/app/config.toml:ro \
ghcr.io/sky22333/hubproxy
```
## Docker Compose
The repository includes `docker-compose.yml`:
```bash
docker compose up -d
```
Mounts `./src/config.toml` to `/app/config.toml`. Log rotation (`200m × 3`) is preconfigured in Compose — no need to duplicate in `docker run`.
:::caution
In production, avoid mapping port 5000 directly to the public internet. Let a Caddy/Nginx container reach HubProxy on the internal network instead.
:::
## With Reverse Proxy
Typical Compose layout:
```
caddy: exposes 443, proxies to hubproxy:5000
hubproxy: internal 5000 only, not mapped to host public interface
```
## Health Check
The image has no built-in `HEALTHCHECK`. Verify manually:
```bash
curl http://127.0.0.1:5000/ready
```
## Compose Logging (Optional)
When using Compose, `docker-compose.yml` configures:
| Option | Meaning |
|--------|---------|
| `max-size=200m` | Max size per log file |
| `max-file=3` | Keep 3 files (~600MB total) |
Without options, `docker run` defaults to ~20MB per log file.

View File

@@ -0,0 +1,65 @@
---
title: Reverse Proxy
description: Configure Caddy and Nginx to pass the real client IP correctly.
---
The reverse proxy must **overwrite** the real client IP so HubProxy can rate-limit per user and resist IP spoofing.
## Caddy
### Basic
```txt
example.com {
reverse_proxy 127.0.0.1:5000 {
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
}
}
```
### Behind Cloudflare
```txt
example.com {
reverse_proxy 127.0.0.1:5000 {
header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
header_up X-Real-IP {http.request.header.CF-Connecting-IP}
header_up X-Forwarded-Proto https
header_up X-Forwarded-Host {host}
}
}
```
## Nginx
:::caution
Avoid `proxy_add_x_forwarded_for` — it appends client-supplied `X-Forwarded-For` and can break IP resolution.
:::
```nginx
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 $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
```
### GitHub acceleration shows "invalid input"
If GitHub acceleration fails behind Nginx, check `proxy_set_header Host` per [issue #62](https://github.com/sky22333/hubproxy/issues/62#issuecomment-3219572440).
## How It Works
HubProxy only trusts forwarding headers when the TCP connection comes from trusted private/local ranges:
- `127.0.0.0/8`
- `10.0.0.0/8`
- `172.16.0.0/12`
- `192.168.0.0/16`
See [IP Trust](/en/security/ip-trust/) for details.

View File

@@ -0,0 +1,92 @@
---
title: FAQ
description: Frequently asked questions about deploying and using HubProxy.
---
<details>
<summary>How is HubProxy different from free CDN proxies?</summary>
HubProxy is fully self-hosted — you control data and bandwidth without relying on unstable third-party CDNs. Customize rate limits, registry allowlists, and upstream SOCKS5 proxies.
</details>
<details>
<summary>Is a reverse proxy required for public deployment?</summary>
Strongly recommended. It provides TLS, correct client IP passing, and avoids exposing port 5000. See [Recommended Architecture](/en/deployment/architecture/).
</details>
<details>
<summary>What's the difference between rate-limit and registry whitelists?</summary>
`[security].whiteList` exempts IPs from rate limiting. `[access].whiteList` controls which Docker images and GitHub repos can be proxied. They are independent.
</details>
<details>
<summary>How do I format GitHub acceleration URLs?</summary>
Prefix the **full original URL** with your HubProxy host, e.g. `https://example.com/https://github.com/owner/repo/releases/download/...`. Path-prefix rewrites like `/github/owner/...` are not supported. See [GitHub Acceleration](/en/guides/github-proxy/).
</details>
<details>
<summary>GitHub acceleration shows 'invalid input'?</summary>
Common causes: wrong URL format (using `/github/` prefix instead of full URL), or incorrect Nginx `Host` header. See [GitHub Acceleration](/en/guides/github-proxy/) and [issue #62](https://github.com/sky22333/hubproxy/issues/62#issuecomment-3219572440).
</details>
<details>
<summary>How does the offline image API work?</summary>
Two steps: `GET /api/image/download?image=...&mode=prepare` for a token, then download with that token. There is no `/v2/offline/...` path. See [Offline Images](/en/guides/offline-images/).
</details>
<details>
<summary>All users share one IP behind Cloudflare?</summary>
If HubProxy connects directly to Cloudflare edges, rate limits apply per Cloudflare IP, not per user. Add a private reverse proxy that writes `CF-Connecting-IP` to forwarding headers.
</details>
<details>
<summary>How do I verify the service is running?</summary>
Visit `https://example.com/ready` — a healthy response includes `ready`, `service`, `version`, and `uptime_sec`.
</details>
<details>
<summary>Docker logs consuming too much disk?</summary>
`docker run` defaults to ~20MB logs. [Docker Compose](/en/deployment/docker/) preconfigures `200m × 3` rotation; adjust `logging.options` in compose as needed.
</details>
<details>
<summary>Does HubProxy support resume or multi-part downloads?</summary>
**GitHub / Hugging Face file downloads: yes.** The proxy forwards `Range` headers and passes through upstream 206 responses — `wget -c` and multi-threaded Range downloads work (except `.sh` / `.ps1` script rewriting).
**Docker pulls: no in-layer Range.** Blobs are streamed whole; clients retry failed layers or pull layers in parallel.
**Offline tar API: no** resume. See [Transfer Capabilities](/en/guides/capabilities/).
</details>
<details>
<summary>How do I add a new acceleration domain?</summary>
Add a regex to `githubExps` in `src/handlers/github.go`. See [Development & Build](/en/guides/development/).
</details>
<details>
<summary>Why can't I pull private images with authType github?</summary>
`authType` labels auth endpoints only — credential injection is not yet implemented. All registry pulls use anonymous auth. Use client-side `docker login` for private images.
</details>

View File

@@ -0,0 +1,56 @@
---
title: System Installation
description: Deploy HubProxy with deb, rpm, or apk packages and manage the service.
---
## Install Script
```bash
curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install.sh | sh
```
Supports `amd64` / `arm64` with `apt`, `dnf`, `apk`, and other package managers.
## File Paths
| Path | Description |
|------|-------------|
| `/etc/hubproxy/config.toml` | Configuration file |
| `/usr/bin/hubproxy` | Binary |
| `/lib/systemd/system/hubproxy.service` | systemd unit (Debian/Ubuntu/RHEL) |
| `/etc/init.d/hubproxy` | OpenRC service (Alpine) |
| `/var/log/hubproxy.log` | Alpine log file |
## systemd
```bash
sudo systemctl status hubproxy # Check service status
sudo systemctl restart hubproxy # Restart after config changes
sudo journalctl -u hubproxy -f # Follow logs
sudo nano /etc/hubproxy/config.toml # Edit config
```
Uninstall:
```bash
sudo apt purge hubproxy # Debian/Ubuntu — remove package and config
```
## OpenRC (Alpine)
```bash
sudo rc-service hubproxy status # Check status
sudo rc-service hubproxy restart # Restart service
sudo tail -f /var/log/hubproxy.log # Follow logs
sudo vi /etc/hubproxy/config.toml # Edit config
```
Uninstall:
```bash
sudo apk del hubproxy # Remove package
```
## Production recommendation
For public or team use, point a **custom domain** at HubProxy through Caddy / Nginx with **HTTPS enabled**, instead of exposing `http://IP:5000` long term. This provides TLS, correct client IP forwarding, and safer access. See [Reverse Proxy](/en/deployment/reverse-proxy/) and [Recommended Architecture](/en/deployment/architecture/).

View File

@@ -0,0 +1,60 @@
---
title: Quick Start
description: Run HubProxy in minutes with Docker or the install script.
---
HubProxy supports Docker images and native package installation.
## Docker (Recommended)
```bash
docker run -d \
--name hubproxy \
-p 5000:5000 \
--restart always \
-v /path/to/config.toml:/app/config.toml:ro \
ghcr.io/sky22333/hubproxy
```
:::tip
[Docker Compose](/en/deployment/docker/) makes config mounting easier; log rotation is preconfigured in Compose.
:::
## Install Script
Auto-detects OS and architecture, downloads `.deb`, `.rpm`, or `.apk` from GitHub Releases:
```bash
curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install.sh | sh
```
The service starts automatically. Config is at `/etc/hubproxy/config.toml`.
## Verify
```bash
curl http://127.0.0.1:5000/ready # Local health check
```
Expected response:
```json
{
"ready": true,
"service": "hubproxy",
"version": "v1.x.x",
"start_time_unix": 1710000000,
"uptime_sec": 42.5,
"uptime_human": "42s"
}
```
## Next Steps
- [System Installation](/en/getting-started/install/)
- [Docker Compose](/en/deployment/docker/)
- [Docker Mirror Guide](/en/guides/docker-mirror/)
## Production recommendation
After verification, set up a **custom domain + reverse proxy + HTTPS** (Caddy / Nginx) so clients use `https://example.com` instead of bare `http://IP:5000`. See [Recommended Architecture](/en/deployment/architecture/) and [Reverse Proxy](/en/deployment/reverse-proxy/).

View File

@@ -0,0 +1,61 @@
---
title: Transfer Capabilities
description: Transfer behavior for Docker pulls and GitHub downloads in HubProxy.
---
Based on current code in `src/handlers/docker.go` and `src/handlers/github.go`.
## Docker Image Pulls
HubProxy fetches manifests and blobs via go-containerregistry, then returns them over HTTP.
| Capability | Supported | Notes |
|------------|-----------|-------|
| Manifest cache | ✅ | GET cached; digest 24h, `latest` etc. 10m |
| Token cache | ✅ | Upstream `expires_in` driven |
| Multi-registry paths | ✅ | e.g. `example.com/ghcr.io/owner/image:tag` |
| containerd `ns` param | ✅ | Matches `[registries]` entries |
| Auth realm rewrite | ✅ | Upstream token → HubProxy `/token` |
| HTTP Range / in-layer resume | ❌ | Blobs always fetched fully; client `Range` ignored |
| Layer-level retry | ✅ | Docker/containerd retries failed layers |
:::note
Each layer costs at least one blob request against rate limits. No Range inside a layer, but clients may pull **different layers** in parallel.
:::
## GitHub / Hugging Face Downloads
The GitHub proxy (`proxyGitHubWithRedirect`) forwards **all client request headers** (including `Range`) upstream and passes through **status codes and response headers** (`Content-Range`, `Accept-Ranges`, etc.) before streaming the body.
| Capability | Supported | Notes |
|------------|-----------|-------|
| Streaming | ✅ | Direct `io.Copy` for normal files |
| HTTP Range / resume | ✅ | `wget -c`, `curl -C -`; 206 responses passed through |
| Multi-connection Range | ✅ | aria2-style parallel chunks (if upstream supports Range) |
| Redirects | ✅ | Max 20; GitHub Location URLs rewritten |
| HTML block | ✅ | `text/html` etc. → 403 |
| File size limit | ✅ | `[server].fileSize`, default 2GB |
| `.sh` / `.ps1` rewrite | ⚠️ | Full download + rewrite + chunked output; **no** Range resume |
### wget resume example
```bash
wget -c "https://example.com/https://github.com/owner/repo/releases/download/v1.0.0/large.bin"
```
See `src/handlers/github.go` lines 113118 (header forward) and 209231 (response pass-through).
## Offline image tar
| Capability | Supported |
|------------|-----------|
| Streaming tar | ✅ |
| One-time token (2 min) | ✅ |
| Range / resume | ❌ |
| `Cache-Control: no-store` | ✅ |
## Related
- [Docker Mirror](/en/guides/docker-mirror/)
- [GitHub Acceleration](/en/guides/github-proxy/)
- [Offline Images](/en/guides/offline-images/)

View File

@@ -0,0 +1,80 @@
---
title: Development & Build
description: Extend acceleration URLs, registry mappings, and build from source.
---
## Layout
```
hubproxy/
├── src/ # Go backend
├── web/ # Vue SPA
├── Dockerfile
└── docs/
```
## Add acceleration URLs
Edit **`githubExps`** in `src/handlers/github.go`:
```go
var githubExps = []*regexp.Regexp{
regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:releases|archive)/.*`),
// add new patterns here
}
```
Requirements:
1. Include `([^/]+)/([^/]+)` capture groups for `[access]` owner/repo matching
2. Run `go test ./handlers/...`
3. Routes use `NoRoute(GitHubProxyHandler)` in `main.go` — no new route needed
Access control: `src/utils/access_control.go` → `CheckGitHubAccess`.
## Add Docker Registry
`config.toml` → `[registries]`. Auth hook: `createUpstreamOptions()` in `src/handlers/docker.go`.
## Add HTTP routes
Register in `buildRouter()` in `src/main.go`.
## Local dev
```bash
cd src && CONFIG_PATH=./config.toml go run .
cd web && npm ci && npm run dev
```
Production embed:
```bash
cd web && npm ci && npm run build
# copy dist to src/dist
cd ../src && go build -o hubproxy .
```
## Docker build
```bash
docker build -t hubproxy:local --build-arg VERSION=1.0.0 .
docker buildx build --platform linux/amd64,linux/arm64 \
-t ghcr.io/your-org/hubproxy:latest \
--build-arg VERSION=1.0.0 --push .
```
| Stage | Image | Role |
|-------|-------|------|
| frontend | node:24-alpine | Vue build |
| builder | golang:1.26-alpine | Go + UPX |
| final | alpine | Runtime |
## Test & release
```bash
cd src && go test ./...
```
CI: `.github/workflows/docker-ghcr.yml`, `release.yml`.

View File

@@ -0,0 +1,80 @@
---
title: Registry Sources
description: Configure upstream registry mappings in HubProxy.
---
HubProxy uses the `[registries]` section for third-party registry upstreams and auth endpoints. Docker Hub always proxies to `registry-1.docker.io` and is not configured here.
## Default Mappings
`config.toml` includes common registries:
```toml
[registries."ghcr.io"]
upstream = "ghcr.io"
authHost = "ghcr.io/token"
authType = "github"
enabled = true
[registries."gcr.io"]
upstream = "gcr.io"
authHost = "gcr.io/v2/token"
authType = "google"
enabled = true
[registries."quay.io"]
upstream = "quay.io"
authHost = "quay.io/v2/auth"
authType = "quay"
enabled = true
[registries."registry.k8s.io"]
upstream = "registry.k8s.io"
authHost = "registry.k8s.io"
authType = "anonymous"
enabled = true
```
## authType Values
| authType | Meaning |
|----------|---------|
| `anonymous` | Anonymous registry (e.g. registry.k8s.io) |
| `github` | GHCR auth endpoint |
| `google` | GCR auth endpoint |
| `quay` | Quay.io auth endpoint |
:::note
`authType` matches upstream token auth endpoints only. The current version does **not** inject GitHub tokens or Google service accounts — all pulls use anonymous auth. Private images require client-side `docker login`.
:::
## Pull Path Format
```bash
# Docker Hub (no registry prefix needed)
docker pull example.com/library/nginx:latest
# Third-party registry
docker pull example.com/ghcr.io/owner/image:tag
```
Also supports containerd `ns` query parameter for configured registries.
## Enable/Disable
```toml
[registries."quay.io"]
enabled = false
```
## Token and Manifest Cache
`[tokenCache]` controls upstream auth token and manifest caching:
```toml
[tokenCache]
enabled = true
defaultTTL = "20m"
```
Digest refs cache for 24 hours; common tags like `latest` cache for 10 minutes. See [config.toml Reference](/en/configuration/reference/#tokencache).

View File

@@ -0,0 +1,66 @@
---
title: Docker Mirror
description: Configure Docker clients to pull images through HubProxy.
---
HubProxy implements Docker Registry API v2 and can accelerate Docker Hub and multiple third-party registries.
## Configure Docker Client
Edit `/etc/docker/daemon.json` (or Docker Desktop settings on Windows):
```json
{
"registry-mirrors": ["https://example.com"]
}
```
Restart Docker:
```bash
sudo systemctl restart docker
```
## Supported Registries
| Registry | Notes |
|----------|-------|
| Docker Hub | Default `registry-1.docker.io`, no path prefix needed |
| ghcr.io | GitHub Container Registry |
| gcr.io | Google Container Registry |
| quay.io | Red Hat Quay |
| registry.k8s.io | Kubernetes official images |
Extend or disable in `[registries]` — see [Registry Sources](/en/guides/docker-mirror-sources/).
## Pull Examples
```bash
# Docker Hub
docker pull example.com/library/nginx:latest
# Third-party registry (path includes registry domain)
docker pull example.com/ghcr.io/owner/image:tag
```
## Image Search
The web UI (`enableFrontend = true`) provides Docker Hub search and tag browsing. API access:
```bash
curl "https://example.com/api/search?q=nginx"
curl "https://example.com/api/tags/library/nginx"
```
## Notes
- Each layer counts against rate limits
- Configure `[access].whiteList` for public deployments
- Ensure correct client IP behind reverse proxy — see [Reverse Proxy](/en/deployment/reverse-proxy/)
- Anonymous upstream pulls; private images need client-side `docker login`
## Other environments
- [Kubernetes & containerd](/en/guides/kubernetes-containerd/)
- [Synology / Feiniu NAS](/en/guides/nas/)
- [Transfer capabilities](/en/guides/capabilities/)

View File

@@ -0,0 +1,77 @@
---
title: GitHub Acceleration
description: Accelerate GitHub Release, Raw, Clone, API, and Hugging Face downloads with HubProxy.
---
HubProxy forwards unmatched routes to its GitHub proxy handler, which relays the **full original URL** to GitHub, Hugging Face, and other upstreams.
## How to Accelerate
Prefix your original URL with the HubProxy host. Two formats are supported.
### Full URL (Recommended)
```bash
# Release download
curl -L -O "https://example.com/https://github.com/owner/repo/releases/download/v1.0.0/app.tar.gz"
# Git clone
git clone https://example.com/https://github.com/owner/repo.git
# API
curl "https://example.com/https://api.github.com/repos/owner/repo/releases/latest"
```
### Omit `https://`
HubProxy auto-prepends the scheme:
```bash
curl -L -O "https://example.com/github.com/owner/repo/releases/download/v1.0.0/app.tar.gz"
```
:::caution
**Not supported:** path-prefix rewrites like `https://example.com/github/owner/repo/...` or `/raw/owner/...` — these return "invalid input".
:::
## Supported URL Types
| Type | Path pattern |
|------|-------------|
| Release / Archive | `github.com/{owner}/{repo}/releases/...`, `/archive/...` |
| Raw / Blob | `github.com/{owner}/{repo}/raw/...` (`/blob/` auto-converted to `/raw/`) |
| Git protocol | `github.com/{owner}/{repo}/info/...`, `/git-...` |
| Raw domains | `raw.githubusercontent.com/...`, `raw.github.com/...` |
| API | `api.github.com/repos/{owner}/{repo}/...` |
| Gist | `gist.github.com/...`, `gist.githubusercontent.com/...` |
| Hugging Face | `huggingface.co/...`, `cdn-lfs.hf.co/...` |
| GitHub Assets | `github.githubassets.com/...`, `opengraph.githubassets.com/...` |
## Script Nesting
HubProxy can rewrite GitHub URLs inside `.sh` / `.ps1` install scripts (max 10MB). Behind a reverse proxy, set `X-Forwarded-Host` correctly — see [Reverse Proxy](/en/deployment/reverse-proxy/).
## Limits and Blocks
| Limit | Description |
|-------|-------------|
| Web content | `text/html`, `application/xml`, etc. are blocked (403) — not for browsing GitHub pages |
| File size | `[server].fileSize` caps single-file downloads (default 2GB) |
| Repo access | `[access].whiteList` / `blackList` restrict proxied GitHub repos |
Large Release files support `wget -c` resume — see [Transfer Capabilities](/en/guides/capabilities/).
```toml
[server]
fileSize = 2147483648
[access]
whiteList = ["trusted-org/*"]
blackList = ["*/malicious-repo"]
```
## Related
- [Hugging Face Acceleration](/en/guides/huggingface/)
- [Transfer capabilities](/en/guides/capabilities/)
- [Development: add new URLs](/en/guides/development/)

View File

@@ -0,0 +1,45 @@
---
title: Hugging Face Acceleration
description: Accelerate Hugging Face model and LFS downloads through HubProxy.
---
Hugging Face uses the same URL-prefix proxy as GitHub — prepend your HubProxy host to the **full original URL**.
## Supported URLs
| Type | Example |
|------|---------|
| Model / dataset files | `huggingface.co/{user}/{repo}/resolve/...` |
| Spaces | `huggingface.co/spaces/{user}/{repo}/...` |
| LFS CDN | `cdn-lfs.hf.co/{user}/{repo}/...` |
Regex patterns are in `githubExps` in `src/handlers/github.go`.
## Examples
```bash
curl -L -O "https://example.com/https://huggingface.co/bert-base-uncased/resolve/main/config.json"
curl -L -O "https://example.com/huggingface.co/bert-base-uncased/resolve/main/pytorch_model.bin"
curl -L -O "https://example.com/https://cdn-lfs.hf.co/user/model-repo/abc123..."
```
## Python / huggingface_hub
Replace original HF URLs with:
```
https://example.com/https://huggingface.co/...
```
Ensure paths match Hugging Face regexes in `githubExps`.
## Limits
Same as [GitHub Acceleration](/en/guides/github-proxy/):
- No HTML browsing
- `[server].fileSize` cap
- Same as GitHub: **supports** `Range` resume and multi-connection downloads — see [Transfer Capabilities](/en/guides/capabilities/)
- `[access]` allow/deny lists apply

View File

@@ -0,0 +1,83 @@
---
title: Kubernetes & containerd
description: Configure HubProxy as a registry mirror for K3s, RKE2, and containerd.
---
Kubernetes nodes typically pull images via **containerd**, not Docker `daemon.json`.
## K3s
Create `/etc/rancher/k3s/registries.yaml` on each node:
```yaml
mirrors:
docker.io:
endpoint:
- "https://example.com"
"ghcr.io":
endpoint:
- "https://example.com"
"quay.io":
endpoint:
- "https://example.com"
"registry.k8s.io":
endpoint:
- "https://example.com"
```
Restart:
```bash
sudo systemctl restart k3s # server
sudo systemctl restart k3s-agent # agent
```
Verify with **crictl** (mirrors don't apply to `ctr`):
```bash
sudo crictl pull docker.io/library/nginx:latest
```
## RKE2
Use `/etc/rancher/rke2/registries.yaml`, same format. Restart `rke2-server` or `rke2-agent`.
## Native containerd (1.5+)
```bash
sudo mkdir -p /etc/containerd/certs.d/docker.io
```
`/etc/containerd/certs.d/docker.io/hosts.toml`:
```toml
server = "https://registry-1.docker.io"
[host."https://example.com"]
capabilities = ["pull", "resolve"]
```
GHCR: `/etc/containerd/certs.d/ghcr.io/hosts.toml` with `server = "https://ghcr.io"`.
Enable in `/etc/containerd/config.toml`:
```toml
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
```
```bash
sudo systemctl restart containerd
```
## Path notes
- docker.io → `/v2/library/nginx/...`
- ghcr.io → `/v2/ghcr.io/owner/image/...`
- containerd `ns` query param supported
## Notes
- Configure every node; use HTTPS in production
- Private images need `imagePullSecrets`; HubProxy pulls upstream anonymously
- See [Transfer Capabilities](/en/guides/capabilities/)

View File

@@ -0,0 +1,68 @@
---
title: NAS Configuration
description: Configure HubProxy on Synology DSM and Feiniu fnOS.
---
Do **not** overwrite entire `daemon.json` with scripts — you may lose `data-root` and break existing containers.
Assumes HubProxy is exposed at `https://example.com` via reverse proxy.
## Synology DSM (Container Manager)
DSM 7.2+ renamed Docker to **Container Manager**.
### UI (Recommended)
1. **Container Manager** → **Registry** → **Settings**
2. Select **Docker Hub** → **Edit**
3. Enable **Registry mirror**, enter `https://example.com`
4. Save and restart Docker engine
### SSH (dockerd.json)
:::caution
Back up first. **Keep** `data-root`, `storage-driver`, etc. — only change `registry-mirrors`.
:::
DSM ≤7.2: `/var/packages/Docker/etc/dockerd.json`
DSM 7.3+: `/var/packages/ContainerManager/etc/dockerd.json`
```json
"registry-mirrors": ["https://example.com"]
```
Restart:
```bash
sudo systemctl restart pkgctl-Docker # DSM ≤7.2
sudo systemctl restart pkg-ContainerManager-dockerd # DSM 7.3+
```
Verify: `sudo docker info | grep -A3 "Registry Mirrors"`
---
## Feiniu fnOS
Official guidance: **do not** edit `/etc/docker/daemon.json` directly with third-party scripts — it contains `data-root`; clearing it can make images/containers disappear.
### Web UI (Recommended)
1. **Docker** → **Image Registry** → **Registry Settings** / **Mirror Settings**
2. **Add URL**: `https://example.com`
3. Move to **top** of list, save, **restart Docker**
### Manual edit (Advanced)
Back up first; only append to `registry-mirrors`, keep `data-root`, restart Docker.
### Notes
- App Center apps may use fixed registries (e.g. Aliyun) unrelated to HubProxy
- Restart Docker after changes
## Related
- [Docker Mirror](/en/guides/docker-mirror/)
- [Reverse Proxy](/en/deployment/reverse-proxy/)

View File

@@ -0,0 +1,84 @@
---
title: Offline Images
description: Package Docker images as tar files online, with single and batch download.
---
HubProxy's web UI (`enableFrontend = true`) and API package images as tar archives without a local Docker daemon.
Downloads use a **two-step flow**: `prepare` for a one-time token, then download with that token. Tokens expire in **2 minutes** and are bound to client IP and User-Agent.
## Web UI
Visit the HubProxy homepage and use the offline image feature.
## Single Image API
**Step 1: Prepare**
```bash
curl "https://example.com/api/image/download?image=library/nginx:latest&mode=prepare"
```
Response:
```json
{
"download_url": "/api/image/download?image=library/nginx%3Alatest&token=..."
}
```
**Step 2: Download tar**
```bash
curl -L -o nginx.tar "https://example.com/api/image/download?image=library/nginx:latest&token=YOUR_TOKEN"
```
Optional parameters:
| Param | Description |
|-------|-------------|
| `platform` | Target platform, e.g. `linux/amd64` |
| `tag` | Used when image has no tag, default `latest` |
| `compressed` | Compress layers, default `true` |
## Batch API
**Step 1: Prepare**
```bash
curl -X POST "https://example.com/api/image/batch?mode=prepare" \
-H "Content-Type: application/json" \
-d '{"images":["nginx:latest","redis:alpine"]}'
```
**Step 2: Download combined tar**
```bash
curl -L -o batch.tar "https://example.com/api/image/batch?token=YOUR_TOKEN"
```
## Image Info
```bash
curl "https://example.com/api/image/info?image=library/nginx:latest"
```
## Limits
| Config / Rule | Default | Description |
|--------------|---------|-------------|
| `[download].maxImages` | `10` | Max images per batch |
| Prepare debounce (single) | 5s | Repeated prepare returns 429 |
| Prepare debounce (batch) | 60s | Same for batch |
| Token TTL | 2 min | Invalid if expired or IP/UA mismatch |
```toml
[download]
maxImages = 10
```
## Notes
- Large images take longer; streamed downloads must restart if interrupted
- Subject to `[access]` lists and IP rate limiting
- `/ready` and frontend static pages are not rate-limited; API and proxy requests are

View File

@@ -0,0 +1,49 @@
---
title: HubProxy Docs
description: Official documentation for the Docker and GitHub acceleration proxy.
template: splash
hero:
tagline: Lightweight, self-hosted multi-service acceleration proxy
image:
file: ../../../assets/hero.svg
actions:
- text: Quick Start
link: /en/getting-started/quick-start/
icon: right-arrow
- text: GitHub
link: https://github.com/sky22333/hubproxy
icon: external
variant: minimal
---
import { Card, CardGrid } from '@astrojs/starlight/components'
## Core Features
<CardGrid stagger>
<Card title="Docker Mirror" icon="rocket">
Accelerate Docker Hub, GHCR, Quay, GCR, registry.k8s.io and other Registry API v2 registries.
</Card>
<Card title="GitHub Acceleration" icon="document">
Prefix the full original URL with your HubProxy host to accelerate Release, Raw, Clone, API, and Hugging Face downloads.
</Card>
<Card title="Offline Images" icon="seti:docker">
Package images as tar archives online, with single and batch download support.
</Card>
<Card title="Image Search" icon="magnifier">
Built-in Docker Hub image search and tag browsing.
</Card>
<Card title="Smart Rate Limiting" icon="warning">
Per-client IP rate limiting with allow/deny lists and registry access control.
</Card>
<Card title="Fully Self-Hosted" icon="approve-check">
Single-binary deployment with no dependency on third-party free CDN proxies.
</Card>
</CardGrid>
## Recommended Reading
- For public deployments: [Recommended Architecture](/en/deployment/architecture/) and [Reverse Proxy](/en/deployment/reverse-proxy/)
- K8s / NAS: [Kubernetes & containerd](/en/guides/kubernetes-containerd/), [NAS Configuration](/en/guides/nas/)
- Capabilities: [Transfer Capabilities](/en/guides/capabilities/); extending: [Development & Build](/en/guides/development/)
- [config.toml Reference](/en/configuration/reference/)

View File

@@ -0,0 +1,50 @@
---
title: IP Trust
description: How HubProxy identifies real client IPs and prevents spoofing.
---
HubProxy uses Gin's `ClientIP()` with trusted proxy CIDRs to decide when to trust forwarding headers.
## Trusted Proxy CIDRs
Forwarding headers are only read when the TCP connection originates from:
- `127.0.0.0/8` (loopback)
- `10.0.0.0/8` (private Class A)
- `172.16.0.0/12` (private Class B)
- `192.168.0.0/16` (private Class C)
Direct public connections **never** trust forwarding headers.
## Rate Limit Keys
| Protocol | Key |
|----------|-----|
| IPv4 | Full IP address |
| IPv6 | `/64` prefix |
At most 10,000 IP entries are cached in memory.
## `[security].whiteList` vs IP Protection
`[security].whiteList` is a **rate-limit exemption** list, not an access control list:
- Whitelisted IPs skip `[rateLimit]`
- Independent from IP spoof protection and `[access]` registry control
## Correct Proxy Headers
The proxy must **overwrite** (not append) client IP:
```nginx
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
```
See [Reverse Proxy](/en/deployment/reverse-proxy/).
## Cloudflare
When users reach your proxy via Cloudflare, the reverse proxy should read `CF-Connecting-IP` and write it to forwarding headers.
HubProxy does **not** ship a Cloudflare IP trust list — it relies on the private-side proxy writing the correct IP.

View File

@@ -0,0 +1,41 @@
---
title: Security Overview
description: HubProxy security model, risks, and best practices.
---
HubProxy is an open proxy service — improper deployment creates abuse risk. Follow these practices to reduce exposure.
## Core Mechanisms
| Mechanism | Description |
|-----------|-------------|
| IP rate limiting | Per real client IP (IPv6 uses `/64`) |
| IP allow/deny | `[security]` controls rate-limit exemption and blocking |
| Repo access control | `[access]` restricts proxied images and GitHub repos |
| Trusted proxies | Forward headers trusted only from private/local networks |
| File size limit | `[server].fileSize` prevents oversized file abuse |
| Offline download tokens | One-time tokens bound to IP and User-Agent, 2-minute TTL |
## Not Built In
HubProxy has **no** admin login, Basic Auth, API keys, or Prometheus `/metrics`. The web UI is a public SPA — security relies on network placement and configuration.
## Main Risks
1. **Open proxy**: Public `0.0.0.0:5000` without `[access].whiteList` lets anyone use your bandwidth
2. **IP spoofing**: Reverse proxy that appends instead of overwriting `X-Forwarded-For` bypasses rate limits
3. **Host injection**: Missing `X-Forwarded-Host` causes incorrect URLs in rewritten `.sh` scripts
## Recommendations
- Use [Recommended Architecture](/en/deployment/architecture/): CDN (optional) → reverse proxy → HubProxy
- Configure `[access].whiteList` for public services
- Overwrite `X-Forwarded-For`, `X-Real-IP`, and `X-Forwarded-Host` at the proxy
- Do not expose port 5000 to the public internet
- Review `[access].blackList` and access logs regularly
## Related Docs
- [IP Trust](/en/security/ip-trust/)
- [Reverse Proxy](/en/deployment/reverse-proxy/)
- [config.toml Reference](/en/configuration/reference/)

View File

@@ -0,0 +1,92 @@
---
title: 常见问题
description: HubProxy 部署与使用中的常见问题解答。
---
<details>
<summary>HubProxy 和免费 CDN 代理有什么区别?</summary>
HubProxy 是完全自托管的代理服务,数据与带宽由你自己控制,不依赖第三方免费 CDN 的不稳定性。你可以自定义限流、仓库白名单和上游 SOCKS5 代理。
</details>
<details>
<summary>公网部署必须配置反向代理吗?</summary>
强烈建议。反代提供 TLS 终止、正确传递客户端 IP并避免将 5000 端口直接暴露。详见 [推荐部署架构](/deployment/architecture/)。
</details>
<details>
<summary>限流白名单和仓库白名单有什么区别?</summary>
`[security].whiteList` 是限流豁免 IP不影响可代理的仓库。`[access].whiteList` 控制允许代理哪些 Docker 镜像和 GitHub 仓库。两者独立配置。
</details>
<details>
<summary>GitHub 加速链接怎么写?</summary>
在**完整原始 URL** 前加上 HubProxy 域名,例如 `https://example.com/https://github.com/owner/repo/releases/download/...`。不支持 `/github/owner/...` 路径替换写法。详见 [GitHub 加速](/guides/github-proxy/)。
</details>
<details>
<summary>GitHub 加速提示「无效输入」?</summary>
常见原因URL 格式错误(使用了 `/github/` 前缀而非完整 URL或 Nginx 反代未正确设置 `Host` 头。参考 [GitHub 加速](/guides/github-proxy/) 与 [issue #62](https://github.com/sky22333/hubproxy/issues/62#issuecomment-3219572440)。
</details>
<details>
<summary>离线镜像 API 怎么用?</summary>
需两步:先 `GET /api/image/download?image=...&mode=prepare` 获取 token再携带 token 下载。不存在 `/v2/offline/...` 路径。详见 [离线镜像包](/guides/offline-images/)。
</details>
<details>
<summary>使用 Cloudflare 后所有用户共用一个 IP 怎么办?</summary>
若 HubProxy 直连 Cloudflare 边缘节点,限流会按 Cloudflare IP 计数,无法区分用户。正确做法是在 Cloudflare 后面加一层私网反代,由反代写入 `CF-Connecting-IP`。
</details>
<details>
<summary>如何验证服务是否正常?</summary>
访问 `https://example.com/ready`,正常时返回 `{"ready":true,"service":"hubproxy",...}`,包含 `version` 与 `uptime_sec` 字段。
</details>
<details>
<summary>Docker 日志占用磁盘过大?</summary>
`docker run` 默认日志约 20MB。若使用 [Docker Compose](/deployment/docker/),已在 compose 文件中配置 `200m × 3` 日志轮转;也可自行在 compose 中调整 `logging.options`。
</details>
<details>
<summary>支持断点续传或多线程分片下载吗?</summary>
**GitHub / Hugging Face 文件下载:支持。** 代理会透传 `Range` 请求头并将上游 206 响应原样返回,`wget -c`、多线程 Range 分片均可使用(`.sh` / `.ps1` 脚本改写除外)。
**Docker 镜像拉取:不支持 layer 内 Range。** blob 整层转发,但客户端可重试失败 layer 或并行拉取不同 layer。
**离线 tar API不支持**断点续传。详见 [传输特性](/guides/capabilities/)。
</details>
<details>
<summary>如何添加新的加速域名?</summary>
在 `src/handlers/github.go` 的 `githubExps` 数组中添加正则表达式,详见 [二次开发与构建](/guides/development/)。
</details>
<details>
<summary>authType 配置了 GitHub Token 为什么私有镜像仍拉不下来?</summary>
当前版本 `authType` 仅标识认证端点类型,尚未实现凭据注入,所有 Registry 均使用匿名拉取。私有镜像需客户端自行 `docker login` 后在请求中携带认证信息。
</details>

View File

@@ -0,0 +1,56 @@
---
title: 系统安装
description: 使用 deb、rpm、apk 安装包部署 HubProxy以及服务管理命令。
---
## 安装脚本
```bash
curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install.sh | sh
```
脚本会自动识别 `amd64` / `arm64` 与 `apt`、`dnf`、`apk` 等包管理器。
## 文件路径
| 路径 | 说明 |
|------|------|
| `/etc/hubproxy/config.toml` | 配置文件 |
| `/usr/bin/hubproxy` | 二进制文件 |
| `/lib/systemd/system/hubproxy.service` | systemd 服务Debian/Ubuntu/RHEL 等) |
| `/etc/init.d/hubproxy` | OpenRC 服务Alpine |
| `/var/log/hubproxy.log` | Alpine 日志文件 |
## systemd 管理
```bash
sudo systemctl status hubproxy # 查看运行状态
sudo systemctl restart hubproxy # 修改配置后重启
sudo journalctl -u hubproxy -f # 实时查看日志
sudo nano /etc/hubproxy/config.toml # 编辑配置
```
卸载:
```bash
sudo apt purge hubproxy # Debian/Ubuntu 卸载并清除配置
```
## OpenRC 管理Alpine
```bash
sudo rc-service hubproxy status # 查看状态
sudo rc-service hubproxy restart # 重启服务
sudo tail -f /var/log/hubproxy.log # 查看日志
sudo vi /etc/hubproxy/config.toml # 编辑配置
```
卸载:
```bash
sudo apk del hubproxy # 删除安装包
```
## 生产环境建议
公网或团队使用时,建议为 HubProxy 绑定**自有域名**,通过 Caddy / Nginx 等反向代理并**开启 HTTPS**,而不是长期直接暴露 `http://IP:5000`。这样可同时获得 TLS、正确的客户端 IP 传递与更安全的访问控制。配置示例见 [反向代理](/deployment/reverse-proxy/) 与 [推荐部署架构](/deployment/architecture/)。

View File

@@ -0,0 +1,60 @@
---
title: 快速开始
description: 使用 Docker 或安装脚本在数分钟内运行 HubProxy。
---
HubProxy 提供 Docker 镜像与系统安装包两种主流部署方式。
## Docker 部署(推荐)
```bash
docker run -d \
--name hubproxy \
-p 5000:5000 \
--restart always \
-v /path/to/config.toml:/app/config.toml:ro \
ghcr.io/sky22333/hubproxy
```
:::tip
使用 [Docker Compose](/deployment/docker/) 可更方便地挂载配置文件;日志轮转已在 Compose 文件中预置。
:::
## 脚本安装
自动识别系统与架构,从 GitHub Releases 下载 `.deb`、`.rpm` 或 `.apk`
```bash
curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install.sh | sh
```
安装完成后服务会自动启动,配置文件位于 `/etc/hubproxy/config.toml`。
## 验证服务
```bash
curl http://127.0.0.1:5000/ready # 本地健康检查
```
正常响应示例:
```json
{
"ready": true,
"service": "hubproxy",
"version": "v1.x.x",
"start_time_unix": 1710000000,
"uptime_sec": 42.5,
"uptime_human": "42秒"
}
```
## 下一步
- [系统安装与服务管理](/getting-started/install/)
- [Docker Compose 部署](/deployment/docker/)
- [Docker 镜像加速用法](/guides/docker-mirror/)
## 生产环境建议
验证通过后,建议尽快为 HubProxy 配置**自有域名 + 反向代理 + HTTPS**(如 Caddy / Nginx客户端通过 `https://example.com` 访问,而不是长期使用裸 `http://IP:5000`。详见 [推荐部署架构](/deployment/architecture/) 与 [反向代理配置](/deployment/reverse-proxy/)。

View File

@@ -0,0 +1,68 @@
---
title: 传输特性
description: HubProxy 在 Docker 拉取与 GitHub 下载场景下的能力边界说明。
---
本文基于当前代码实现(`src/handlers/docker.go`、`src/handlers/github.go`),说明各场景的传输行为。
## Docker 镜像拉取
HubProxy 通过 go-containerregistry 向上游拉取 manifest 与 blob再以 HTTP 响应形式返回客户端。
| 能力 | 支持 | 说明 |
|------|------|------|
| Manifest 缓存 | ✅ | GET manifest 可缓存digest 24h`latest` 等 10 分钟 |
| Token 缓存 | ✅ | 上游 `expires_in` 驱动 |
| 多 Registry 路径 | ✅ | 如 `example.com/ghcr.io/owner/image:tag` |
| containerd `ns` 参数 | ✅ | 识别 `[registries]` 中的 registry |
| 认证 realm 改写 | ✅ | 上游 token 地址改写到 HubProxy `/token` |
| HTTP Range / layer 内续传 | ❌ | blob 始终整层读取后转发,不读取客户端 `Range` |
| layer 级重试 | ✅ | Docker/containerd 拉取失败会重试整个 layer |
:::note
每个 layer 对应至少一次 blob 请求,均计入 IP 限流。HubProxy 对 blob **不做** Range 分片,但客户端可并行拉取**不同 layer**(多连接)。
:::
### 与标准 Registry 的差异
- blob 非透明透传,由 HubProxy 从上游完整拉取后再 `io.Copy` 转发
- 不支持 PATCH/PUT 上传(仅拉取)
- HEAD / GET manifest 支持
## GitHub / Hugging Face 下载
GitHub 代理(`proxyGitHubWithRedirect`)会将客户端**全部请求头**(含 `Range`)转发上游,并将上游**状态码与响应头**(含 `Content-Range`、`Accept-Ranges`)原样返回,再流式转发 body。
| 能力 | 支持 | 说明 |
|------|------|------|
| 流式转发 | ✅ | 普通文件直接 `io.Copy` |
| HTTP Range / 断点续传 | ✅ | `wget -c`、`curl -C -` 可用;上游返回 206 时原样透传 |
| 多连接 Range 分片 | ✅ | aria2 等多线程分片下载可用(依赖上游支持 Range |
| 重定向跟随 | ✅ | 最多 20 次GitHub URL 的 Location 自动改写 |
| 网页类型拦截 | ✅ | `text/html` 等返回 403 |
| 文件大小限制 | ✅ | `[server].fileSize`,默认 2GB按响应头 `Content-Length` 校验) |
| `.sh` / `.ps1` 脚本改写 | ⚠️ | 脚本会完整下载并改写内容后 chunked 输出,**不支持** Range 续传 |
### wget 断点续传示例
```bash
# 首次下载(中断后可续传)
wget -c "https://example.com/https://github.com/owner/repo/releases/download/v1.0.0/large.bin"
```
实现位置:`src/handlers/github.go` 第 113118 行(转发请求头)、第 209231 行(透传响应)。
## 离线镜像 tar
| 能力 | 支持 |
|------|------|
| 流式打包 tar | ✅ |
| 一次性 token2 分钟) | ✅ |
| Range / 断点续传 | ❌ |
| `Cache-Control: no-store` | ✅ |
## 相关文档
- [Docker 镜像加速](/guides/docker-mirror/)
- [GitHub 加速](/guides/github-proxy/)
- [离线镜像包](/guides/offline-images/)

View File

@@ -0,0 +1,81 @@
---
title: 二次开发与构建
description: 扩展加速域名、Registry 映射,以及从源码构建 HubProxy。
---
## 项目结构
```
hubproxy/
├── src/ # Go 后端main.go、handlers、config、utils
├── web/ # Vue 前端 SPA
├── Dockerfile # 多阶段构建
└── docs/ # 文档站
```
## 增加加速 URL
GitHub / Hugging Face 等 URL 前缀代理由 `src/handlers/github.go` 的 **`githubExps`** 控制:
```go
var githubExps = []*regexp.Regexp{
regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:releases|archive)/.*`),
// 在此追加新正则
}
```
要求:
1. 正则需含 `([^/]+)/([^/]+)` 捕获组,供 `[access]` 匹配 owner/repo
2. 运行 `go test ./handlers/...`
3. 路由已在 `main.go` 的 `NoRoute(GitHubProxyHandler)` 注册,新域名无需加路由
访问控制逻辑:`src/utils/access_control.go` → `CheckGitHubAccess`。
## 增加 Docker Registry
`config.toml` → `[registries]`,认证扩展点在 `src/handlers/docker.go` → `createUpstreamOptions()`。
## 增加 HTTP 路由
在 `src/main.go` → `buildRouter()` 注册。
## 本地开发
```bash
cd src && CONFIG_PATH=./config.toml go run .
cd web && npm ci && npm run dev
```
生产嵌入前端:
```bash
cd web && npm ci && npm run build
# 将 dist 复制到 src/dist
cd ../src && go build -o hubproxy .
```
## Docker 构建
```bash
docker build -t hubproxy:local --build-arg VERSION=1.0.0 .
docker buildx build --platform linux/amd64,linux/arm64 \
-t ghcr.io/your-org/hubproxy:latest \
--build-arg VERSION=1.0.0 --push .
```
| 阶段 | 镜像 | 作用 |
|------|------|------|
| frontend | node:24-alpine | 构建 Vue |
| builder | golang:1.26-alpine | 编译 + UPX |
| final | alpine | 运行时 |
## 测试与发布
```bash
cd src && go test ./...
```
CI`.github/workflows/docker-ghcr.yml`(镜像)、`release.yml`(安装包)。

View File

@@ -0,0 +1,80 @@
---
title: Docker 镜像源
description: 在 HubProxy 中配置上游 Registry 映射。
---
HubProxy 通过 `[registries]` 段配置第三方 Registry 的上游地址与认证端点。Docker Hub 固定代理到 `registry-1.docker.io`,无需在此段配置。
## 默认 Registry 映射
`config.toml` 中预置了常用 Registry
```toml
[registries."ghcr.io"]
upstream = "ghcr.io"
authHost = "ghcr.io/token"
authType = "github"
enabled = true
[registries."gcr.io"]
upstream = "gcr.io"
authHost = "gcr.io/v2/token"
authType = "google"
enabled = true
[registries."quay.io"]
upstream = "quay.io"
authHost = "quay.io/v2/auth"
authType = "quay"
enabled = true
[registries."registry.k8s.io"]
upstream = "registry.k8s.io"
authHost = "registry.k8s.io"
authType = "anonymous"
enabled = true
```
## authType 说明
| authType | 含义 |
|----------|------|
| `anonymous` | 匿名 Registry如 registry.k8s.io |
| `github` | GHCR 认证端点 |
| `google` | GCR 认证端点 |
| `quay` | Quay.io 认证端点 |
:::note
`authType` 用于匹配上游 token 认证地址,当前版本**不会**据此注入 GitHub Token 或 Google 服务账号。所有 Registry 拉取均使用匿名认证;拉取私有镜像需客户端自行提供 `docker login` 凭据。
:::
## 拉取路径格式
```bash
# Docker Hub无需前缀 registry 域名)
docker pull example.com/library/nginx:latest
# 第三方 Registry
docker pull example.com/ghcr.io/owner/image:tag
```
也支持 containerd 的 `ns` 查询参数识别已配置的 Registry。
## 启用/禁用 Registry
```toml
[registries."quay.io"]
enabled = false
```
## Token 与 Manifest 缓存
`[tokenCache]` 段控制上游认证 Token 与 Manifest 缓存:
```toml
[tokenCache]
enabled = true
defaultTTL = "20m"
```
digest 引用缓存 24 小时,`latest` 等常用 tag 缓存 10 分钟,详见 [config.toml 参考](/configuration/reference/#tokencache)。

View File

@@ -0,0 +1,66 @@
---
title: Docker 镜像加速
description: 配置 Docker 客户端使用 HubProxy 加速镜像拉取。
---
HubProxy 兼容 Docker Registry API v2可作为 Docker Hub 及多种第三方 Registry 的镜像加速入口。
## 配置 Docker 客户端
编辑 `/etc/docker/daemon.json`Windows 为 Docker Desktop 设置):
```json
{
"registry-mirrors": ["https://example.com"]
}
```
重启 Docker
```bash
sudo systemctl restart docker
```
## 支持的 Registry
| Registry | 说明 |
|----------|------|
| Docker Hub | 默认 `registry-1.docker.io`,无需路径前缀 |
| ghcr.io | GitHub Container Registry |
| gcr.io | Google Container Registry |
| quay.io | Red Hat Quay |
| registry.k8s.io | Kubernetes 官方镜像 |
可在 `config.toml` 的 `[registries]` 中扩展或禁用,详见 [Docker 镜像源配置](/guides/docker-mirror-sources/)。
## 拉取示例
```bash
# Docker Hub
docker pull example.com/library/nginx:latest
# 第三方 Registry路径含 registry 域名)
docker pull example.com/ghcr.io/owner/image:tag
```
## 镜像搜索
Web 界面(`enableFrontend = true`)提供 Docker Hub 搜索与标签浏览,也可直接调用 API
```bash
curl "https://example.com/api/search?q=nginx"
curl "https://example.com/api/tags/library/nginx"
```
## 注意事项
- 拉取一个镜像会请求多个 layer每个 HTTP 请求均计入 IP 限流配额
- 公网服务建议配置 `[access].whiteList` 限制可代理的镜像
- 配合反向代理时确保正确传递客户端 IP详见 [反向代理配置](/deployment/reverse-proxy/)
- 当前版本对 Registry 使用匿名拉取,私有镜像需客户端自行 `docker login`
## 其他环境
- [Kubernetes 与 containerd](/guides/kubernetes-containerd/)
- [群晖 / 飞牛 NAS](/guides/nas/)
- [传输特性Range 续传、layer 拉取)](/guides/capabilities/)

View File

@@ -0,0 +1,77 @@
---
title: GitHub 加速
description: 使用 HubProxy 加速 GitHub Release、Raw、Clone、API 与 Hugging Face 下载。
---
HubProxy 将未匹配其他路由的请求交给 GitHub 代理处理器,把**完整原始 URL** 转发到 GitHub、Hugging Face 等上游。
## 加速方式
在原始 URL 前加上 HubProxy 域名,支持两种写法。
### 完整 URL推荐
```bash
# Release 下载
curl -L -O "https://example.com/https://github.com/owner/repo/releases/download/v1.0.0/app.tar.gz"
# Git Clone
git clone https://example.com/https://github.com/owner/repo.git
# API
curl "https://example.com/https://api.github.com/repos/owner/repo/releases/latest"
```
### 省略 `https://`
HubProxy 会自动补全协议头:
```bash
curl -L -O "https://example.com/github.com/owner/repo/releases/download/v1.0.0/app.tar.gz"
```
:::caution
**不支持**将域名替换为路径前缀的写法,例如 `https://example.com/github/owner/repo/...` 或 `/raw/owner/...` 会返回「无效输入」。
:::
## 支持的 URL 类型
| 类型 | 匹配路径示例 |
|------|-------------|
| Release / Archive | `github.com/{owner}/{repo}/releases/...`、`/archive/...` |
| Raw / Blob | `github.com/{owner}/{repo}/raw/...``/blob/` 自动转为 `/raw/` |
| Git 协议 | `github.com/{owner}/{repo}/info/...`、`/git-...` |
| Raw 域名 | `raw.githubusercontent.com/...`、`raw.github.com/...` |
| API | `api.github.com/repos/{owner}/{repo}/...` |
| Gist | `gist.github.com/...`、`gist.githubusercontent.com/...` |
| Hugging Face | `huggingface.co/...`、`cdn-lfs.hf.co/...` |
| GitHub Assets | `github.githubassets.com/...`、`opengraph.githubassets.com/...` |
## 脚本嵌套加速
HubProxy 可自动改写 `.sh` / `.ps1` 安装脚本中的 GitHub URL脚本最大 10MB。反代部署时需正确设置 `X-Forwarded-Host`,详见 [反向代理配置](/deployment/reverse-proxy/)。
## 限制与拒绝
| 限制 | 说明 |
|------|------|
| 网页内容 | `text/html`、`application/xml` 等网页类型会被拒绝403不能用来加速 GitHub 网页浏览 |
| 文件大小 | `[server].fileSize` 控制单文件上限,默认 2GB |
| 仓库访问 | `[access].whiteList` / `blackList` 限制可代理的 GitHub 仓库 |
Release 等大文件支持 `wget -c` 断点续传,见 [传输特性](/guides/capabilities/)。
```toml
[server]
fileSize = 2147483648
[access]
whiteList = ["trusted-org/*"]
blackList = ["*/malicious-repo"]
```
## 相关文档
- [Hugging Face 加速](/guides/huggingface/)
- [传输特性(断点续传、分片)](/guides/capabilities/)
- [二次开发:添加新加速 URL](/guides/development/)

View File

@@ -0,0 +1,53 @@
---
title: Hugging Face 加速
description: 通过 HubProxy 加速 Hugging Face 模型与 LFS 文件下载。
---
Hugging Face 下载与 GitHub 共用同一套 URL 代理机制,在**完整原始 URL** 前加上 HubProxy 域名即可。
## 支持的 URL
| 类型 | 示例 |
|------|------|
| 模型 / 数据集文件 | `huggingface.co/{user}/{repo}/resolve/...` |
| Spaces | `huggingface.co/spaces/{user}/{repo}/...` |
| LFS CDN | `cdn-lfs.hf.co/{user}/{repo}/...` |
正则定义位于 `src/handlers/github.go` 的 `githubExps` 数组。
## 下载示例
```bash
# 模型文件
curl -L -O "https://example.com/https://huggingface.co/bert-base-uncased/resolve/main/config.json"
# 省略 https://
curl -L -O "https://example.com/huggingface.co/bert-base-uncased/resolve/main/pytorch_model.bin"
# LFS 大文件
curl -L -O "https://example.com/https://cdn-lfs.hf.co/user/model-repo/abc123..."
```
## Python / huggingface_hub
将原始 HF URL 替换为 HubProxy 前缀形式:
```
https://example.com/https://huggingface.co/...
```
确保最终请求路径能被 `githubExps` 中的 Hugging Face 正则匹配。
## 限制
与 [GitHub 加速](/guides/github-proxy/) 相同:
- 不支持网页浏览HTML 会被拒绝)
- 单文件受 `[server].fileSize` 限制
- 与 GitHub 相同,**支持** `Range` 断点续传与多连接分片(见 [传输特性](/guides/capabilities/)
- 受 `[access]` 仓库黑白名单约束
```toml
[access]
whiteList = ["trusted-user/*"]
```

View File

@@ -0,0 +1,90 @@
---
title: Kubernetes 与 containerd
description: 在 K3s、RKE2 及原生 containerd 中配置 HubProxy 镜像加速。
---
HubProxy 兼容 OCI/Distribution Registry API v2。Kubernetes 节点通常由 **containerd** 拉取镜像,配置方式与 Docker `daemon.json` 不同。
## K3s
在每个节点创建 `/etc/rancher/k3s/registries.yaml`
```yaml
mirrors:
docker.io:
endpoint:
- "https://example.com"
"ghcr.io":
endpoint:
- "https://example.com"
"quay.io":
endpoint:
- "https://example.com"
"registry.k8s.io":
endpoint:
- "https://example.com"
```
重启服务:
```bash
sudo systemctl restart k3s # server
sudo systemctl restart k3s-agent # agent
```
验证(使用 **crictl**mirror 不对 `ctr` 生效):
```bash
sudo crictl pull docker.io/library/nginx:latest
```
## RKE2
配置 `/etc/rancher/rke2/registries.yaml`,格式同上,重启 `rke2-server` 或 `rke2-agent`。
## 原生 containerd1.5+
```bash
sudo mkdir -p /etc/containerd/certs.d/docker.io
```
`/etc/containerd/certs.d/docker.io/hosts.toml`
```toml
server = "https://registry-1.docker.io"
[host."https://example.com"]
capabilities = ["pull", "resolve"]
```
GHCR 示例:`/etc/containerd/certs.d/ghcr.io/hosts.toml`
```toml
server = "https://ghcr.io"
[host."https://example.com"]
capabilities = ["pull", "resolve"]
```
确保 `/etc/containerd/config.toml` 启用:
```toml
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
```
```bash
sudo systemctl restart containerd
```
## 路径说明
- docker.io`/v2/library/nginx/...`
- ghcr.io 等:`/v2/ghcr.io/owner/image/...`
- 支持 containerd `ns` 查询参数识别 `[registries]`
## 注意事项
- 每节点独立配置;生产环境 HubProxy 建议 HTTPS 反代
- 私有镜像需 `imagePullSecrets`HubProxy 对上游匿名拉取
- 见 [传输特性](/guides/capabilities/)

View File

@@ -0,0 +1,71 @@
---
title: NAS 配置
description: 在群晖 DSM 与飞牛 fnOS 上配置 HubProxy 镜像加速。
---
NAS 上的 Docker 通过图形界面管理,**不要**随意用脚本覆盖整个 `daemon.json`,以免丢失 `data-root` 导致容器丢失。
以下假设 HubProxy 已通过反代暴露在 `https://example.com`。
## 群晖 DSMContainer Manager
DSM 7.2+ 将「Docker」更名为 **Container Manager**。
### 图形界面(推荐)
1. **Container Manager** → **注册表** → **设置**
2. 选择 **Docker Hub** → **编辑**
3. 勾选 **启用 Registry 镜像**,填入 `https://example.com`
4. 保存并重启 Docker 引擎
### SSH 修改 dockerd.json
:::caution
备份原文件,**保留** `data-root`、`storage-driver` 等字段,仅改 `registry-mirrors`。
:::
DSM 7.2 及更早:`/var/packages/Docker/etc/dockerd.json`
DSM 7.3+`/var/packages/ContainerManager/etc/dockerd.json`
```json
"registry-mirrors": ["https://example.com"]
```
重启:
```bash
# DSM 7.2 及更早
sudo systemctl restart pkgctl-Docker
# DSM 7.3+
sudo systemctl restart pkg-ContainerManager-dockerd
```
验证:`sudo docker info | grep -A3 "Registry Mirrors"`
---
## 飞牛 fnOS
官方建议:**不要**用脚本直接改写 `/etc/docker/daemon.json`(含 `data-root`,误删会导致镜像/容器丢失)。
### Web 界面(推荐)
1. **Docker** → **镜像仓库** → **仓库设置** / **加速源设置**
2. **添加 URL**`https://example.com`
3. 拖到列表**顶部**,保存并**重启 Docker**
### 手动编辑(高级)
先备份,仅向 `registry-mirrors` 追加地址,保留 `data-root` 等字段,然后重启 Docker。
### 注意
- 应用中心部分应用走阿里云等固定 Registry与 HubProxy 无关
- 修改后必须重启 Docker 才生效
## 相关文档
- [Docker 镜像加速](/guides/docker-mirror/)
- [反向代理](/deployment/reverse-proxy/)

View File

@@ -0,0 +1,84 @@
---
title: 离线镜像包
description: 在线打包 Docker 镜像为 tar 文件,支持单镜像与批量下载。
---
HubProxy Web 界面(`enableFrontend = true`)与 API 支持将镜像在线打包为 tar 离线包,无需本地 Docker 环境。
下载采用**两步流程**:先 `prepare` 获取一次性 token再携带 token 下载。Token 有效期 **2 分钟**,绑定客户端 IP 与 User-Agent。
## Web 界面
访问 HubProxy 首页,在「离线镜像」功能中输入镜像名与标签即可下载。
## 单镜像 API
**第一步:申请下载**
```bash
curl "https://example.com/api/image/download?image=library/nginx:latest&mode=prepare"
```
响应示例:
```json
{
"download_url": "/api/image/download?image=library/nginx%3Alatest&token=..."
}
```
**第二步:下载 tar**
```bash
curl -L -o nginx.tar "https://example.com/api/image/download?image=library/nginx:latest&token=YOUR_TOKEN"
```
可选参数:
| 参数 | 说明 |
|------|------|
| `platform` | 指定平台,如 `linux/amd64` |
| `tag` | 镜像未含 tag 时使用,默认 `latest` |
| `compressed` | 是否压缩层,默认 `true` |
## 批量 API
**第一步:申请批量下载**
```bash
curl -X POST "https://example.com/api/image/batch?mode=prepare" \
-H "Content-Type: application/json" \
-d '{"images":["nginx:latest","redis:alpine"]}'
```
**第二步:下载合并 tar**
```bash
curl -L -o batch.tar "https://example.com/api/image/batch?token=YOUR_TOKEN"
```
## 镜像信息
```bash
curl "https://example.com/api/image/info?image=library/nginx:latest"
```
## 限制
| 配置 / 规则 | 默认值 | 说明 |
|------------|--------|------|
| `[download].maxImages` | `10` | 单次批量镜像数量上限 |
| prepare 防抖(单镜像) | 5 秒 | 同一用户重复 prepare 会返回 429 |
| prepare 防抖(批量) | 60 秒 | 同上 |
| Token TTL | 2 分钟 | 过期或 IP/UA 不匹配则无效 |
```toml
[download]
maxImages = 10
```
## 注意事项
- 大镜像打包耗时较长,流式传输中断后需重新请求
- 受 `[access]` 黑白名单与 IP 限流约束
- `/ready` 与前端静态页面不计入限流API 与代理请求会计入

View File

@@ -0,0 +1,49 @@
---
title: HubProxy 文档
description: Docker 与 GitHub 加速代理服务的官方文档,涵盖部署、配置与安全实践。
template: splash
hero:
tagline: 轻量级、自托管的多功能加速代理
image:
file: ../../assets/hero.svg
actions:
- text: 快速开始
link: /getting-started/quick-start/
icon: right-arrow
- text: GitHub
link: https://github.com/sky22333/hubproxy
icon: external
variant: minimal
---
import { Card, CardGrid } from '@astrojs/starlight/components'
## 核心能力
<CardGrid stagger>
<Card title="Docker 镜像加速" icon="rocket">
支持 Docker Hub、GHCR、Quay、GCR、registry.k8s.io 等 Registry API v2 标准仓库。
</Card>
<Card title="GitHub 文件加速" icon="document">
在完整 URL 前加域名即可加速 Release、Raw、Clone、API 与 Hugging Face 下载。
</Card>
<Card title="离线镜像包" icon="seti:docker">
在线打包镜像为 tar支持单镜像与批量下载。
</Card>
<Card title="镜像搜索" icon="magnifier">
内置 Docker Hub 镜像搜索与标签浏览。
</Card>
<Card title="智能限流" icon="warning">
按真实客户端 IP 限流,支持黑白名单与仓库访问控制。
</Card>
<Card title="完全自托管" icon="approve-check">
单二进制部署,不依赖第三方免费 CDN 代理服务。
</Card>
</CardGrid>
## 推荐阅读
- 公网部署请优先阅读 [推荐部署架构](/deployment/architecture/) 与 [反向代理配置](/deployment/reverse-proxy/)
- K8s / NAS 用户见 [Kubernetes 与 containerd](/guides/kubernetes-containerd/)、[NAS 配置](/guides/nas/)
- 能力边界见 [传输特性](/guides/capabilities/),扩展开发见 [二次开发与构建](/guides/development/)
- 配置项说明见 [config.toml 参考](/configuration/reference/)

View File

@@ -0,0 +1,50 @@
---
title: IP 信任机制
description: HubProxy 如何识别真实客户端 IP 并防止伪造。
---
HubProxy 使用 Gin 的 `ClientIP()` 获取客户端地址,并配合可信代理网段判断何时信任转发头。
## 可信代理网段
仅当 TCP 连接来自以下网段时,才读取 `X-Forwarded-For` / `X-Real-IP`
- `127.0.0.0/8`(本机)
- `10.0.0.0/8`(私网 A 类)
- `172.16.0.0/12`(私网 B 类)
- `192.168.0.0/16`(私网 C 类)
直连公网 IP 的请求**不会**信任任何转发头,直接使用 TCP 远端地址。
## 限流 IP 计算
| 协议 | 限流键 |
|------|--------|
| IPv4 | 完整 IP 地址 |
| IPv6 | `/64` 网段 |
内存中最多缓存 10000 条 IP 记录,不会无限增长。
## `[security].whiteList` 与 IP 防护
`[security].whiteList` 是**限流豁免名单**,不是「允许访问的 IP 列表」:
- 白名单 IP 不受 `[rateLimit]` 限制
- 与 IP 伪造防护、仓库访问控制(`[access]`)是独立机制
## 正确反代示例
反代必须**覆盖写**(非 append客户端 IP
```nginx
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
```
详见 [反向代理配置](/deployment/reverse-proxy/)。
## Cloudflare 场景
若用户经 Cloudflare 到达反代,反代应从 `CF-Connecting-IP` 读取真实 IP 并写入转发头,而不是让 HubProxy 直连 Cloudflare。
HubProxy **不**内置 Cloudflare IP 信任列表,依赖「反代在私网侧正确写入 IP」这一架构。

View File

@@ -0,0 +1,41 @@
---
title: 安全概述
description: HubProxy 安全模型、风险点与最佳实践。
---
HubProxy 作为开放代理服务,部署不当可能带来滥用风险。遵循以下实践可显著降低暴露面。
## 核心安全机制
| 机制 | 说明 |
|------|------|
| IP 限流 | 按真实客户端 IP 限制请求频率IPv6 按 `/64` |
| IP 黑白名单 | `[security]` 控制限流豁免与封禁 |
| 仓库访问控制 | `[access]` 限制可代理的镜像与 GitHub 仓库 |
| 可信代理 | 仅信任来自私网/本机的转发头,防止 IP 伪造 |
| 文件大小限制 | `[server].fileSize` 防止超大文件滥用 |
| 离线下载 Token | 一次性 token绑定 IP 与 User-Agent2 分钟过期 |
## 未内置的能力
HubProxy **没有**管理后台登录、Basic Auth、API Key 或 Prometheus 指标端点。Web 界面为公开 SPA安全依赖网络层与配置策略。
## 主要风险
1. **开放代理**:公网直连 `0.0.0.0:5000` 且无 `[access].whiteList` 时,任何人可使用你的带宽代理任意仓库
2. **IP 伪造**:反代未覆盖写 `X-Forwarded-For` 时,攻击者可绕过限流
3. **Host 注入**:反代未设置 `X-Forwarded-Host` 时,`.sh` 脚本可能生成错误加速 URL
## 推荐实践
- 使用 [推荐部署架构](/deployment/architecture/)CDN可选→ 反代 → HubProxy
- 公网服务配置 `[access].whiteList`
- 反代覆盖写 `X-Forwarded-For`、`X-Real-IP`、`X-Forwarded-Host`
- 不要将 `5000` 端口暴露到公网
- 定期审查 `[access].blackList` 与访问日志
## 相关文档
- [IP 信任机制](/security/ip-trust/)
- [反向代理配置](/deployment/reverse-proxy/)
- [config.toml 参考](/configuration/reference/)

352
docs/src/styles/custom.css Normal file
View File

@@ -0,0 +1,352 @@
/* HubProxy docs */
:root {
--sl-color-accent: #2563eb;
--sl-color-accent-high: #1d4ed8;
--sl-sidebar-width: 15rem;
--sl-toc-width: 18rem;
--hub-ease: cubic-bezier(0.4, 0, 0.2, 1);
--hub-duration-fast: 0.15s;
--hub-duration: 0.22s;
--hub-duration-slow: 0.32s;
}
html {
-webkit-tap-highlight-color: transparent;
scroll-padding-top: calc(1.5rem + var(--sl-nav-height) + var(--sl-mobile-toc-height));
}
@media (min-width: 72rem) {
html {
scroll-padding-top: calc(1.5rem + var(--sl-nav-height));
}
}
@keyframes hub-fade-up {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes hub-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes hub-scale-in {
from {
opacity: 0;
transform: scale(0.97) translateY(-6px);
}
to {
opacity: 1;
transform: none;
}
}
#starlight__sidebar {
scrollbar-width: none;
-ms-overflow-style: none;
scrollbar-gutter: auto;
}
#starlight__sidebar::-webkit-scrollbar {
display: none;
}
@media (min-width: 72rem) {
:root[data-has-toc] {
--__toc-width: var(--sl-toc-width);
}
.right-sidebar-container {
width: var(--sl-toc-width);
}
.right-sidebar-panel .sl-container {
width: calc(var(--sl-toc-width) - 2 * var(--sl-sidebar-pad-x));
max-width: calc(var(--sl-toc-width) - 2 * var(--sl-sidebar-pad-x));
}
[data-has-sidebar][data-has-toc] .main-pane {
--sl-content-margin-inline: 0;
width: min(
calc(100% - var(--sl-toc-width)),
calc(
var(--sl-content-width) +
(100% - var(--sl-content-width) - var(--sl-toc-width)) / 2
)
);
}
}
@media (max-width: 49.999rem) {
.sidebar-pane {
transform: translateX(-100%);
transition: transform var(--hub-duration) var(--hub-ease);
}
[aria-expanded='true'] ~ .sidebar-pane {
transform: translateX(0);
}
}
.sidebar-content a,
.right-sidebar-panel a,
#starlight__mobile-toc a,
.social-icons a,
.header a,
#starlight__mobile-toc,
#starlight__mobile-toc summary,
.sl-markdown-content a:not(:where(.not-content *)),
footer a {
transition:
color var(--hub-duration-fast) var(--hub-ease),
background-color var(--hub-duration-fast) var(--hub-ease),
border-color var(--hub-duration-fast) var(--hub-ease),
text-decoration-color var(--hub-duration-fast) var(--hub-ease),
opacity var(--hub-duration-fast) var(--hub-ease);
}
.sidebar-content summary,
.sidebar-content summary .caret {
transition:
color var(--hub-duration-fast) var(--hub-ease),
transform var(--hub-duration) var(--hub-ease),
opacity var(--hub-duration-fast) var(--hub-ease);
}
.site-title {
transition: opacity var(--hub-duration-fast) var(--hub-ease);
}
.site-title:hover {
opacity: 0.88;
}
footer a:hover {
opacity: 0.85;
}
site-search button,
starlight-menu-button button {
transition:
color var(--hub-duration-fast) var(--hub-ease),
background-color var(--hub-duration-fast) var(--hub-ease),
transform var(--hub-duration-fast) var(--hub-ease),
box-shadow var(--hub-duration-fast) var(--hub-ease);
}
site-search button:hover,
starlight-menu-button button:hover {
transform: scale(1.04);
}
site-search button:active,
starlight-menu-button button:active {
transform: scale(0.97);
}
starlight-theme-select label,
starlight-lang-select label {
transition:
border-color var(--hub-duration-fast) var(--hub-ease),
background-color var(--hub-duration-fast) var(--hub-ease),
color var(--hub-duration-fast) var(--hub-ease);
}
.sl-link-button,
.pagination-links a,
.card {
transition:
color var(--hub-duration-fast) var(--hub-ease),
background-color var(--hub-duration-fast) var(--hub-ease),
border-color var(--hub-duration) var(--hub-ease),
transform var(--hub-duration) var(--hub-ease),
box-shadow var(--hub-duration) var(--hub-ease);
}
/* minimal 为文本链式按钮,勿叠加卡片式 hover首页 GitHub 按钮) */
.sl-link-button.primary:hover {
transform: translateY(-1px);
box-shadow: var(--sl-shadow-sm);
}
.sl-link-button.minimal:hover {
transform: none;
box-shadow: none;
opacity: 0.72;
}
.pagination-links a:hover {
transform: translateY(-2px);
box-shadow: var(--sl-shadow-md);
}
.sl-link-button:active,
.pagination-links a:active {
transform: translateY(0);
}
.pagination-links svg {
transition: transform var(--hub-duration) var(--hub-ease);
}
.pagination-links a[rel='prev']:hover svg {
transform: translateX(-3px);
}
.pagination-links a[rel='next']:hover svg {
transform: translateX(3px);
}
.sl-markdown-content .starlight-aside {
transition:
border-color var(--hub-duration-fast) var(--hub-ease),
box-shadow var(--hub-duration) var(--hub-ease);
}
.expressive-code .copy button {
transition:
opacity var(--hub-duration-fast) var(--hub-ease),
background-color var(--hub-duration-fast) var(--hub-ease),
transform var(--hub-duration-fast) var(--hub-ease);
}
.expressive-code .copy button:hover {
transform: scale(1.06);
}
.card:hover {
transform: translateY(-2px);
box-shadow: var(--sl-shadow-md);
}
.card-grid.stagger .card {
animation: hub-fade-up var(--hub-duration-slow) var(--hub-ease) both;
}
.card-grid.stagger .card:nth-child(1) {
animation-delay: 0.04s;
}
.card-grid.stagger .card:nth-child(2) {
animation-delay: 0.08s;
}
.card-grid.stagger .card:nth-child(3) {
animation-delay: 0.12s;
}
.card-grid.stagger .card:nth-child(4) {
animation-delay: 0.16s;
}
.card-grid.stagger .card:nth-child(5) {
animation-delay: 0.2s;
}
.card-grid.stagger .card:nth-child(6) {
animation-delay: 0.24s;
}
.hero img {
width: min(100%, 22rem);
height: auto;
border-radius: 1rem;
box-shadow: var(--sl-shadow-md);
}
@media (prefers-color-scheme: dark) {
.hero img {
box-shadow: 0 12px 40px rgb(0 0 0 / 35%);
}
}
/* 仅正文 FAQ勿用全局 details 以免破坏移动端 TOC / 侧栏 */
.sl-markdown-content details {
margin-block: 1rem;
padding: 0.75rem 1rem;
border: 1px solid var(--sl-color-gray-5);
border-radius: 0.5rem;
transition:
background-color var(--hub-duration-fast) var(--hub-ease),
border-color var(--hub-duration-fast) var(--hub-ease);
}
.sl-markdown-content details[open] {
background: var(--sl-color-gray-6);
}
.sl-markdown-content summary {
cursor: pointer;
font-weight: 600;
transition: color var(--hub-duration-fast) var(--hub-ease);
}
.sl-markdown-content details > :not(summary) {
margin-top: 0.75rem;
}
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
}
.main-pane {
view-transition-name: main-content;
}
::view-transition-old(main-content),
::view-transition-new(main-content) {
animation-duration: var(--hub-duration);
animation-timing-function: var(--hub-ease);
}
html {
scroll-behavior: smooth;
}
site-search dialog[open] {
animation: hub-scale-in var(--hub-duration) var(--hub-ease) both;
}
site-search dialog[open]::backdrop {
animation: hub-fade-in var(--hub-duration) var(--hub-ease) both;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
.card:hover,
site-search button:hover,
starlight-menu-button button:hover,
.sl-link-button.primary:hover,
.pagination-links a:hover {
transform: none;
}
.card-grid.stagger .card {
animation: none;
}
}

5
docs/tsconfig.json Normal file
View File

@@ -0,0 +1,5 @@
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}