开源 · MIT · 单二进制 · 无闭源中间件

找到对你网络最快的容器镜像源,
再把拉不动的镜像弄回家

MirrorPilot 是一个自托管的单二进制面板:对镜像源做四层真实测速、生成 daemon.json、用 GitHub Actions 把 ghcr.io 的镜像搬进你自己的仓库、接入 ddn-k8s 中转。它不坐在你的拉取路径上,也不偷偷改你的配置。

纯 Go,无 CGO linux/amd64 + arm64 中英双语界面 服务端渲染,零构建
https://your-lan:8080/probe
SPEED TEST — 四层测速,逐层归因
镜像源结果连通TokenManifest吞吐Digest
1Paneldocker.1panel.live ok1408 ms—529 ms2.0 MB/s294b68…
DaoClouddocker.m.daocloud.io ok156 ms96 ms34 ms651.5 kB/s294b68…
1ms.rundocker.1ms.run failed309 ms114 ms110 ms中断294b68…
↑ 2026-09 真实生产数据。每层单独归因:429 是限流不是挂了;被 8 MiB 上限截断的读取报「无法校验」而不是「不匹配」;横杠不是零。
What it does

四个页面,回答四个不同的问题

「哪个镜像源最快」和「这个镜像到底怎么拉」是两个问题——障碍的形状取决于镜像住在哪里。MirrorPilot 把它们分开回答。

1

测速(/probe)—— 哪个镜像源对我的网络最快?

四层分离测量:连通(GET /v2/)、Token(匿名令牌,按 registry 点名的 realm 去取,而不是瞎猜端点)、Manifest(首字节 + 本地现算摘要)、吞吐(真拉一个 blob,上限 8 MiB)。知道哪一层挂了,比一片红有用得多。

2

配置(/config)—— daemon.json 怎么写?

按实测排名生成 registry-mirrors 顺序(顺序本身就是功能),也生成 containerd 的 hosts.toml。粘贴你已有的 daemon.json,它做合并而不是替换;带注释或尾逗号的文档会被拒绝而不是静默修正——Docker 也不收。

3

搬运(/sync)—— ghcr.io 拉不动怎么办?

registry-mirrors 只对 Docker Hub 生效。对 ghcr.io / quay.io / gcr.io,正道是借 GitHub Actions 的网络:生成 workflow、写好仓库 secret、一键 dispatch。页面展示的是运行日志,而不是在按钮上假装成功。

4

中转(/config 下半页)—— 连 Actions 都不用等呢?

中转不是镜像源——镜像源在上游同一路径讲 registry 协议,中转把整条原始地址当路径。内置华为云 SWR 公益 ddn-k8s 的地址风格,设一次端点,任何镜像地址变成一条可直接 pull 的命令。默认关闭,由你决定开不开。

BACKGROUND

后台自动测速

每 30 分钟把启用的源全部重测一遍,排名不会悄悄过时。不需要解锁主密码——测速是公开的 registry 读。

CRYPTO

凭据加密落盘

Argon2id 派生密钥 + AES-256-GCM,密文绑定用途(AAD)。GitHub token 的密文挪到别处也解不开。

LOCKED

重启后锁定

派生密钥只活在进程内存。容器重启后,必须输入一次密码才能读任何已存凭据——这是设计,不是缺陷。

HONEST

摘要从不采信

blob 摘要永远由本地对收到的字节现算,绝不读响应头。指控镜像源发坏内容之前,先排除是我们自己要少了。

What it is NOT

先说清楚它不是什么

把边界说清楚,替你省时间。

✕
它不是 registry 代理不坐在你的拉取路径上。镜像源答不了的镜像,它自己也答不了——代理是放大器,不是发生器。
✕
它不是 KSpeeder 的直接替代品KSpeeder 把第三方源捆绑在自己的端点后面。MirrorPilot 测量这些源,并帮你把镜像搬进你自己控制的仓库。
✕
它不会背着你改 daemon.json只生成配置和命令,你看完再决定跑不跑。你的系统,你的手。
✕
它不是闭源中间件没有付费档位,没有「免费节点」转卖给你。MIT 协议,代码全在。
「你没有任何一台能稳定出海的机器」——这个约束排除了 Harbor / Zot 那类 pull-through cache(它自己得先够到上游),也塑造了这里的每一个设计决定。
Field data

实测结果长什么样

2026-09 在国内生产环境真实测得。引擎遵循 registry 的鉴权协议:401 带 realm 是匿名的开场白,没有 realm 的拒绝才被如实报成「需要凭据」。

DaoClouddocker.m.daocloud.io
连通 156mstoken 96msmanifest 34ms651.5 kB/s
1Paneldocker.1panel.live
连通 1408ms免 tokenmanifest 529ms2.0 MB/s
1ms.rundocker.1ms.run
连通 / token / manifest 全通吞吐偶发中断 · 如实记录
南京大学docker.nju.edu.cn
校外 403 · 需要凭据(真实)
USTCdocker.mirrors.ustc.edu.cn
域名已 NXDOMAIN · 服务收回

同一批测出的源可以诚实对比:每次运行都记录 manifest 解析到的 digest——tag 可能命中的是缓存,同一个 tag 在两个源上未必是同一份字节。

Quick start

五分钟跑起来

两条命令。首次打开网页时创建面板账号——没有默认密码,磁盘上也不预写任何东西。

bash# 拉起来
git clone https://github.com/DC1024/mirrorpilot.git
cd mirrorpilot
docker compose up -d

# 打开面板,创建账号
open http://<host>:8080

或者直接用镜像:
docker pull ghcr.io/dc1024/mirrorpilot:latest

daemon.json(生成结果示例){
  "registry-mirrors": [
    "https://docker.1panel.live",
    "https://docker.m.daocloud.io",
    "https://docker.1ms.run"
  ],
  "insecure-registries": ["192.168.43.0/24"],
  "log-driver": "json-file"
}

↑ 排名来自你自己的实测,不是别人榜单的转发。已有配置粘贴进去做合并,不属于它的字段原样保留。

本机 / NAS

docker compose

数据落在 /data 卷:SQLite、加密凭据、测速历史。重启不丢。

公网?请套 TLS

Caddy 一行 tls internal

面板保管你的 GitHub / 阿里云凭据,不要裸 HTTP 上公网。README 里有完整的 Caddy 配置(含 IP 直访的 default_sni 坑)。

忘记主密码

-reset,推倒重来

没有重置链接,也没有恢复密钥——这正是它防住「偷走 /data 卷」的原因。镜像源、设置、测速历史都会保留。