Skip to content

Repository files navigation

Mihomo Hub

A private, serverless Mihomo YAML profile generator and link manager.

一个运行在 Cloudflare Workers 上的私有 Mihomo 配置生成与链接管理面板。

简体中文 · English · Architecture · Security audit

Cloudflare Workers GitHub Stars Tests


简体中文

介绍

Mihomo Hub 用于把一个或多个机场订阅组合成统一的 Mihomo YAML 配置,并生成便于设备订阅的短链接。它提供密码保护的管理后台、链接 Token、自动到期、个人分流规则和访问统计,适合个人或小规模自托管使用。

主域名根路径默认展示项目介绍主页,也可以在设置中改为跳转到指定伪装页面。管理入口位于 /config,配置订阅地址格式为 /m/{短码}

当前版本是单管理员模式。面板统计的是 YAML 配置链接的请求次数与响应字节数,不是代理节点产生的真实网络流量。

功能介绍

  • Cloudflare Workers 无服务器部署
  • Cloudflare D1 持久化存储
  • /config 管理密码登录、原子限速与可撤销服务端会话
  • 配置链接创建、编辑、停用和软删除
  • 配置文件名与独立备注
  • 随机 6 位短码自动查重,手动短码支持 5~32 位
  • 系统路由与高风险弱短码黑名单(随机和手动输入双重校验)
  • 一个配置组合 1~10 个机场订阅
  • 每个机场可选择直连或模板分流组更新订阅
  • 自动生成 proxy-providers 和机场策略组
  • 可选 Token 访问保护;至少 10 位,默认随机生成 32 位
  • 永不过期或按天自动到期
  • DOMAINDOMAIN-SUFFIXDOMAIN-KEYWORDIP-CIDRIP-CIDR6 个人规则
  • 模板目录自动发现与模板兼容性检查
  • YAML 下载次数、响应字节、Token 失败和过期请求统计
  • 订阅 URL、访问 Token 和 YAML 快照 AES-GCM 加密存储
  • 根域名项目主页、可选伪装跳转
  • Cloudflare 原生登录、主页、订阅和分组统计限速;Cron 自动清理临时登录记录
  • HTTPS-only 机场订阅与仅本机监听的安全模板默认值
  • 桌面端与移动端响应式管理界面

页面与路由

地址 说明
/ 默认项目介绍主页;设置外部地址后返回 302 跳转
/config 登录入口
/config/links 配置链接管理
/config/analytics 链接访问统计
/config/settings 站点名称与伪装跳转设置
/m/{5~32位短码} 关闭 Token 后的公开 YAML 地址
/m/abc123?token=... 启用 Token 后的 YAML 地址

/m/{短码} 与未来的根目录短链接共用一份保留清单。dashboardapiloginadminsetupstatic 等系统路径,以及 000000111111123456654321888888 等明显弱短码不能创建。随机按钮会查询 D1 并避开保留值与已用短码,手动输入时页面和服务端都会校验。关闭 Token 后仍可编辑 5~32 位短码,但任何获得或猜到短码的人都能直接下载配置。

多数订阅客户端只能保存 URL,因此兼容格式仍为 /m/abc123?token=...;完整 URL 就是敏感凭据。支持自定义请求头的客户端应优先使用 /m/abc123 并发送 Authorization: Bearer <Token>。后台列表默认遮住 Token,只在复制完整链接时写入剪贴板。

快速开始

需要 Node.js 22 和 npm:

git clone https://github.com/Atsea111/Mihomo-Hub.git
cd Mihomo-Hub
npm install
cp .dev.vars.example .dev.vars

编辑被 Git 忽略的 .dev.vars。示例文件故意不提供可直接使用的密码或密钥;请用密码管理器生成管理员密码,并单独生成 APP_SECRET

openssl rand -hex 32

把 12~256 位、同时包含字母和数字的管理员密码,以及上面生成的随机值,分别填入 .dev.varsADMIN_PASSWORDAPP_SECRET,不要把 .dev.vars 提交到 Git。管理员密码不区分大小写组合,符号可选,但不能使用明显的常见、连续或重复模式。

初始化本地 D1 并启动:

npm run db:migrate:local
npm run dev

服务监听 0.0.0.0:8787,本机打开 http://localhost:8787/config。如果运行在 Docker 中,需要发布 8787:8787。默认只允许 loopback 使用明文 HTTP;确实需要从可信局域网访问 http://192.168.x.x:8787 时,在仅本机且被 Git 忽略的 .dev.vars 中设置 ALLOW_INSECURE_LAN_DEV=true,测试完应改回 false。生产环境不要设置该开关。

部署方式一:Wrangler CLI

  1. 登录 Cloudflare 并创建 D1:

    npx wrangler login
    npx wrangler d1 create mihomo-hub
  2. 不要把返回的 database_id 写入仓库。部署时通过当前终端传给临时部署配置:

    export D1_DATABASE_ID="Cloudflare 返回的 D1 UUID"
  3. 通过交互式命令创建生产 Secrets:

    npx wrangler secret put ADMIN_PASSWORD
    npx wrangler secret put APP_SECRET
  4. 迁移生产数据库并部署。脚本只会把 ID 写入被 Git 忽略的 dist/ 临时配置,不会改动 wrangler.jsonc

    npm run db:migrate:remote
    npm run deploy
  5. 在 Cloudflare Worker 的 Settings → Domains & Routes 中绑定自定义域名。

部署方式二:Cloudflare 连接 GitHub

  1. Fork 本仓库;wrangler.jsonc 中保留本地占位值 local,不要提交真实 D1 ID。

  2. 在 Cloudflare Workers & Pages 中选择 Create application → Import a repository

  3. 选择 GitHub 仓库和生产分支 main

  4. 使用以下构建设置:

    Build command:  npm run build
    Deploy command: npm run db:migrate:remote:built && npm run deploy:built
    Root directory: /
    
  5. Settings → Build → Build Variables and Secrets 中创建构建 Secret D1_DATABASE_ID,值为 npx wrangler d1 create 返回的 UUID。D1 ID 是部署绑定标识而非运行时凭据,Worker 的普通运行时变量不能替代 D1 绑定;本项目在构建后把它注入被忽略的临时部署配置。

  6. 在 Worker 的 Settings → Variables and Secrets 中创建运行时 Secret:

    • ADMIN_PASSWORD(12~256 位,必须同时包含字母和数字)
    • APP_SECRET(至少 32 个随机字符,创建数据后应长期保持不变)
  7. 触发部署。上面的 Deploy command 会先执行未应用的 D1 migration,再发布 Worker。项目内置的 Rate Limiting bindings 会随 Worker 自动创建,不需要再填变量。

不要把密码放在 GitHub Actions 普通变量、wrangler.jsoncvars.dev.vars.example 中。ADMIN_PASSWORDAPP_SECRET 是运行时 Secret;D1_DATABASE_ID 是仅供部署命令读取的 Build Secret,两类变量不要放错位置。Cloudflare 的 Secrets 文档Wrangler D1 配置Workers Builds 文档 提供了更多细节。

使用教程

  1. 打开 https://你的域名/config,输入部署时设置的 ADMIN_PASSWORD
  2. 在“设置”中填写站点名称;伪装地址留空会显示项目主页,填写外部地址才会跳转。GitHub 地址固定为本项目源码常量。
  3. 进入“链接”,点击“创建链接”。
  4. 填写 YAML 文件名和备注,选择配置模板。
  5. 填写机场名称与 HTTPS 订阅 URL;更新方式默认直连,需要代理下载时可选择模板中的分流组。点击“添加订阅”可以组合多个机场。
  6. 使用自动查重的随机 6 位短码,或手动填写 5~32 位短码。
  7. Token 开启时至少填写 10 个字符,建议提高长度和复杂度。关闭 Token 代表创建公开链接,短码仍可手动编辑。然后设置有效天数和个人分流规则。
  8. 保存后点击配置卡片中的地址即可复制完整 URL,再把它添加到 Mihomo 客户端的配置订阅中。

配置模板

模板位于 templates/mihomo/*.yaml。新增兼容模板并重新部署后,它会自动出现在创建配置的下拉框中。模板必须包含三组生成标记:

# @mihomo-hub:providers:start
# @mihomo-hub:providers:end
# @mihomo-hub:provider-groups:start
# @mihomo-hub:provider-groups:end
# @mihomo-hub:custom-rules:start
# @mihomo-hub:custom-rules:end

已创建的配置使用加密 YAML 快照。更新模板不会静默改变已有订阅;编辑并重新保存配置后才会重新生成。

开发路线

  • V1:单管理员登录和 Cloudflare Workers 部署
  • V1:多机场 YAML 生成、Token、到期和个人规则
  • V1:D1 加密存储和基础访问统计
  • 配置 DNS、IPv6、TUN、嗅探等全局模块
  • 更细粒度的策略组与规则编辑器
  • 模板版本管理、预览和差异对比
  • 用户注册、用户登录和所有者数据隔离界面
  • 订阅导入、导出与备份恢复
  • 操作日志和更完整的安全审计
  • Vercel + Postgres/Neon 部署适配
  • 多语言界面和主题设置

Technologies Used

  • Runtime: Cloudflare Workers
  • Database: Cloudflare D1 / SQLite
  • Backend: Hono, Zod, Web Crypto API
  • Frontend: React 19, React Router, Vite, Lucide React
  • Language: TypeScript
  • Testing: Vitest
  • Deployment: Wrangler, Cloudflare Workers Builds

安全说明

  • .dev.vars.wrangler/ 已被 Git 忽略。
  • 真实 D1 database_id 通过 Cloudflare Build Secret 注入临时部署配置,不进入仓库。
  • 生产密码与 APP_SECRET 必须使用 Cloudflare Worker Secrets。
  • D1 中的订阅地址、Token 和生成 YAML 使用应用层 AES-GCM 加密。
  • 登录同时受 Cloudflare 边缘限速、D1 原子单来源限速和全站限速保护;退出登录会撤销 D1 会话。
  • Token 开启时最少 10 位,界面默认生成 32 位随机值;关闭 Token 的短链接是公开地址。完整配置 URL 属于敏感凭据,后台默认遮住 Token,Workers invocation URL 日志默认关闭。
  • 升级时 0003_security_hardening.sql 会停用全部旧配置并标记旧凭据版本;在后台逐条编辑、轮换 Token 并保存后才能重新启用。
  • 模板内第三方规则地址固定到审核时的 Git commit,避免上游分支变化直接改变已生成配置;升级规则需要人工更新并重新生成配置。
  • APP_SECRET 遗失后无法恢复已有密文,请安全备份且不要随意轮换。
  • 配置链接仍然属于敏感信息;建议开启 Token,并避免在聊天记录或公开日志中分享完整链接。

English

Overview

Mihomo Hub is a private, self-hosted dashboard that combines one or more proxy subscriptions into a complete Mihomo YAML profile and exposes it through a manageable short URL. It runs on Cloudflare Workers and stores data in Cloudflare D1.

The root domain shows the project homepage by default and can optionally redirect to a configured decoy. The password-protected dashboard lives at /config, and generated profiles are served from /m/{slug}.

The current release uses a single administrator account. Analytics cover YAML profile requests and response bytes, not actual proxy traffic.

Features

  • Serverless Cloudflare Workers deployment
  • Cloudflare D1 persistence
  • Strong-password dashboard with atomic rate limits and revocable sessions
  • Create, edit, disable, and soft-delete profile links
  • Collision-checked random six-character slugs and 5–32 character custom slugs
  • Reserved route and weak-code denylist for generated and manual slugs
  • Combine up to ten subscription providers
  • Generated provider groups and provider name prefixes
  • Optional Token protection with a 10-character minimum and a recommended random 32-character default
  • Permanent or day-based expiration
  • Domain, keyword, IPv4, and IPv6 custom rules
  • Build-time template discovery and compatibility checks
  • Request, response-byte, Token-failure, and expiration analytics
  • AES-GCM encryption for subscription URLs, Tokens, and rendered YAML
  • Project homepage, optional decoy redirect, site title, and fixed GitHub Star button
  • Cloudflare public-route and analytics-write rate limiting
  • HTTPS-only provider URLs and loopback-only proxy defaults
  • Responsive desktop and mobile dashboard

Quick Start

git clone https://github.com/Atsea111/Mihomo-Hub.git
cd Mihomo-Hub
npm install
cp .dev.vars.example .dev.vars

Set local-only values in .dev.vars, then run:

npm run db:migrate:local
npm run dev

Open http://localhost:8787/config. Docker users must publish port 8787:8787.

Cloudflare Deployment

Create D1, keep its real ID out of the repository, add a 12–256 character ADMIN_PASSWORD containing letters and numbers and a 32+ character APP_SECRET as Cloudflare runtime Secrets, and deploy with a temporary shell variable:

npx wrangler login
npx wrangler d1 create mihomo-hub
npx wrangler secret put ADMIN_PASSWORD
npx wrangler secret put APP_SECRET
D1_DATABASE_ID="your-d1-uuid" npm run db:migrate:remote
D1_DATABASE_ID="your-d1-uuid" npm run deploy

Alternatively, connect the repository through Cloudflare Workers Builds. Use npm run build as the build command and npm run db:migrate:remote:built && npm run deploy:built as the deploy command. Add D1_DATABASE_ID under Settings → Build → Build Variables and Secrets; add ADMIN_PASSWORD and APP_SECRET under runtime Settings → Variables and Secrets. The build script injects the D1 ID only into the ignored generated deployment config.

See the official Cloudflare Secrets and Workers Builds documentation for current platform details.

Usage

  1. Sign in at /config with the deployed administrator password.
  2. Configure the site title and optional decoy destination under Settings. The GitHub project link is fixed in source.
  3. Create a profile and choose a YAML template.
  4. Add one or more named HTTPS subscription URLs.
  5. Token protection accepts any value of at least 10 characters and defaults to a random 32-character value. Disabling it creates a public link while keeping the 5–32 character slug editable; then choose expiration and custom rules.
  6. Save and copy the generated URL into a Mihomo-compatible client.

Roadmap

  • Cloudflare Workers MVP with single-admin authentication
  • Multi-provider generation, Tokens, expiration, and custom rules
  • Encrypted D1 persistence and link analytics
  • DNS, IPv6, TUN, and sniffing configuration controls
  • Advanced policy-group and rule editing
  • Template versions, previews, and diffs
  • Multi-user authentication and user-facing ownership
  • Backup, restore, import, and export
  • Audit logs and expanded security controls
  • Vercel and Postgres/Neon adapter
  • Internationalized UI and themes

Technology Stack

  • Cloudflare Workers and D1
  • Hono and Zod
  • React 19, React Router, Vite, and Lucide React
  • TypeScript and Web Crypto API
  • Vitest and Wrangler

Security

Never commit .dev.vars. Production credentials must be stored as Cloudflare Worker Secrets. D1_DATABASE_ID belongs to Workers Builds configuration and is not a runtime Worker Secret. Keep APP_SECRET backed up and stable: changing or losing it makes previously encrypted profile data unreadable. The security migration disables every legacy profile and requires a validated edit/credential rotation before it can be re-enabled. Query-string Tokens remain available for URL-only subscription clients; prefer Authorization: Bearer where headers are supported and treat a copied full URL as a password.

Releases

Packages

Contributors

Languages