{"id":50463761,"url":"https://github.com/harrisonwang/wharf","last_synced_at":"2026-06-17T22:01:33.752Z","repository":{"id":281347802,"uuid":"945001809","full_name":"harrisonwang/wharf","owner":"harrisonwang","description":"Docker Hub proxy service","archived":false,"fork":false,"pushed_at":"2026-05-06T10:38:33.000Z","size":2038,"stargazers_count":366,"open_issues_count":0,"forks_count":23,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-06T12:34:23.740Z","etag":null,"topics":["docker","proxy","registry"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/harrisonwang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-08T12:31:19.000Z","updated_at":"2026-05-06T10:38:24.000Z","dependencies_parsed_at":"2025-03-25T14:29:57.394Z","dependency_job_id":"ddf276b4-95bf-42d3-a684-2e0f44ffeedd","html_url":"https://github.com/harrisonwang/wharf","commit_stats":null,"previous_names":["harrisonwang/docker-registry-proxy-rs","harrisonwang/docxy","harrisonwang/wharf"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/harrisonwang/wharf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrisonwang%2Fwharf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrisonwang%2Fwharf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrisonwang%2Fwharf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrisonwang%2Fwharf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/harrisonwang","download_url":"https://codeload.github.com/harrisonwang/wharf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harrisonwang%2Fwharf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34466930,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","proxy","registry"],"created_at":"2026-06-01T06:00:30.975Z","updated_at":"2026-06-17T22:01:33.745Z","avatar_url":"https://github.com/harrisonwang.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Wharf\n\n![og-image](og-image.svg)\n\n[![English](https://img.shields.io/badge/English-Click-orange)](README_EN.md)\n[![简体中文](https://img.shields.io/badge/简体中文-点击查看-blue)](README.md)\n[![Русский](https://img.shields.io/badge/Русский-Нажмите-orange)](README_RU.md)\n[![Español](https://img.shields.io/badge/Español-Clic-blue)](README_ES.md)\n[![한국어](https://img.shields.io/badge/한국어-클릭-orange)](README_KR.md)\n[![العربية](https://img.shields.io/badge/العربية-انقر-blue)](README_AR.md)\n[![Türkçe](https://img.shields.io/badge/Türkçe-Tıkla-orange)](README_TR.md)\n\n轻量级 Docker 镜像代理服务，旨在解决国内访问 Docker Hub 受限问题。\n\n\u003e **更名说明:** 本项目已由 **Docxy** 更名为 **Wharf**。后续二进制命令、安装目录、systemd 服务和 Release 产物统一使用 `wharf`；旧文档或博客中出现的 Docxy 指向同一个项目。\n\n\u003e 📢 **使用教程:** [**跟 Docker Hub 连接超时说拜拜！用 Wharf 自建专属镜像加速器**](https://voxsay.com/posts/docxy-docker-proxy-tutorial-for-china/)\n\n## 核心特性\n\n*   🚀 **一键部署**: 提供 `install.sh` 自动化脚本，可一键完成环境配置、证书申请 (Let's Encrypt)、服务部署，无需手动干预。\n\n*   📦 **多种部署模式**:\n    *   **独立运行**: 内置 TLS 功能，直接对外提供 HTTPS 服务。\n    *   **Nginx 代理**: 可配合 Nginx 作为后端服务运行。\n    *   **CDN 回源**: 支持 HTTP 模式，方便接入 CDN。\n\n*   ⚡ **支持登录提升速率**: 允许用户通过 `docker login` 使用个人账户认证，将匿名用户的拉取速率限制（10次/小时/IP）提升至认证用户的（100次/小时/账户）。\n\n*   💎 **完全透明的代理**: 完美兼容 Docker Registry V2 API，客户端仅需修改镜像源地址，无额外学习成本和使用习惯的改变。\n\n*   🛡️ **高性能与安全**: 基于 **Rust** 和 **Actix Web** 构建，性能卓越、内存安全。采用流式传输处理镜像，开销极小。\n\n## 安装与部署\n\n我们提供了一键安装脚本来简化部署流程，在开始前，请提前将您的域名解析到目标主机。\n\n```bash\nbash \u003c(curl -Ls https://raw.githubusercontent.com/harrisonwang/wharf/main/install.sh)\n```\n\n脚本将引导您完成安装，并提供以下三种部署模式：\n\n---\n\n### 模式一：独立运行 (HTTPS)\n\n这是最简单、最推荐的模式。Wharf 将直接监听 80 和 443 端口，对外提供完整的 HTTPS 代理服务。\n\n**特点:**\n- 无需额外配置 Web 服务器。\n- 自动处理 HTTP 到 HTTPS 的重定向。\n- 可选择自动申请 Let's Encrypt 证书或使用您自己的证书。\n\n**安装流程:**\n1.  运行一键安装脚本。\n2.  在模式选择时，输入 `1` 或直接回车。\n3.  根据提示输入您的域名，并选择证书处理方式。\n4.  脚本将自动完成所有配置并启动服务。\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e模式二：Nginx 反向代理 (高级)\u003c/summary\u003e\n\n### 模式二：Nginx 反向代理\n\n此模式适用于您已经拥有并希望通过 Nginx 统一管理 Web 服务的场景。\n\n**特点:**\n- 由 Nginx 统一处理 HTTPS 加密和证书管理，Wharf 在后端以普通 HTTP 模式运行。\n- Wharf 作为后端 HTTP 服务运行在一个指定端口上 (如: 9000)。\n- 方便与其他服务集成。\n\n**安装流程:**\n1.  运行一键安装脚本。\n2.  在模式选择时，输入 `2`。\n3.  根据提示输入您的域名、Wharf 后端监听端口以及证书信息。\n4.  脚本会自动为您生成一份 Nginx 配置文件示例，您需要手动将其添加到您的 Nginx 配置中，并重载 Nginx 服务。\n\n\u003c/details\u003e\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e模式三：CDN 回源 (HTTP) (高级)\u003c/summary\u003e\n\n### 模式三：CDN 回源 (HTTP)\n\n此模式适用于您希望将 Wharf 作为 CDN 的源站，以获得更好的全球加速效果。\n\n**特点:**\n- Wharf 仅监听 HTTP 端口。\n- 由 CDN 服务商负责处理 HTTPS 请求和证书。\n- Wharf 会信任并处理 `X-Forwarded-*` 头，以正确识别客户端 IP 和协议。\n\n**安装流程:**\n1.  运行一键安装脚本。\n2.  在模式选择时，输入 `3`。\n3.  根据提示输入 Wharf 需要监听的 HTTP 端口。\n4.  配置您的 CDN 服务，将源站指向 Wharf 服务的地址和端口。\n\n\u003c/details\u003e\n\n\n## Docker 客户端使用\n\n配置 Docker 客户端以使用您的代理服务。\n\n### 方式一：匿名使用 (基础配置)\n\n这是最基础的配置，将 Docker 的默认请求指向您的代理服务。\n\n1.  **配置 Docker Daemon**\n\n    编辑 `/etc/docker/daemon.json` 文件 (如果不存在则创建)，并添加以下内容。将 `your-domain.com` 替换为您的域名。\n\n    ```json\n    {\n      \"registry-mirrors\": [\"https://your-domain.com\"]\n    }\n    ```\n\n2.  **重启 Docker 服务**\n\n    ```bash\n    sudo systemctl restart docker\n    ```\n    现在，`docker pull` 将通过您的代理进行拉取。\n\n### 多仓库代理\n\nWharf 支持在同一个服务进程中配置多个上游仓库。Docker Hub 仍可通过 `registry-mirrors` 使用；GHCR、Quay.io 等非 Docker Hub 仓库需要使用对应的代理域名拉取。\n\n示例配置：\n\n```toml\n[registry]\ndefault = \"dockerhub\"\n\n[[registry.upstreams]]\nname = \"dockerhub\"\nhosts = [\"docker.example.com\"]\nupstream_registry = \"https://registry-1.docker.io\"\nauth_realm = \"https://auth.docker.io/token\"\nauth_service = \"registry.docker.io\"\nauto_library_prefix = true\npublic_base_url = \"https://docker.example.com\"\n\n[[registry.upstreams]]\nname = \"ghcr\"\nhosts = [\"ghcr.example.com\"]\nupstream_registry = \"https://ghcr.io\"\nauth_realm = \"https://ghcr.io/token\"\nauth_service = \"ghcr.io\"\nauto_library_prefix = false\npublic_base_url = \"https://ghcr.example.com\"\n\n[[registry.upstreams]]\nname = \"quay\"\nhosts = [\"quay.example.com\"]\nupstream_registry = \"https://quay.io\"\nauth_realm = \"https://quay.io/v2/auth\"\nauth_service = \"quay.io\"\nauto_library_prefix = false\npublic_base_url = \"https://quay.example.com\"\n```\n\n使用示例：\n\n```bash\ndocker pull ghcr.example.com/owner/image:tag\ndocker pull quay.example.com/organization/image:tag\ndocker login ghcr.example.com\ndocker login quay.example.com\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e方式二：登录使用 (提升拉取速率)\u003c/summary\u003e\n\n此方式可以在匿名使用的基础上，通过登录您的 Docker Hub 账户来获取更高的镜像拉取速率。\n\n1.  **完成基础配置**\n\n    请确保您已经完成了 **方式一** 中的所有步骤。\n\n2.  **登录代理服务**\n\n    使用 `docker login` 命令并输入您的 Docker Hub 用户名和密码。\n\n    ```bash\n    docker login your-domain.com\n    ```\n\n3.  **同步认证信息**\n\n    登录成功后，需要手动编辑 `~/.docker/config.json` 文件，将您刚刚为 `your-domain.com` 生成的 `auth` 信息，复制一份给 `https://index.docker.io/v1/`。\n\n    修改前：\n    ```json\n    {\n        \"auths\": {\n            \"your-domain.com\": {\n                \"auth\": \"aBcDeFgHiJkLmNoPqRsTuVwXyZ...\"\n            }\n        }\n    }\n    ```\n\n    修改后：\n    ```json\n    {\n        \"auths\": {\n            \"your-domain.com\": {\n                \"auth\": \"aBcDeFgHiJkLmNoPqRsTuVwXyZ...\"\n            },\n            \"https://index.docker.io/v1/\": {\n                \"auth\": \"aBcDeFgHiJkLmNoPqRsTuVwXyZ...\"\n            }\n        }\n    }\n    ```\n    保存文件后，您的 `docker pull` 请求就会以认证用户的方式发送，从而享受更高的速率限制。\n\n\u003c/details\u003e\n\n## 开发\n\n\u003e [!NOTE]\n\u003e 详细的技术背景、系统架构和实现流程，请参阅 [**技术架构与原理文档**](docs/ARCHITECTURE.md)。\n\n1.  **克隆仓库**\n    ```bash\n    git clone https://github.com/harrisonwang/wharf.git\n    cd wharf\n    ```\n\n2.  **修改配置文件**\n    打开 `config/default.toml.example`，复制为 `config/default.toml`，然后修改配置。开发调试时建议本地跑 HTTP（8080），通过 Tunnel 对外提供 HTTPS 域名。\n\n    ```bash\n    cp config/default.toml.example config/default.toml\n    ```\n\n    然后编辑 `config/default.toml`：\n\n    ```toml\n    # config/default.toml\n\n    [server]\n    http_port = 8080      # 使用非特权端口\n    https_port = 8443\n    http_enabled = true   # 启用 HTTP\n    https_enabled = false # 禁用 HTTPS\n    behind_proxy = true\n    public_base_url = \"https://your-dev-domain.example\" # 必须填写 Tunnel 暴露给外网的地址\n\n    [registry]\n    default = \"dockerhub\"\n    upstream_registry = \"https://registry-1.docker.io\"\n    auth_realm = \"https://auth.docker.io/token\"\n    auth_service = \"registry.docker.io\"\n    auto_library_prefix = true\n\n    [tls]\n    cert_path = \"/tmp/wharf-dev.crt\"\n    key_path = \"/tmp/wharf-dev.key\"\n    ```\n\n    说明：\n    - `public_base_url` 必须与外部真实访问地址完全一致（协议/域名/端口）。\n    - 当 `https_enabled = false` 时，本地不会读取证书文件；但当前配置结构仍要求保留 `[tls]` 字段，可使用占位路径。\n\n3.  **运行项目**\n    现在，可以直接用 `cargo` 运行项目。\n    ```bash\n    cargo run\n    ```\n    服务将启动并监听在 `http://0.0.0.0:8080`。\n\n4.  **通过 Tunnel 暴露公网域名（便于本地联调）**\n    在另一个终端启动隧道，将公网请求转发到本地 `8080`。以下命令为示例，具体参数以各服务商文档为准。\n\n    ```bash\n    # ngrok\n    ngrok http 8080\n\n    # tunnl.gg（示例）\n    ssh -N -R \u003csubdomain\u003e:80:127.0.0.1:8080 \u003ctunnl-endpoint\u003e\n\n    # localhost.run\n    ssh -N -R 80:127.0.0.1:8080 nokey@localhost.run\n    ```\n\n    例如你使用固定二级域名 `example.com` 时：\n    - `public_base_url` 应设置为 `https://example.com`\n    - 隧道命令可用：`ssh -N -R dev:80:127.0.0.1:8080 ssh.edge.ng`\n\n5.  **验证链路**\n    ```bash\n    curl -i https://your-dev-domain.example/health\n    curl -i https://your-dev-domain.example/v2/\n    curl -i http://127.0.0.1:8080/v2/ -H 'Host: evil.test'\n    ```\n    预期：`WWW-Authenticate` 中的 `realm` 固定指向 `public_base_url`，不受 `Host` 头影响。\n\n6.  **构建发布版本**\n    ```bash\n    cargo build --release\n    ```\n\n## 许可证\n\n本项目采用 MIT 许可证，查看 [LICENSE](LICENSE) 了解更多信息。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharrisonwang%2Fwharf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharrisonwang%2Fwharf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharrisonwang%2Fwharf/lists"}