- 新增 §12:PAC 不能直接下发的原因、三个规则集产物、PAC 更新后的再生成流程、 mihomo/Shadowrocket 两种客户端接入方式与验证口径 - 新增 rrpp-subscription/:API.md(订阅端点/method/rules 参数/规则集说明) 与 gen_rulesets.py(PAC → 客户端规则集转换脚本,幂等、原子替换) - method 新增 shadowrocket(.conf:远程 RULE-SET + FINAL,不猜测 REALITY 参数) - method=clash 新增 &rules=provider|inline|global
7.4 KiB
7.4 KiB
RRPP 订阅服务 · SSO 认证接入文档
架构:客户端 → nginx(api.rrrosmontis.icu) → RRPP 后端(127.0.0.1:5010) → SSO(127.0.0.1:4550) → nodes.json(国家分层)
1. 客户端公开端点
统一订阅端点
GET https://api.rrrosmontis.icu/v1/rrpp/subscription?method=<类型>&user=<b64url邮箱>&password=<b64url密码>[&prefer=<协议>][&rules=<模式>]
| 参数 | 必填 | 说明 |
|---|---|---|
method |
是 | clash / v2ray / shadowrocket / rrpp_client |
user |
是 | URL-safe base64 编码的邮箱 |
password |
是 | URL-safe base64 编码的密码 |
prefer |
否 | vless / ss / http,指定优先协议;缺省 vless,无则回退 vless→ss→http |
rules |
否 | 仅 method=clash:provider(默认) / inline / global,见 §7 |
token |
否 | SSO 会话 token(免密,代登录态);与 user/password 二选一 |
旧端点(兼容)
GET /v1/rrpp/nodes_update?user=<b64>&password=<b64>
等价于 method=rrpp_client。
2. method 说明
| method | Content-Type | 内容 | 适用客户端 |
|---|---|---|---|
clash |
text/yaml |
Clash YAML:proxies + proxy-groups(RRPP) + rule-providers + rules(备注 R.R.P.P. - 国家代码) |
mihomo / Clash Verge / ClashX Meta |
v2ray |
text/plain |
base64 节点串(vless:// / ss:// / http://) |
v2rayN / Shadowrocket / Quantumult |
shadowrocket |
text/plain |
Shadowrocket .conf:[General] + 远程 RULE-SET + FINAL(不含节点) |
Shadowrocket |
rrpp_client |
application/json |
旧格式节点 JSON(仅 http,remark = 服务商 流量) |
RRPP 自建客户端 |
3. 返回码
| 码 | 场景 |
|---|---|
| 200 | 成功 |
| 401 | 凭据缺失/SSO 认证失败 |
| 403 | tier=0(RRPP 未开通) |
| 404 | method 未知,或 rules 取值非法 |
| 502 | SSO 不可达 |
| 503 | nodes.json 缺失/损坏,或该 tier 无可用节点 |
4. nodes.json 格式(国家分层)
C:/BtSoft/nginx/others/htmlResources/private/RRPP/nodes.json,顶层为国家数组:
[
{
"country": "JP", // 国家代码
"available_level": [1, 2, 3], // 可见等级
"provider": "Azure", // 服务商
"traffic": "15G", // 流量限额
"domain": "iam.aeolianchi.me", // 域名
"ipv6_only": false, // 可选,true 时备注加 (IPv6)
"methods": { // 可用协议
"http": { "port": ..., "username": ..., "password": ... },
"vless": { "port": ..., "uuid": ..., "flow": ..., "sni": ..., "public_key": ..., "short_id": ... },
"ss": { "port": ..., "method": ..., "password": ... }
}
},
...
]
5. 协议选择逻辑
prefer指定则优先用该协议- 缺省默认
vless(最好用) - 该国家无
prefer协议时按vless → ss → http回退 rrpp_client固定只用http(兼容性),备注 =provider + traffic(IPv6 加(IPv6))
6. SSO 认证
- 后端调 SSO
POST http://127.0.0.1:4550/v1/sso/service/rrpp/nodes(带X-SSO-Service-Token+X-Real-IP) - SSO 返回
{tier: 0|1|2|3},0=未开通 - 服务密钥读
sso-rrrosmontis-icu/secrets.json的service_tokens.rrpp
7. 分流规则(PAC → 规则集,随订阅下发)
7.1 为什么不是直接下发 PAC
PAC 是给浏览器/操作系统用的 JS 自动配置;mihomo/Clash 与 Shadowrocket 都不能读 PAC。
两者唯一共同能吃的格式是「每行自带规则类型的规则行文本」(Clash 术语 behavior: classical):
- mihomo:
rule-providers(behavior: classical+format: text) - Shadowrocket:
RULE-SET,<url>,<策略>(官方手册要求「规则集的内容需包含规则类型」)
因此把 PAC 数据在后端一次性转换成三个规则集文件,两种客户端共用同一份文件。
7.2 规则集文件(CDN 公开)
生成目录即 CDN 根下的 RRPP/PAC/,公开可访问、无鉴权(规则集本身不含节点信息):
| 规则集 | 文件 | 规则数 | 组成 | 策略 |
|---|---|---|---|---|
rrpp-proxy |
rrpp-proxy.list |
3943 | 539 DOMAIN + 3404 DOMAIN-SUFFIX(强制代理域名) |
RRPP / PROXY |
rrpp-direct |
rrpp-direct.list |
16 | 16 DOMAIN-SUFFIX(保守直连种子) |
DIRECT |
rrpp-cn-ip |
rrpp-cn-ip.list |
7456 | 7456 IP-CIDR(中国 IP 段) |
DIRECT |
URL:https://cdn.rrrosmontis.icu/RRPP/PAC/<文件名>
体积:120366 / 386 / 177443 字节,合计 11415 条规则。
7.3 规则顺序(与 PAC 语义一致)
RULE-SET,rrpp-proxy → RRPP # 强制代理优先(PAC 中强制代理规则优先级更高)
RULE-SET,rrpp-direct → DIRECT # 直连种子
RULE-SET,rrpp-cn-ip → DIRECT # 中国 IP 直连
MATCH → RRPP # 其余全走代理
7.4 维护流程(PAC 更新后)
转换脚本 gen_rulesets.py(与本文件同目录,另在仓库 server_config/rrpp-subscription/ 存有副本):
python gen_rulesets.py # 读 PAC 目录 → 原子覆写三个 .list(幂等,内容不变则不写)
python gen_rulesets.py --check # 只检查将有哪些变化,不写盘
python gen_rulesets.py --pac-dir <目录> --out-dir <目录> --quiet
- 输入:
pac_domains.json/pac_direct_domains.json/pac_ip_cn.json - 转换规则:
full:x→DOMAIN,x;keyword:x→DOMAIN-KEYWORD,x;regexp:/include:→跳过并计数;行内#注释剥离;*.x/普通域名→DOMAIN-SUFFIX,x - 输出排序去重、LF 换行、无注释,写盘用临时文件 +
os.replace原子替换 - 订阅端无需任何改动:文件名与 URL 固定,客户端按
interval自动拉新规则
7.5 客户端接入
| 场景 | 用法 |
|---|---|
| mihomo / Clash Verge(推荐) | &method=clash → 规则走 rule-providers,YAML 约 2.4KB,规则每 24h 自动更新 |
客户端不认 rule-providers,或想「导入一次到位」 |
&method=clash&rules=inline → 规则内联进 YAML(约 440KB),导入即含节点+全部规则 |
| Shadowrocket(只想要规则,节点另行导入) | &method=shadowrocket → .conf,规则走远程 RULE-SET(在「配置 → 规则集URL」中可见并自动更新) |
| Shadowrocket(想一次导入节点+规则) | 用 &method=clash&rules=inline(小火箭兼容 Clash YAML,含节点信息的标准 Clash 链接可同时导入配置与节点) |
| 兜底 / 排障 | &rules=global → 只有 MATCH,RRPP,全流量走代理(等价旧行为) |
method=shadowrocket的.conf不写[Proxy]段:Shadowrocket 的 REALITY 参数写法官方未文档化,不猜测; 该配置的策略PROXY指向首页当前选中的节点,节点请用clash/v2ray订阅导入。
7.6 验证记录(2026-09-19)
- 生成:11415 条规则;
regexp:跳过 7 条、非法 1 条 - CDN:三个 URL 均 HTTP 200,
md5与本地生成一致(806808b8/8f89397e/3e75093d) - mihomo v1.19.31 真实内核运行验证:
-t校验通过;运行时GET /providers/rules显示rrpp-proxy=3943、rrpp-direct=16、rrpp-cn-ip=7456(behavior=Classical),落地文件字节数与生成完全一致;&rules=inline配置亦通过-t校验 - Shadowrocket 为 iOS 应用,未做实机验证,仅依据官方手册的
RULE-SET/ Clash YAML 兼容说明实现