Skip to the content.

使用文档 · 开发文档 · 配置文档

MagicPanel 配置文档

这份文档回答:有哪些配置、每项配置长什么样、要改它去哪里改、改完怎么验证和发布。

目标是让一个 Agent 拿到「把 X 改成 Y」这种需求时,不用读代码就能改对、改完能自测、然后安全地发出去。


目录


配置全景

面板里可配的东西一共十一类,按「先定大框架、再填内容」理解最省事:

# 配置 决定什么 改完要不要重新发布
1 节点来源 有哪些节点、什么时候更新、哪些留 要
2 本地节点 自己加的单个节点 要
3 规则来源 域名 / IP 清单 要
4 策略组 流量怎么分组 要
5 分流规则 什么流量走哪组 要
6 引擎平台 一类客户端的标识与专属扩展 要
7 引擎默认配置 这一类引擎的顶层键基线 要
8 引擎平台配置 某个「引擎+平台」的顶层键 要
9 设备独立配置 某台设备的个性化 不用,分发时实时叠加
10 拓展模块 可复用的 YAML 片段 要
11 设备 每台机器的订阅地址 不用(地址即刻生效)

判断要不要重新发布:只有第 9 项(设备独立配置)和第 11 项(设备)是分发时实时生效的,其他都要重新构建发布。


产物结构

客户端拿到的 config.yaml 由四层合并而成,优先级由低到高:

① 基础配置      引擎默认配置 → 引擎平台配置 → 设备独立配置
② 结构化内容    节点 / 策略组 / 分流规则(服务端生成,任何配置层都不许覆盖)
③ 拓展模块      启用的 YAML 片段,与引擎匹配后深度合并
④ 平台扩展      单个引擎平台专属的 YAML 片段,最后应用

产物里有哪些段(以 Stash 为例):

段 内容 谁维护
基础键 mixed-port、mode、log-level、allow-lan、ipv6、profile… 基础配置三层
dns DNS 解析、Fake-IP、策略 基础配置 / 拓展模块
tun 接管模式 基础配置 / 拓展模块
proxies 节点(含本地节点 名称 (类型)) 节点来源 / 本地节点
proxy-groups 策略组 策略组页
rule-providers 规则集引用 规则来源页
rules 分流规则 分流规则页
hosts 静态域名解析 基础配置 / 平台扩展
mtproto Telegram MTProto(仅 Stash) 设备独立配置
http / cron / script-providers Stash 专属 拓展模块 / 平台扩展

五类键任何配置层都不许写:proxies、proxy-providers、proxy-groups、rule-providers、rules。服务端硬校验,写了直接被拒。


基础配置三层

键与作用域

层 存哪 生效时机
引擎默认配置 base_configs,engine=<引擎>、platform=''、device_id=0 固化在构建快照
引擎平台配置 base_configs,engine、platform 有值、device_id=0 固化在构建快照
设备独立配置 base_configs,device_id>0 分发时实时叠加

只存与上层不同的差异:每层存的是「这一层相对上层的差量」,不是完整配置。

列表的合并语义(最容易踩)

层 语义 例子
引擎默认配置 整体替换 上层 dns.fake-ip-filter: [a, b],这一层写 [c] → 结果就是 [c]
引擎平台配置 整体替换 同上
设备独立配置 只记新增,分发时追加 上层 [a, b],这一层写 [c] → 结果 [a, b, c]

设备独立配置用追加语义,是为了「给这台机器加一条过滤」不必把整份列表复制一遍。

伪键

伪键 作用 出现在
_direct_domains 生成置顶的 DOMAIN-SUFFIX,<域名>,DIRECT 规则 引擎默认配置 / 引擎平台配置 / 设备独立配置
_fake_ip_filter 写进 dns.fake-ip-filter 同上
_panel_direct_rule 面板域名强制直连(置顶 DOMAIN-SUFFIX,<面板域名>,DIRECT) 同上

伪键只存在于配置层,编译时会被翻译掉,产物里不会出现。

常用顶层键

键 说明 备注
mixed-port 混合端口  
mode rule / global / direct  
allow-lan 允许局域网连接 MTProto 依赖它
ipv6 是否启用 IPv6  
log-level 日志级别  
profile store-selected 等  
dns.enable Mihomo 内核接管 DNS Stash 由客户端接管
dns.nameserver-policy 按域名指定 DNS 设备独立配置常用
tun Mihomo 的 TUN 模式 设备独立配置常用(桌面机)
hosts 静态解析 Mac mini 连家里 NAS 用
mtproto Telegram MTProto 仅 Stash;port / secret / ipv6 / dc-config-url

预设

base_config.PRESETS 里内置(基础配置的预设,经 /api/v1/base-config/schema 下发):

预设 引擎 说明
Stash 官方完整默认 stash 按官方文档补全:DNS、嗅探、Geo、HTTP 引擎、Google 中国站重定向
Mihomo 官方完整默认 mihomo 按官方文档补全:DNS、Geo、嗅探(HTTP 引擎是 Stash 专属)
兼容现状(精简) stash / mihomo 精简版
MTProto 代理(Telegram) stash 套用时现场生成 32 位十六进制密钥

拓展模块的预设是另一套,纯前端常量,在 src/snippetPresets.js 的 SNIPPET_PRESETS(服务端不提供预设接口)。


DNS 段:国内直连为默认,海外敏感域走代理(2026-10-27 重构)

DNS 段固化在「引擎默认配置」:源码基线 server/app/services/base_config.py 的 _DNS_COMMON / STASH_DNS / MIHOMO_OFFICIAL。引擎平台配置、平台扩展、设备独立配置、 拓展模块一律不写 dns: 键(追加合并会悄悄盖过基线);家用 Fake-IP 清单在平台层用 _fake_ip_filter 伪键维护。规范细则见 AGENTS.md 约束 31。

背景实测(2026-10-25 / 10-27,家里出口 R6S PPPoE)

通道 实测结果
明文 UDP(119.29.29.29 / 180.76.76.76 / 223.5.5.5 / 168.95.1.1) 链路被注入,www.google.com 返回 104.244.42.197 这类假 IP
国内 DoH(dns.alidns.com / 223.5.5.5 / doh.pub / dot.pub / 1.12.12.12 / 120.53.53.53) 加密挡住了链路注入,但解析器服务端对海外被墙域名投毒;对国内域名返回正确的国内 CDN 节点
境外 DoH(1.1.1.1 / 8.8.8.8 / 9.9.9.9 / dns.google / quad9 …) 国内直连一律超时或被重置,只能走代理出口

设计原则:本地答案只在两种场合被真正使用

Fake-IP 模式下,走代理的连接由代理节点在出口侧远程解析,客户端本地的解析答案 (哪怕是污染值)根本不会被使用。本地答案真正影响连通性的只有两处:

  1. 命中 Fake-IP 排除清单(fake-ip-filter)的域名——应用拿到真实 IP,答案必须干净 (+.microsoft.com / +.live.com / lens.l.google.com 这类海外域);
  2. 走 DIRECT 的连接——必须拿到正确视角的 CDN 节点 (cn / +.cn 等国内集合要国内视角;mirror-accelerate / pt / trackers 这类 「直连但服务器在境外」的集合要干净答案)。

由此得出各域名的解析路径:

域名类别 解析路径 位置
默认(含全部国内域名,未命中任何策略) 国内 DoH 直连双运营商并发:120.53.53.53(腾讯 doh.pub)/ 223.5.5.5(阿里 alidns),裸 IP,最快者生效 基线 nameserver
海外敏感域(Fake-IP 排除清单里的海外域:微软全家、lens.l.google.com) 境外 DoH 走代理:1.1.1.1 / 8.8.8.8 平台层 nameserver-policy
直连的海外集合(mirror-accelerate / pt / trackers) 同上 平台层 nameserver-policy
节点域名(*.magichub.top 等) 国内 DoH 直连,独立链路不跟随规则 proxy-server-nameserver

国内域名不需要显式策略:默认解析器就是国内 DoH,为 cn / +.cn 等再写 nameserver-policy 是纯冗余(同一台服务器),且策略命中只用单服务器、反而比 默认路径的双运营商并发差。alidns(223.5.5.5)为什么可以放在默认路径: 它对海外域名的污染答案在本设计下永远不会被使用(fake-ip 由节点远程解析、 海外敏感域显式走境外 DoH),它的国内答案与 doh.pub 实测一致;放它只为运营商冗余。

引擎差异(海外敏感域的「走代理」写法):

引擎 写法 出处
Stash 策略值写裸 IP https://1.1.1.1/dns-query,靠 follow-rule: true + 出口 IP 规则送进代理 Stash 没有 #策略组 语法(stash.wiki/features/dns-server「DNS 查询跟随规则」)
Mihomo 策略值写裸 IP https://1.1.1.1/dns-query,靠 respect-rules: true + 出口 IP 规则送进代理(需配 proxy-server-nameserver,已配;不建议与 prefer-h3 同用,prefer-h3 为 False) wiki.metacubex.one/config/dns:「dns 连接遵守路由规则」

配套规则与说明:

改 DNS 段时必须同时成立的前提

  1. 规则里有 IP-CIDR,1.1.1.1/32 / 1.0.0.1/32 / 8.8.8.8/32 / 8.8.4.4/32 → 🚀 默认代理 (境外 DoH 的出口;删掉这几条,海外敏感域解析直接超时)。
  2. 规则里有 IP-CIDR,120.53.53.53/32 / 223.5.5.5/32 → DIRECT (国内 DoH 的直连出口;Stash follow-rule 下缺了这两条,默认解析会被兜底规则送进代理)。
  3. nameserver-policy 里的 rule-set:<name> 要逐个集合写成独立的键。 rule-set:cn,ai-cn,apple-cn 这种逗号合并写法是 Stash 专有扩展,Mihomo 不认, 合并键在 Mihomo 客户端上静默失效。
  4. 兜底前的 RULE-SET,cn-ip,DIRECT 不带 no-resolve:它是”未列入集合的国内域名” 的最后直连机会,带 no-resolve 会让这些域名直接落到 MATCH → 🚀 默认代理, 从境外出口访问国内站点。为这一条多付一次国内 DNS 解析是值得的。

怎么验证

DNS 段改完,静态校验查不出问题(Stash 目标只做静态校验),要真跑:

# 用真实产物在 mihomo 上实跑。注意:产物含 tun 段,测试机上要先 tun.enable: false
# 并改掉 mixed-port,否则会劫持测试机全部流量。
mihomo -d /tmp/mpverify -f /tmp/mpverify/config.yaml   # config 里加 dns.listen 与 external-controller
curl -s "http://127.0.0.1:19090/dns/query?name=<域名>&type=A"

# 期望:国内域名(baidu / taobao / 小众国内站)→ 国内 CDN IP;
#       海外敏感域(microsoft / live / ghfast.top)→ 真实 IP(走代理的境外 DoH);
#       故障注入:把 1.1.1.1 出口规则改指向空组后,国内域名仍必须可解析——
#       默认解析不依赖代理,这是本方案与旧方案的核心区别。

节点来源

base_configs 之外的表:sources。

字段 含义 默认
name 来源名 必填
url 订阅地址(加密存储) 必填
enabled 是否参与分发 true
filter 节点过滤正则 空
ua 抓取时的 User-Agent Stash
interval 抓取间隔(秒),0 = 关自动抓取 21600
test_interval 测速间隔(秒),0 = 关自动测速 21600
client_interval 客户端更新间隔,0 = 跟随抓取间隔 0
auto_fetch 自动抓取开关 true
auto_test 自动测速开关 true
allow_private 允许内网地址节点 false
filter_unavailable 只分发可用节点 false
proxy_url 抓取走代理的地址(加密存储;留空 = 直连) 空
headers_enc 自定义请求头(名字 + 值,密文存储;列表只回显名字) 空
source_kind remote(在线抓取)/ file(上传的文件) remote

要点


本地节点

表:local_nodes。

字段 含义
name 节点名(产物里是 名称 (类型))
node_type 本地 / 自建 / 家宽 / 机房 / 专线 / 中转 / 落地
protocol 协议(决定参数表单)
server / port 地址与端口
params 协议参数(加密存储)
extra_yaml 额外 YAML 片段
enabled 是否写入产物

要点


规则来源

表:rule_providers。

字段 含义 默认
name 集合名 必填
kind remote(远程)/ inline(内联)/ repo(仓库托管) remote
url 远程地址(加密存储) 远程必填
repo_path 仓库内相对路径,如 rule/magic-chat.yaml 仓库来源必填
inline_content 内联内容 内联必填
behavior domain / ipcidr / classical domain
format yaml / text / mrs yaml
interval 抓取间隔(秒) 86400
client_interval 客户端更新间隔 0
proxy_url 抓取走代理的地址(加密存储;留空 = 直连) 空
enabled 是否参与分发 true

要点


策略组

表:proxy_groups。

字段 含义 默认
name 组名 必填
type select / url-test / fallback / load-balance / relay select
hidden 是否隐藏 false
use_sources 聚合哪些节点来源 空
local_nodes 勾选哪些本地节点 空
proxies 直接列出的节点 / 其它组 空
filter 节点过滤正则 空
url 测速地址 https://www.gstatic.com/generate_204
interval / timeout / tolerance url-test 的间隔 / 超时 / 容差(毫秒) 600 / 8000 / 150
lazy 延迟到被使用才测速 true
strategy load-balance 分配策略:一致性哈希 / 轮询 / 粘性会话 空
local_first 本地节点优先 false
targets 适用引擎平台(["*"] = 全部) ["*"]
devices 适用设备(["*"] = 全部) ["*"]

要点


分流规则

表:rules。

字段 含义 默认
type 规则类型(见下) 必填
value 匹配内容 必填
target 命中的策略组或 DIRECT / REJECT 必填
enabled 是否生效 true
no_resolve IP 字面量规则不触发解析 false
note 备注 空
targets 适用引擎平台(["*"] = 全部) ["*"]
devices 适用设备(["*"] = 全部) ["*"]

规则类型分两层校验(server/app/config.py):

  1. 创建时只认全局 13 种(config.RULE_TYPES,routers/policy.py):DOMAIN-SUFFIX、DOMAIN、DOMAIN-KEYWORD、DOMAIN-REGEX、IP-CIDR、IP-CIDR6、GEOIP、GEOSITE、RULE-SET、SRC-IP-CIDR、DST-PORT、PROCESS-NAME、MATCH。界面下拉就是这 13 种。
  2. 构建时再按引擎官方白名单复查(config.STASH_RULE_TYPES / config.MIHOMO_RULE_TYPES)。超出该引擎白名单的类型客户端加载会失败。

no-resolve 只对 IP-CIDR、IP-CIDR6、GEOIP、RULE-SET、SRC-IP-CIDR 有效。

要点


引擎平台

表:targets。

字段 含义
name 平台名(如 Stash-iOS),会拼进产物文件名
engine stash / mihomo
platform ios / macos / tvos / windows / android / linux
description 说明
extra_yaml 该平台专属的 YAML 片段,最后应用

要点


拓展模块

表:snippets。

字段 含义 默认
name 模块名 必填
category 分类(general / dns / panel / script / rewrite) general
engine stash / mihomo / all all
content YAML 内容 必填
enabled 是否启用 true
sort 合并顺序(越大越后合并) 0
note 备注 空

要点


设备

表:devices。

字段 含义 默认
name 文件名(产物文件名就是 <name>.yaml) 必填
platform 平台标签(随所选引擎平台自动带出,不参与文件名) 必填
target_id 挂在哪个引擎平台 必填
env 订阅环境 production / testing production
note 设备名(后台与门户展示用) 空
last_pull_at 任意资源(配置本体 + 规则集 + 节点来源)的最后拉取时间 空
last_config_at 配置本体(config.yaml)的最后拉取时间 空

要点


设置项

表:settings(键值对)。

键 含义 默认
base_url 对外基础地址(生成订阅链接用) 空
session_ttl_hours 会话有效期(小时) 168
profile_update_interval 配置更新提示(小时,写入响应头 profile-update-interval) 1
core_proxy 核心下载代理(仅用于安装测速核心) 空
scheduler_enabled 内置定时任务总开关 1
auto_fetch_sources / auto_fetch_rules 自动抓取来源 1
auto_test_sources 自动测速 1
auto_build_enabled 策略变化时自动构建 1
auto_build_interval_hours 构建检查间隔(小时) 1
auto_publish_enabled 校验通过后自动构建发布 1
auto_publish_env 自动构建发布到 production / testing production

WebDAV 备份相关键:webdav_url、webdav_username、webdav_password_enc、webdav_dir、webdav_interval_hours、webdav_keep、webdav_enabled。


怎么改:界面 / 接口 / 直接改库

界面

最快的方式,路径:

要改 页面
节点来源 节点来源
本地节点 节点来源 → 本地节点
规则来源 规则来源
策略组 策略组
分流规则 分流规则
引擎平台 引擎平台
引擎默认配置 / 引擎平台配置 / 设备独立配置 基础配置(左侧树选作用域)
拓展模块 拓展模块
设备 设备管理
定时任务与自动构建发布 构建发布 → 自动运行配置
账号、PIN、备份、测速核心 系统设置

接口

全部接口在 /api/v1/**,写操作需要 X-CSRF-Token(登录时返回)和会话 Cookie。

BASE=https://magichub.top:8443
# 登录,取 csrf_token
CSRF=$(curl -s -X POST $BASE/api/v1/auth/login -H 'Content-Type: application/json' \
  -d '{"username":"astral","password":"******"}' | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrf_token"])')
# 下面所有请求都带上:-b cookie.txt -H "X-CSRF-Token: $CSRF"
curl -c cookie.txt -s -X POST $BASE/api/v1/auth/login -H 'Content-Type: application/json' \
  -d '{"username":"astral","password":"******"}' > /dev/null

改配置的常用请求:

# 新增/更新分流规则
curl -b cookie.txt -X POST $BASE/api/v1/rules -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' \
  -d '{"type":"DOMAIN-SUFFIX","value":"example.com","target":"🚀 默认代理","targets":["Stash-macOS"],"devices":["*"]}'

# 调整策略组
curl -b cookie.txt -X PUT $BASE/api/v1/groups/3 -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' -d '{"name":"🚀 默认代理","type":"select","use_sources":[1,2]}'

# 改某台设备的独立配置(读出生效值 → 改 → 写回)
curl -b cookie.txt -s "$BASE/api/v1/base-config?engine=stash&platform=ios&device_id=1" \
  -H "X-CSRF-Token: $CSRF" > /tmp/layer.json
# 编辑 /tmp/layer.json 里的 "content"(YAML),再:
curl -b cookie.txt -X PUT $BASE/api/v1/base-config -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' \
  -d '{"content":"mtproto:\n  port: 5753\n  secret: 0123456789abcdef0123456789abcdef\n"}' \
  --get --data-urlencode 'engine=stash' --data-urlencode 'platform=ios' --data-urlencode 'device_id=1'

接口清单(122 个)见 docs/development/接口清单与安卓客户端说明.md。

直接改库

尽量别这么做。 真要改:

ssh archon@10.0.1.2
docker exec magicpanel python3 -c "
import sqlite3; c = sqlite3.connect('/app/data/magicpanel.db')
print(c.execute('SELECT id, name, engine, platform FROM targets').fetchall())
"

archon 是用户名,NAS 的主机名是 Altair;10.0.1.2 与 10.0.1.8 分别对应 NAS 与 Mac mini, 见环境与地址速查。

改完必须:

  1. VACUUM 或至少 PRAGMA wal_checkpoint(TRUNCATE)(WAL 模式)。
  2. 重新构建发布(快照里固化了旧数据)。
  3. 跑一次数据自检。

线上库结构由 server/app/db.py 的 SCHEMA + 迁移定义,改结构要走代码迁移,不要手动 ALTER TABLE。


改完怎么验证

1. 数据自检

scp scripts/check_data_consistency.py archon@10.0.1.2:/tmp/check_data.py
ssh archon@10.0.1.2 "docker cp /tmp/check_data.py magicpanel:/tmp/check_data.py && \
  docker exec magicpanel python3 /tmp/check_data.py /app/data/magicpanel.db"

会检查:引用完整性、命名规范、冗余覆盖、结构键越权、兜底规则顺序与范围交集、无人引用的空组。

输出分两类:

2. 产物预览

不产生构建,先看产物对不对:

curl -b cookie.txt -X POST $BASE/api/v1/base-config/preview -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' -d '{"engine":"stash","platform":"ios","device_id":1}'

或者在「基础配置」页点「预览产物」。

3. 构建校验

curl -b cookie.txt -X POST $BASE/api/v1/builds -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' -d '{"note":"改了什么"}'

返回里 results 逐目标给出 ok / errors / warnings;Mihomo 目标还会跑 mihomo -t。

4. 拉真实订阅看

curl -s "$BASE/feed/<令牌>/config.yaml" | head -40

5. 代码改动另加

cd server && ../.venv/bin/python -m pytest tests -q
npm run build

改完怎么发布

配置改动(数据变了):

# 1. 创建构建
curl -b cookie.txt -X POST $BASE/api/v1/builds -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' -d '{"note":"说明这次改了什么"}'
# 2. 校验通过后发到测试
curl -b cookie.txt -X POST $BASE/api/v1/builds/<id>/publish-to-test -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' -d '{"reason":"说明"}'
# 3. 验证没问题再发生产
curl -b cookie.txt -X POST $BASE/api/v1/builds/<id>/publish-to-prod -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' -d '{"reason":"说明"}'

代码改动:

DEPLOY_PROXY=http://10.0.1.8:7890 bash scripts/deploy.sh

DEPLOY_PROXY 指向 Mac mini 上的 Stash 混合端口。它注入到 NAS 端的构建过程,必须用内网地址 10.0.1.8。

部署脚本会跑测试、同步代码、重建容器、等健康检查、跑数据自检、验域名。代码改了但没重新构建发布,订阅内容不会变。

回滚:面板「构建发布 → 回滚至生产」;代码问题用 git revert + 重新部署。


改配置的禁忌

  1. 不要在配置层写那五个结构化键(proxies、proxy-providers、proxy-groups、rule-providers、rules),会被硬拒。
  2. 不要在兜底规则后面加规则,那条规则永远不生效。
  3. 不要用超出引擎白名单的规则类型,客户端会加载失败。
  4. 不要给 Mihomo 设备加 mtproto,Mihomo 没有这个能力。
  5. 不要建两个同「引擎+平台」的引擎平台,写入会 409。
  6. 不要手动改线上数据库结构,走代码迁移。
  7. 不要把凭据写进仓库,scripts/check_secrets.py 会拦。
  8. 改引擎默认配置后要核对官方文档,scripts/check_engine_defaults.py 会逐键对账。
  9. 别把设备独立配置当完整配置写:它只记新增项,写全量会导致上层内容被当成”这一层特有”。
  10. 改完记得发布:配置不发布,客户端拿到的还是旧的。