livehl/aimirrorPublic

🚀 200倍速!AI时代的下载神器 | Docker/PyPI/HuggingFace/CRAN 全加速 | 并行分片+智能缓存,让下载飞起来

AI summary: A smart, parallel-download proxy that accelerates PyPI, Docker, CRAN, and HuggingFace in restricted corporate networks.

Stars
215
Forks
21
Watchers
3
Open issues
1
Open PRs
0
Contributors
~1
Commits
51
Branches
1

PythonMITCreated Mar 5, 2026Last push 6mo agoLatest release v0.3.4+1 this month

Quick answers

What is aimirror?
A smart, parallel-download proxy that accelerates PyPI, Docker, CRAN, and HuggingFace in restricted corporate networks.
What does aimirror do?
aimirror is a specialized high-performance cache and proxy designed to rescue AI engineers trapped behind slow corporate networks. It acts as a unified download accelerator for multiple package managers including pip, Docker, and the HuggingFace CLI. Instead of just passively caching, it intercepts requests, dynamically routes large files, and executes multi-threaded HTTP Range parallel downloads to saturate available bandwidth. It automatically rewrites HTML and JSON API responses to seamlessly spoof clients, providing massive speedups on large machine learning artifacts without requiring users to alter their existing workflows.
Who is aimirror for?
AI engineers, data scientists, and DevOps teams dealing with massive machine learning dependencies over constrained, proxied, or highly-latent network connections.
How do I get started with aimirror?
pip install aimirror
How popular is aimirror on GitHub?
livehl/aimirror has 215 stars and 21 forks on GitHub.
What license does aimirror use?
livehl/aimirror is released under the MIT license.

Star history

since Mar 1, 2026
0100200Mar 2026May 2026Jul 2026Oct 2026
215 stars as of Oct 2, 2026. Before Jul 29, 2026, reconstructed from public GitHub event archives (checked against the repository's real star total); since then measured daily.

Contribution activity

commits per day, last 52 weeks
OctNovDecJanFebMarAprMayJunJulAugSepMonWedFri2025-10-04: 0 commits2025-10-05: 0 commits2025-10-06: 0 commits2025-10-07: 0 commits2025-10-08: 0 commits2025-10-09: 0 commits2025-10-10: 0 commits2025-10-11: 0 commits2025-10-12: 0 commits2025-10-13: 0 commits2025-10-14: 0 commits2025-10-15: 0 commits2025-10-16: 0 commits2025-10-17: 0 commits2025-10-18: 0 commits2025-10-19: 0 commits2025-10-20: 0 commits2025-10-21: 0 commits2025-10-22: 0 commits2025-10-23: 0 commits2025-10-24: 0 commits2025-10-25: 0 commits2025-10-26: 0 commits2025-10-27: 0 commits2025-10-28: 0 commits2025-10-29: 0 commits2025-10-30: 0 commits2025-10-31: 0 commits2025-11-01: 0 commits2025-11-02: 0 commits2025-11-03: 0 commits2025-11-04: 0 commits2025-11-05: 0 commits2025-11-06: 0 commits2025-11-07: 0 commits2025-11-09: 0 commits2025-11-10: 0 commits2025-11-11: 0 commits2025-11-12: 0 commits2025-11-13: 0 commits2025-11-14: 0 commits2025-11-15: 0 commits2025-11-16: 0 commits2025-11-17: 0 commits2025-11-18: 0 commits2025-11-19: 0 commits2025-11-20: 0 commits2025-11-21: 0 commits2025-11-22: 0 commits2025-11-23: 0 commits2025-11-24: 0 commits2025-11-25: 0 commits2025-11-26: 0 commits2025-11-27: 0 commits2025-11-28: 0 commits2025-11-29: 0 commits2025-11-30: 0 commits2025-12-01: 0 commits2025-12-02: 0 commits2025-12-03: 0 commits2025-12-04: 0 commits2025-12-05: 0 commits2025-12-06: 0 commits2025-12-07: 0 commits2025-12-08: 0 commits2025-12-09: 0 commits2025-12-10: 0 commits2025-12-11: 0 commits2025-12-12: 0 commits2025-12-13: 0 commits2025-12-14: 0 commits2025-12-15: 0 commits2025-12-16: 0 commits2025-12-17: 0 commits2025-12-18: 0 commits2025-12-19: 0 commits2025-12-20: 0 commits2025-12-21: 0 commits2025-12-22: 0 commits2025-12-23: 0 commits2025-12-24: 0 commits2025-12-25: 0 commits2025-12-26: 0 commits2025-12-27: 0 commits2025-12-28: 0 commits2025-12-29: 0 commits2025-12-30: 0 commits2025-12-31: 0 commits2026-01-01: 0 commits2026-01-02: 0 commits2026-01-03: 0 commits2026-01-04: 0 commits2026-01-05: 0 commits2026-01-06: 0 commits2026-01-07: 0 commits2026-01-08: 0 commits2026-01-09: 0 commits2026-01-10: 0 commits2026-01-11: 0 commits2026-01-12: 0 commits2026-01-13: 0 commits2026-01-14: 0 commits2026-01-15: 0 commits2026-01-16: 0 commits2026-01-17: 0 commits2026-01-18: 0 commits2026-01-19: 0 commits2026-01-20: 0 commits2026-01-21: 0 commits2026-01-22: 0 commits2026-01-23: 0 commits2026-01-24: 0 commits2026-01-25: 0 commits2026-01-26: 0 commits2026-01-27: 0 commits2026-01-28: 0 commits2026-01-29: 0 commits2026-01-30: 0 commits2026-01-31: 0 commits2026-02-01: 0 commits2026-02-02: 0 commits2026-02-03: 0 commits2026-02-04: 0 commits2026-02-05: 0 commits2026-02-06: 0 commits2026-02-07: 0 commits2026-02-08: 0 commits2026-02-09: 0 commits2026-02-10: 0 commits2026-02-11: 0 commits2026-02-12: 0 commits2026-02-13: 0 commits2026-02-14: 0 commits2026-02-15: 0 commits2026-02-16: 0 commits2026-02-17: 0 commits2026-02-18: 0 commits2026-02-19: 0 commits2026-02-20: 0 commits2026-02-21: 0 commits2026-02-22: 0 commits2026-02-23: 0 commits2026-02-24: 0 commits2026-02-25: 0 commits2026-02-26: 0 commits2026-02-27: 0 commits2026-02-28: 0 commits2026-03-01: 0 commits2026-03-02: 0 commits2026-03-03: 0 commits2026-03-04: 0 commits2026-03-05: 5 commits2026-03-06: 17 commits2026-03-07: 11 commits2026-03-08: 0 commits2026-03-09: 0 commits2026-03-10: 6 commits2026-03-11: 0 commits2026-03-12: 0 commits2026-03-13: 0 commits2026-03-14: 3 commits2026-03-15: 9 commits2026-03-16: 0 commits2026-03-17: 0 commits2026-03-18: 0 commits2026-03-19: 0 commits2026-03-20: 0 commits2026-03-21: 0 commits2026-03-22: 0 commits2026-03-23: 0 commits2026-03-24: 0 commits2026-03-25: 0 commits2026-03-26: 0 commits2026-03-27: 0 commits2026-03-28: 0 commits2026-03-29: 0 commits2026-03-30: 0 commits2026-03-31: 0 commits2026-04-01: 0 commits2026-04-02: 0 commits2026-04-03: 0 commits2026-04-04: 0 commits2026-04-05: 0 commits2026-04-06: 0 commits2026-04-07: 0 commits2026-04-08: 0 commits2026-04-09: 0 commits2026-04-10: 0 commits2026-04-11: 0 commits2026-04-12: 0 commits2026-04-13: 0 commits2026-04-14: 0 commits2026-04-15: 0 commits2026-04-16: 0 commits2026-04-17: 0 commits2026-04-18: 0 commits2026-04-19: 0 commits2026-04-20: 0 commits2026-04-21: 0 commits2026-04-22: 0 commits2026-04-23: 0 commits2026-04-24: 0 commits2026-04-25: 0 commits2026-04-26: 0 commits2026-04-27: 0 commits2026-04-28: 0 commits2026-04-29: 0 commits2026-04-30: 0 commits2026-05-01: 0 commits2026-05-02: 0 commits2026-05-03: 0 commits2026-05-04: 0 commits2026-05-05: 0 commits2026-05-06: 0 commits2026-05-07: 0 commits2026-05-08: 0 commits2026-05-09: 0 commits2026-05-10: 0 commits2026-05-11: 0 commits2026-05-12: 0 commits2026-05-13: 0 commits2026-05-14: 0 commits2026-05-15: 0 commits2026-05-16: 0 commits2026-05-17: 0 commits2026-05-18: 0 commits2026-05-19: 0 commits2026-05-20: 0 commits2026-05-21: 0 commits2026-05-22: 0 commits2026-05-23: 0 commits2026-05-24: 0 commits2026-05-25: 0 commits2026-05-26: 0 commits2026-05-27: 0 commits2026-05-28: 0 commits2026-05-29: 0 commits2026-05-30: 0 commits2026-05-31: 0 commits2026-06-01: 0 commits2026-06-02: 0 commits2026-06-03: 0 commits2026-06-04: 0 commits2026-06-05: 0 commits2026-06-06: 0 commits2026-06-07: 0 commits2026-06-08: 0 commits2026-06-09: 0 commits2026-06-10: 0 commits2026-06-11: 0 commits2026-06-12: 0 commits2026-06-13: 0 commits2026-06-14: 0 commits2026-06-15: 0 commits2026-06-16: 0 commits2026-06-17: 0 commits2026-06-18: 0 commits2026-06-19: 0 commits2026-06-20: 0 commits2026-06-21: 0 commits2026-06-22: 0 commits2026-06-23: 0 commits2026-06-24: 0 commits2026-06-25: 0 commits2026-06-26: 0 commits2026-06-27: 0 commits2026-06-28: 0 commits2026-06-29: 0 commits2026-06-30: 0 commits2026-07-01: 0 commits2026-07-02: 0 commits2026-07-03: 0 commits2026-07-04: 0 commits2026-07-05: 0 commits2026-07-06: 0 commits2026-07-07: 0 commits2026-07-08: 0 commits2026-07-09: 0 commits2026-07-10: 0 commits2026-07-11: 0 commits2026-07-12: 0 commits2026-07-13: 0 commits2026-07-14: 0 commits2026-07-15: 0 commits2026-07-16: 0 commits2026-07-17: 0 commits2026-07-18: 0 commits2026-07-19: 0 commits2026-07-20: 0 commits2026-07-21: 0 commits2026-07-22: 0 commits2026-07-23: 0 commits2026-07-24: 0 commits2026-07-25: 0 commits2026-07-26: 0 commits2026-07-27: 0 commits2026-07-28: 0 commits2026-07-29: 0 commits2026-07-30: 0 commits2026-07-31: 0 commits2026-08-01: 0 commits2026-08-02: 0 commits2026-08-03: 0 commits2026-08-04: 0 commits2026-08-05: 0 commits2026-08-06: 0 commits2026-08-07: 0 commits2026-08-08: 0 commits2026-08-09: 0 commits2026-08-10: 0 commits2026-08-11: 0 commits2026-08-12: 0 commits2026-08-13: 0 commits2026-08-14: 0 commits2026-08-15: 0 commits2026-08-16: 0 commits2026-08-17: 0 commits2026-08-18: 0 commits2026-08-19: 0 commits2026-08-20: 0 commits2026-08-21: 0 commits2026-08-22: 0 commits2026-08-23: 0 commits2026-08-24: 0 commits2026-08-25: 0 commits2026-08-26: 0 commits2026-08-27: 0 commits2026-08-28: 0 commits2026-08-29: 0 commits2026-08-30: 0 commits2026-08-31: 0 commits2026-09-01: 0 commits2026-09-02: 0 commits2026-09-03: 0 commits2026-09-04: 0 commits2026-09-05: 0 commits2026-09-06: 0 commits2026-09-07: 0 commits2026-09-08: 0 commits2026-09-09: 0 commits2026-09-10: 0 commits2026-09-11: 0 commits2026-09-12: 0 commits2026-09-13: 0 commits2026-09-14: 0 commits2026-09-15: 0 commits2026-09-16: 0 commits2026-09-17: 0 commits2026-09-18: 0 commits2026-09-19: 0 commits2026-09-20: 0 commits2026-09-21: 0 commits2026-09-22: 0 commits2026-09-23: 0 commits2026-09-24: 0 commits2026-09-25: 0 commits2026-09-26: 0 commits2026-09-27: 0 commits2026-09-28: 0 commits2026-09-29: 0 commits2026-09-30: 0 commits2026-10-01: 0 commits2026-10-02: 0 commits2026-10-03: 0 commits
51 commits in the last yearLessMore

Signals and awards

derived from tracked data
  • Permissive license

    MIT

  • Continuous integration

    Automated checks passing

What aimirror does

aimirror is a specialized high-performance cache and proxy designed to rescue AI engineers trapped behind slow corporate networks. It acts as a unified download accelerator for multiple package managers including pip, Docker, and the HuggingFace CLI. Instead of just passively caching, it intercepts requests, dynamically routes large files, and executes multi-threaded HTTP Range parallel downloads to saturate available bandwidth. It automatically rewrites HTML and JSON API responses to seamlessly spoof clients, providing massive speedups on large machine learning artifacts without requiring users to alter their existing workflows.

AI engineers, data scientists, and DevOps teams dealing with massive machine learning dependencies over constrained, proxied, or highly-latent network connections.

  • Parallel Chunking: Forces single-threaded tools like pip to download large wheel files using highly concurrent multi-threaded HTTP Range requests.
  • Unified Endpoint: Provides a single proxy service that simultaneously accelerates PyPI, Docker Hub, CRAN, and HuggingFace downloads.
  • Intelligent LRU Cache: Deduplicates files based on strict digest hashes rather than just URLs, aggressively optimizing local disk usage.
  • Response Rewriting: Automatically modifies links in JSON and HTML API responses so clients natively utilize the proxy for subsequent artifact fetches.
  • Custom Handlers: Includes specialized Python logic to navigate complex authentication and manifest workflows specific to Docker Registries.

Where teams use it

Corporate Intranet Bypassing

Engineers on throttled VPNs can download gigabyte-sized PyTorch wheels in seconds instead of waiting hours for standard sequential downloads.

Team Dependency Caching

Deploying aimirror on a local network server so a team only downloads massive HuggingFace models from the external internet exactly once.

CI/CD Pipeline Acceleration

Speeding up automated build pipelines that repeatedly pull the same bloated CUDA Docker layers by serving them from an instant local cache.

Multi-Source Custom Mirroring

Configuring custom routing rules via YAML to accelerate niche or internal HTTP endpoints without writing complex new proxy logic.

Getting started: pip install aimirror

README

main branch

🚀 aimirror

Python FastAPI License PyPI

AI 时代的下载镜像加速器 —— 被慢速网络逼疯的工程师的自救工具

一个服务 = PyPI + Docker Hub + CRAN + HuggingFace 全加速,还能任意扩展更多源

💡 项目背景

作为一名 AI 工程师,每天的工作离不开:

  • pip install torch —— 几百 MB 的 wheel 包下载到地老天荒
  • docker pull nvidia/cuda —— 几个 GB 的镜像层反复下载
  • huggingface-cli download —— 模型文件从 HuggingFace 蜗牛般爬过来

公司内网有代理,但单线程下载大文件依然慢得让人崩溃。重复下载相同的包?不存在的缓存。忍无可忍,于是写了这个工具。

aimirror = 智能路由 + 并行分片下载 + 本地缓存,让下载速度飞起来。

✨ 功能特性

  • ⚡ 并行下载 —— HTTP Range 分片,多线程并发,榨干带宽
  • 💾 智能缓存 —— 基于文件 digest 去重,LRU 自动淘汰
  • 🎯 动态路由 —— 小文件直接代理,大文件自动并行
  • 🔗 多源支持 —— Docker Hub、PyPI、CRAN、HuggingFace 开箱即用
  • 🔌 任意扩展 —— 只要是 HTTP 下载,配置一条规则即可几十倍加速
  • 📝 内容改写 —— 自动改写 HTML/JSON 响应中的链接,无缝代理
  • 🎛️ 特殊处理 —— 支持自定义 Handler 处理复杂场景(如 Docker Registry)
  • 🚦 并发控制 —— 全局下载并发限制,防止资源耗尽
  • 🔄 路径重写 —— 灵活的路径替换规则,适配各种 API 差异
  • 🔑 缓存优化 —— 支持原始 URL 作为缓存 key,解决临时签名问题

🔥 性能实测

PyPI 包安装加速对比

使用 uv pip install 安装 148 个依赖包(含 torch、transformers 等大包):

模式 解析依赖 准备包 总耗时 加速比
❌ 仅代理 (900KB/s) 17m 04s 14m 20s ~31 分钟 1x
✅ aimirror (170MB/s) 34.78s 45.81s ~80 秒 23x

💡 实测环境: 公司内网代理,带宽瓶颈明显。使用 aimirror 后从 900KB/s 飙升至 170MB/s,提速近 200 倍!

缓存效果

场景 耗时 速度 说明
首次下载 80s 170MB/s 并行下载 + 写入缓存
缓存命中 <1s 3000+ MB/s 万兆内网实测,本地 SSD 更快,瞬开

多源同时加速

一个 aimirror 服务,同时加速多种包管理器:

包管理器 配置方式 加速效果
pip/uv export HTTPS_PROXY=http://localhost:8081 或 pip install -i http://localhost:8081/simple PyPI 包 23x 加速
docker /etc/docker/daemon.json 中设置 registry-mirrors 镜像拉取并行分片
R CRAN options(repos = c(CRAN = "http://localhost:8081")) R 包下载加速
huggingface-cli export HF_ENDPOINT=http://localhost:8081 模型文件秒下
conda .condarc 中配置 channels 同理可扩展
npm/maven 配置 registry 指向 aimirror 任意 HTTP 源均可

🔌 扩展能力: 只要是 HTTP 下载,在 config.yaml 中添加一条规则即可接入加速,无需启动多个服务。

🏗️ 架构

flowchart LR
    subgraph Client["客户端"]
        PIP[pip install]
        DOCKER[docker pull]
        HF[huggingface-cli]
        R[R install.packages]
    end

    subgraph aimirror["aimirror 服务"]
        ROUTER[路由匹配器<br/>router.py]
        HANDLER[特殊处理器<br/>handlers/]
        PROXY[直接代理<br/>proxy]
        DOWNLOADER[并行下载器<br/>downloader.py]
        CACHE[缓存管理器<br/>cache.py]
        REWRITE[内容改写<br/>content_rewrite]
    end

    subgraph UpstreamProxy["上游代理 (可选)"]
        COMPANY_PROXY[公司代理]
    end

    subgraph Upstream["上游服务"]
        PYPI[PyPI]
        DOCKER_HUB[Docker Hub]
        HF_HUB[HuggingFace]
        CRAN[CRAN]
    end

    PIP --> ROUTER
    DOCKER --> ROUTER
    HF --> ROUTER
    R --> ROUTER

    ROUTER -->|匹配 handler| HANDLER
    ROUTER -->|小文件/代理策略| PROXY
    ROUTER -->|大文件/并行策略| DOWNLOADER

    HANDLER --> PROXY
    PROXY -->|需要改写| REWRITE
    REWRITE --> Client
    PROXY -->|直接返回| Client
    
    DOWNLOADER --> CACHE
    CACHE -->|命中| Client
    CACHE -->|未命中| UpstreamProxy
    PROXY --> UpstreamProxy

    UpstreamProxy -.->|可选| Upstream
    UpstreamProxy -->|直连| Upstream

    DOCKER_HUB -->|返回文件| CACHE
    PYPI -->|返回文件| CACHE
    HF_HUB -->|返回文件| CACHE
    CRAN -->|返回文件| CACHE
Loading

🚀 快速开始

方式一:pip 安装(推荐)

# 安装
pip install aimirror

# 启动
aimirror

# 使用
curl http://localhost:8081/health

方式二:源码安装

# 克隆仓库
git clone https://github.com/livehl/aimirror.git
cd aimirror

# 安装依赖
pip install -r requirements.txt

# 启动
python main.py

# 使用
curl http://localhost:8081/health

🔧 客户端配置

pip / uv

# 临时使用(单次安装)
pip install torch --index-url http://localhost:8081/simple --trusted-host localhost:8081

# 全局配置(推荐)
pip config set global.index-url http://localhost:8081/simple
pip config set global.trusted-host localhost:8081

# 使用 uv(速度更快)
uv pip install torch --index-url http://localhost:8081/simple

# 或使用环境变量
export HTTPS_PROXY=http://localhost:8081
pip install torch

Docker

# 配置 daemon.json
sudo tee /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["http://localhost:8081"]
}
EOF
sudo systemctl restart docker

# 或临时拉取
docker pull --registry-mirror=http://localhost:8081 nginx

⚠️ 重要提示:Docker 镜像层文件通常很大(GB 级别),建议将 chunk_size 设置为 0(自动模式)。

自动模式下,chunk_size = 文件总大小 / concurrency,这样可以:

  • 避免固定小分片导致分片数量过多
  • 减少 Docker Registry token 因超时失效的概率
  • 保持并发数不变,同时优化分片大小

配置示例见 config.yaml 中的 docker-blob 规则。

HuggingFace (huggingface-cli)

# 设置环境变量
export HF_ENDPOINT=http://localhost:8081

# 下载模型(支持所有文件类型:.gguf, .bin, .safetensors, .json 等)
huggingface-cli download TheBloke/Llama-2-7B-GGUF llama-2-7b.Q4_K_M.gguf

# 下载整个仓库
huggingface-cli download meta-llama/Llama-2-7b-hf --local-dir ./models

或使用 Python:

import os
os.environ["HF_ENDPOINT"] = "http://localhost:8081"

from huggingface_hub import hf_hub_download, snapshot_download

# 下载单个文件
hf_hub_download(repo_id="TheBloke/Llama-2-7B-GGUF", filename="llama-2-7b.Q4_K_M.gguf")

# 下载整个仓库
snapshot_download(repo_id="meta-llama/Llama-2-7b-hf", local_dir="./models")

R (CRAN)

# 在 R 控制台中设置
options(repos = c(CRAN = "http://localhost:8081"))

# 或在 .Rprofile 中永久配置
cat('options(repos = c(CRAN = "http://localhost:8081"))\n', file = "~/.Rprofile")

Conda

# 修改 .condarc
cat >> ~/.condarc <<EOF
channels:
  - http://localhost:8081/conda-forge
  - http://localhost:8081/bioconda
EOF

npm / yarn

# 临时使用
npm install --registry http://localhost:8081/registry/npm

# 全局配置
npm config set registry http://localhost:8081/registry/npm
yarn config set registry http://localhost:8081/registry/npm

📖 API

代理端点

路径 方法 说明
/{full_path:path} GET/HEAD/POST/PUT/DELETE 通用代理入口,根据路由规则转发到对应上游

管理端点

路径 方法 说明 响应示例
/health GET 健康检查 {"status": "ok", "active_downloads": 0, "downloads": []}
/stats GET 缓存统计信息 {"cache": {"total_size_mb": 1024, "file_count": 100}}

健康检查响应详情

curl http://localhost:8081/health

响应字段说明:

  • status: 服务状态,ok 表示正常运行
  • active_downloads: 当前正在进行的下载任务数
  • downloads: 正在下载的文件列表(缓存 key)

缓存统计响应详情

curl http://localhost:8081/stats | jq

响应包含缓存目录的总大小、文件数量等信息。

🚀 快速开始

方式一:pip 安装(推荐)

# 安装
pip install aimirror

# 启动
aimirror

# 使用
curl http://localhost:8081/health

方式二:源码安装

# 克隆仓库
git clone https://github.com/livehl/aimirror.git
cd aimirror

# 安装依赖
pip install -r requirements.txt

# 启动
python main.py

# 使用
curl http://localhost:8081/health

🐳 Docker 部署

使用 GitHub Container Registry

# 拉取镜像
docker pull ghcr.io/livehl/aimirror:latest

# 运行(基础版)
docker run -d -p 8081:8081 \
  -v $(pwd)/cache:/data/fast_proxy/cache \
  ghcr.io/livehl/aimirror:latest

# 运行(带自定义配置)
docker run -d -p 8081:8081 \
  -v $(pwd)/config.yaml:/app/config.yaml \
  -v $(pwd)/cache:/data/fast_proxy/cache \
  ghcr.io/livehl/aimirror:latest

Docker Compose 示例

version: '3.8'

services:
  aimirror:
    image: ghcr.io/livehl/aimirror:latest
    container_name: aimirror
    ports:
      - "8081:8081"
    volumes:
      - ./config.yaml:/app/config.yaml
      - ./cache:/data/fast_proxy/cache
      - ./logs:/data/fast_proxy
    restart: unless-stopped

注意:上游代理请在 config.yaml 中配置 server.upstream_proxy,不支持环境变量方式。

⚙️ 配置示例

# fast_proxy 配置文件
server:
  host: "0.0.0.0"
  port: 8081
  upstream_proxy: ""  # 上游代理,默认空表示直连
  public_host: "127.0.0.1:8081"  # 对外访问地址,用于 HTML 链接改写
  max_concurrent_downloads: 100  # 全局最大并发下载数,超过则排队

cache:
  dir: "/data/fast_proxy/cache"
  max_size_gb: 100
  lru_enabled: true

rules:
  # Docker Registry 代理(/v2/ 和 /v2/auth 在代码中特殊处理)
  - name: docker-blob
    pattern: "/v2/.*/blobs/sha256:[a-f0-9]+"
    upstream: "https://registry-1.docker.io"
    strategy: parallel
    min_size: 1       # all
    concurrency: 20
    chunk_size: 0     # 自动模式:总大小/concurrency,避免超大文件分片过多导致 token 超时
  - name: docker-registry
    pattern: "/v2/.*"
    upstream: "https://registry-1.docker.io"
    strategy: proxy
    handler: handlers.docker  # 特殊处理模块路径
    
  - name: pip-packages
    pattern: "/packages/.+\\.(whl|tar\\.gz|zip)$"
    upstream: "https://pypi.org"
    strategy: parallel
    min_size: 1       # all
    concurrency: 20
    chunk_size: 5242880      # 5MB per chunk
    
  - name: r-package
    pattern: "/src/contrib/.*"
    upstream: "https://cran.r-project.org"
    strategy: parallel
    min_size: 102400       # 100K
    concurrency: 20
    chunk_size: 5242880

  - name: huggingface-files
    pattern: '/.*/(blob|resolve)/[^/]+/.+'
    upstream: "https://huggingface.co"
    strategy: parallel
    min_size: 102400       #100k
    concurrency: 20
    chunk_size: 10485760    # 10MB per chunk
    cache_key_source: original  # 使用原始 URL 作为缓存 key(避免临时签名影响缓存命中)
    path_rewrite:
      - search: "/blob/"
        replace: "/resolve/"
    # HEAD 请求时需要额外保留的响应头(用于元数据获取)
    head_meta_headers:
      - "x-repo-commit"
      - "x-linked-etag"
      - "x-linked-size"
      - "etag"

  - name: huggingface-api
    pattern: '/api/models/.*'
    upstream: "https://huggingface.co"
    strategy: proxy

  # 示例:其他使用临时签名 URL 的站点
  # - name: example-signed-url
  #   pattern: '/signed-download/.*'
  #   upstream: "https://example.com"
  #   strategy: parallel
  #   min_size: 10485760
  #   concurrency: 10
  #   cache_key_source: original  # 使用原始 URL 作为缓存 key

  - name: default
    pattern: ".*"
    upstream: "https://pypi.org"
    strategy: proxy
    content_rewrite:         # 响应内容改写配置
      content_types:         # 匹配的 Content-Type(HTML 和 JSON)
        - "text/html"
        - "application/json"
        - "application/vnd.pypi.simple"
      targets:               # 要替换的目标 host 列表
        - "https://files.pythonhosted.org"

logging:
  level: "INFO"
  file: "/data/fast_proxy/fast_proxy.log"

配置说明

Server 配置
字段 说明 默认值
server.host 服务监听地址 "0.0.0.0"
server.port 服务监听端口 8081
server.upstream_proxy 上游代理地址,空字符串表示直连 ""
server.public_host 对外访问地址,用于 HTML 链接改写 "127.0.0.1:8081"
server.max_concurrent_downloads 全局最大并发下载数,超过则排队 100
Cache 配置
字段 说明 默认值
cache.dir 缓存目录路径 "./cache"
cache.max_size_gb 缓存最大容量(GB) 100
cache.lru_enabled 是否启用 LRU 自动淘汰 true
Rules 配置
字段 说明 示例
rules[].name 规则名称 "docker-blob"
rules[].pattern URL 匹配正则表达式 "/v2/.*/blobs/sha256:[a-f0-9]+"
rules[].upstream 上游源 base URL "https://registry-1.docker.io"
rules[].strategy 下载策略:proxy 直接代理 / parallel 并行下载 "parallel"
rules[].min_size 最小文件大小(字节),小于此值使用代理 1048576
rules[].concurrency 并行下载线程数 20
rules[].chunk_size 每个分片大小(字节),≤0 表示自动计算(总大小/concurrency) 10485760
rules[].cache_key_source 缓存 key 来源:original 使用原始URL,final 使用最终URL "original"
rules[].path_rewrite 路径重写规则数组 [{search: "/blob/", replace: "/resolve/"}]
rules[].content_rewrite 响应内容改写配置(用于 HTML/JSON 中的链接替换) 见 default 规则
rules[].handler 特殊处理模块路径 "handlers.docker"
rules[].head_meta_headers HEAD 请求时额外保留的响应头列表 ["etag", "x-repo-commit"]
Logging 配置
字段 说明 默认值
logging.level 日志级别:DEBUG/INFO/WARNING/ERROR "INFO"
logging.file 日志文件路径 "/tmp/fast_proxy.log"

高级配置示例

自定义 Handler

创建 handlers/custom.py:

async def exec_path(request, full_path, config, http_client):
    """
    自定义请求处理器
    
    Args:
        request: FastAPI Request 对象
        full_path: 请求路径
        config: 全局配置字典
        http_client: httpx.AsyncClient 实例
    
    Returns:
        (handled, response): 
        - handled: bool,是否已处理
        - response: 如果 handled=True,返回 Response 对象
    """
    if full_path.startswith('/custom/'):
        # 处理自定义逻辑
        return True, Response(content="Custom response")
    
    # 未处理,继续后续流程
    return False, None

在 config.yaml 中配置:

rules:
  - name: custom-handler
    pattern: "/custom/.*"
    upstream: "https://example.com"
    strategy: proxy
    handler: handlers.custom
扩展示例:添加 GitHub Releases 下载加速
rules:
  - name: github-releases
    pattern: '/.*/releases/download/.+'
    upstream: "https://github.com"
    strategy: parallel
    min_size: 1048576      # 1MB 以上启用并行
    concurrency: 16
    chunk_size: 10485760   # 10MB 分片
扩展示例:添加自定义软件源
rules:
  - name: my-company-repo
    pattern: '/artifacts/.+\.(jar|war|zip)$'
    upstream: "https://artifacts.mycompany.com"
    strategy: parallel
    min_size: 10485760     # 10MB 以上启用并行
    concurrency: 10
    chunk_size: 20971520   # 20MB 分片
    cache_key_source: original

🧪 测试

运行测试

# 运行简单测试(无需 pytest)
python test_simple.py

# 运行完整测试套件(需要 pytest)
pytest test_proxy.py -v

手动验证

测试 PyPI 代理

curl -o /dev/null "http://localhost:8081/packages/fb/d7/71b982339efc4fff3c622c6fefecddfd3e0b35b60c5f822872d5b806bb71/torch-1.0.0-cp27-cp27m-manylinux1_x86_64.whl" \
  -w "HTTP: %{http_code}, Size: %{size_download}, Time: %{time_total}s\n"

测试 HuggingFace 代理

export HF_ENDPOINT=http://localhost:8081

# 测试下载 GGUF 模型文件
huggingface-cli download TheBloke/Llama-2-7B-GGUF llama-2-7b.Q4_K_M.gguf

# 测试下载 safetensors 格式模型
huggingface-cli download meta-llama/Llama-2-7b-hf model-00001-of-00002.safetensors

# 测试下载整个仓库
huggingface-cli download sentence-transformers/all-MiniLM-L6-v2 --local-dir ./test-model

测试 Docker Registry 代理

# 获取 token
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/nginx:pull" \
  | grep -o '"token":"[^"]*"' | cut -d'"' -f4)

# 下载 blob
curl -o /dev/null "http://localhost:8081/v2/library/nginx/blobs/sha256:abc123" \
  -H "Authorization: Bearer $TOKEN" \
  -w "HTTP: %{http_code}, Size: %{size_download}, Time: %{time_total}s\n"

验证缓存命中

# 第一次下载(并行下载)
time curl -o /tmp/test1.gguf "http://localhost:8081/unsloth/model/resolve/main/file.gguf"

# 第二次下载(缓存命中,应该快很多)
time curl -o /tmp/test2.gguf "http://localhost:8081/unsloth/model/resolve/main/file.gguf"

# 查看缓存统计
curl http://localhost:8081/stats | jq

📄 License

MIT

View on GitHub

Recent activity

commits and pull requests

Recent open issues

view all

Releases and announcements

24 total
  1. v0.3.4v0.3.4Mar 15, 2026

    分块断点续传

  2. v0.3.3v0.3.3Mar 15, 2026

    fix

  3. v0.3.2v0.3.2Mar 15, 2026

    chunk_size=0时禁用多任务并发下载,避免线程抢占。

  4. v0.3.1v0.3.1Mar 14, 2026

    支持路径重写,支持nvidia和torch的地址

  5. v0.3.0v0.3.0Mar 10, 2026

    修复连接池泄露的问题。

Commits per week

last 52 weeks
330Week of 2025-10-04: 0 commitsWeek of 2025-10-11: 0 commitsWeek of 2025-10-18: 0 commitsWeek of 2025-10-25: 0 commitsWeek of 2025-11-01: 0 commitsWeek of 2025-11-09: 0 commitsWeek of 2025-11-16: 0 commitsWeek of 2025-11-23: 0 commitsWeek of 2025-11-30: 0 commitsWeek of 2025-12-07: 0 commitsWeek of 2025-12-14: 0 commitsWeek of 2025-12-21: 0 commitsWeek of 2025-12-28: 0 commitsWeek of 2026-01-04: 0 commitsWeek of 2026-01-11: 0 commitsWeek of 2026-01-18: 0 commitsWeek of 2026-01-25: 0 commitsWeek of 2026-02-01: 0 commitsWeek of 2026-02-08: 0 commitsWeek of 2026-02-15: 0 commitsWeek of 2026-02-22: 0 commitsWeek of 2026-03-01: 33 commitsWeek of 2026-03-08: 9 commitsWeek of 2026-03-15: 9 commitsWeek of 2026-03-22: 0 commitsWeek of 2026-03-29: 0 commitsWeek of 2026-04-05: 0 commitsWeek of 2026-04-12: 0 commitsWeek of 2026-04-19: 0 commitsWeek of 2026-04-26: 0 commitsWeek of 2026-05-03: 0 commitsWeek of 2026-05-10: 0 commitsWeek of 2026-05-17: 0 commitsWeek of 2026-05-24: 0 commitsWeek of 2026-05-31: 0 commitsWeek of 2026-06-07: 0 commitsWeek of 2026-06-14: 0 commitsWeek of 2026-06-21: 0 commitsWeek of 2026-06-28: 0 commitsWeek of 2026-07-05: 0 commitsWeek of 2026-07-12: 0 commitsWeek of 2026-07-19: 0 commitsWeek of 2026-07-26: 0 commitsWeek of 2026-08-02: 0 commitsWeek of 2026-08-09: 0 commitsWeek of 2026-08-16: 0 commitsWeek of 2026-08-23: 0 commitsWeek of 2026-08-30: 0 commitsWeek of 2026-09-06: 0 commitsWeek of 2026-09-13: 0 commitsWeek of 2026-09-20: 0 commitsWeek of 2026-09-27: 0 commitsOct 4, 2025Sep 27, 2026
51 commits in the last 52 weeks.

When work happens

weekday and hour
SunMonTueWedThuFriSat036912151821Sun 0:00 — 0 commitsSun 1:00 — 0 commitsSun 2:00 — 0 commitsSun 3:00 — 0 commitsSun 4:00 — 4 commitsSun 5:00 — 0 commitsSun 6:00 — 0 commitsSun 7:00 — 4 commitsSun 8:00 — 1 commitsSun 9:00 — 0 commitsSun 10:00 — 0 commitsSun 11:00 — 0 commitsSun 12:00 — 0 commitsSun 13:00 — 0 commitsSun 14:00 — 0 commitsSun 15:00 — 0 commitsSun 16:00 — 0 commitsSun 17:00 — 0 commitsSun 18:00 — 0 commitsSun 19:00 — 0 commitsSun 20:00 — 0 commitsSun 21:00 — 0 commitsSun 22:00 — 0 commitsSun 23:00 — 0 commitsMon 0:00 — 0 commitsMon 1:00 — 0 commitsMon 2:00 — 0 commitsMon 3:00 — 0 commitsMon 4:00 — 0 commitsMon 5:00 — 0 commitsMon 6:00 — 0 commitsMon 7:00 — 0 commitsMon 8:00 — 0 commitsMon 9:00 — 0 commitsMon 10:00 — 0 commitsMon 11:00 — 0 commitsMon 12:00 — 0 commitsMon 13:00 — 0 commitsMon 14:00 — 0 commitsMon 15:00 — 0 commitsMon 16:00 — 0 commitsMon 17:00 — 0 commitsMon 18:00 — 0 commitsMon 19:00 — 0 commitsMon 20:00 — 0 commitsMon 21:00 — 0 commitsMon 22:00 — 0 commitsMon 23:00 — 0 commitsTue 0:00 — 0 commitsTue 1:00 — 0 commitsTue 2:00 — 3 commitsTue 3:00 — 1 commitsTue 4:00 — 0 commitsTue 5:00 — 0 commitsTue 6:00 — 0 commitsTue 7:00 — 0 commitsTue 8:00 — 0 commitsTue 9:00 — 0 commitsTue 10:00 — 0 commitsTue 11:00 — 0 commitsTue 12:00 — 0 commitsTue 13:00 — 0 commitsTue 14:00 — 0 commitsTue 15:00 — 0 commitsTue 16:00 — 0 commitsTue 17:00 — 0 commitsTue 18:00 — 0 commitsTue 19:00 — 0 commitsTue 20:00 — 0 commitsTue 21:00 — 0 commitsTue 22:00 — 2 commitsTue 23:00 — 0 commitsWed 0:00 — 0 commitsWed 1:00 — 0 commitsWed 2:00 — 0 commitsWed 3:00 — 0 commitsWed 4:00 — 0 commitsWed 5:00 — 0 commitsWed 6:00 — 0 commitsWed 7:00 — 0 commitsWed 8:00 — 0 commitsWed 9:00 — 0 commitsWed 10:00 — 0 commitsWed 11:00 — 0 commitsWed 12:00 — 0 commitsWed 13:00 — 0 commitsWed 14:00 — 0 commitsWed 15:00 — 0 commitsWed 16:00 — 0 commitsWed 17:00 — 0 commitsWed 18:00 — 0 commitsWed 19:00 — 0 commitsWed 20:00 — 0 commitsWed 21:00 — 0 commitsWed 22:00 — 0 commitsWed 23:00 — 0 commitsThu 0:00 — 0 commitsThu 1:00 — 0 commitsThu 2:00 — 0 commitsThu 3:00 — 0 commitsThu 4:00 — 0 commitsThu 5:00 — 0 commitsThu 6:00 — 0 commitsThu 7:00 — 0 commitsThu 8:00 — 0 commitsThu 9:00 — 0 commitsThu 10:00 — 0 commitsThu 11:00 — 0 commitsThu 12:00 — 0 commitsThu 13:00 — 0 commitsThu 14:00 — 1 commitsThu 15:00 — 4 commitsThu 16:00 — 0 commitsThu 17:00 — 0 commitsThu 18:00 — 0 commitsThu 19:00 — 0 commitsThu 20:00 — 0 commitsThu 21:00 — 0 commitsThu 22:00 — 0 commitsThu 23:00 — 0 commitsFri 0:00 — 2 commitsFri 1:00 — 2 commitsFri 2:00 — 2 commitsFri 3:00 — 1 commitsFri 4:00 — 1 commitsFri 5:00 — 1 commitsFri 6:00 — 1 commitsFri 7:00 — 0 commitsFri 8:00 — 0 commitsFri 9:00 — 0 commitsFri 10:00 — 0 commitsFri 11:00 — 0 commitsFri 12:00 — 0 commitsFri 13:00 — 2 commitsFri 14:00 — 1 commitsFri 15:00 — 1 commitsFri 16:00 — 0 commitsFri 17:00 — 0 commitsFri 18:00 — 0 commitsFri 19:00 — 0 commitsFri 20:00 — 0 commitsFri 21:00 — 0 commitsFri 22:00 — 0 commitsFri 23:00 — 3 commitsSat 0:00 — 0 commitsSat 1:00 — 2 commitsSat 2:00 — 1 commitsSat 3:00 — 2 commitsSat 4:00 — 3 commitsSat 5:00 — 0 commitsSat 6:00 — 0 commitsSat 7:00 — 0 commitsSat 8:00 — 1 commitsSat 9:00 — 0 commitsSat 10:00 — 5 commitsSat 11:00 — 0 commitsSat 12:00 — 0 commitsSat 13:00 — 0 commitsSat 14:00 — 0 commitsSat 15:00 — 0 commitsSat 16:00 — 0 commitsSat 17:00 — 0 commitsSat 18:00 — 0 commitsSat 19:00 — 0 commitsSat 20:00 — 0 commitsSat 21:00 — 0 commitsSat 22:00 — 0 commitsSat 23:00 — 0 commits
Commit volume by weekday and hour (UTC). Larger dots mean more commits.

Who is committing

last 52 weeks
Maintainer commits51 (100%)
Community commits0 (0%)

51 commits in total over the last year.

DateListRankStars gained
Mar 11, 2026daily#18+136