最后更新于:2026年06月

当你管理多节点、多协议、多用户订阅时,原始订阅链接往往格式不统一、节点数量杂乱无章。订阅转换正是解决这个问题的利器——它能把各种格式的订阅链接统一转换成 Clash/Mihomo/Shadowrocket 等客户端支持的格式,同时应用自定义规则策略、重命名节点、启用 Emoji 美化,一键生成整洁可用的配置文件。
本文将带你从零了解 subconverter 的工作原理,手动搭建本地订阅转换服务,定制 ACL 分流规则,并实现 CI/CD 自动化订阅管理。
🔑 订阅转换基础:为什么需要它?
原始订阅的问题
不同机场/服务商使用的订阅协议五花八门:
┌────────────────────────────────────────────────────┐
│ 原始订阅格式 │
│ │
│ [SS 订阅] - SIP008 JSON 格式 │
│ [Trojan 订阅] - Base64 + URL scheme │
│ [VLESS 订阅] - vless://xxx 链接 │
│ [混合订阅] - 多种协议链接的混合 Base64 编码 │
│ [Shadowrocket 订阅] - 私有格式 │
│ │
│ 问题: │
│ - 节点数量庞大,难以管理 │
│ - 无规则策略,所有流量默认走代理 │
│ - 节点名称无标准化 │
│ - 无法跨客户端共享 │
└────────────────────────────────────────────────────┘
订阅转换的价值
┌────────────────────────────────────────────────────┐
│ 订阅转换能做什么 │
│ │
│ 1. 协议统一 │
│ SSR/SS/VLESS/Trojan/Wireguard/UDP │
│ → 统一转换为 Clash/Mihomo/sing-box 配置 │
│ │
│ 2. 规则注入 │
│ 加入分流规则(国内直连、国外代理、广告拦截) │
│ │
│ 3. 节点管理 │
│ 去重、重命名、排序、标记、过滤协议类型 │
│ │
│ 4. 策略组配置 │
│ 自动/手动选择、故障转移、负载均衡 │
│ │
│ 5. 订阅合并 │
│ 多个订阅链接合并为一个订阅 │
│ │
│ 6. 规则订阅 │
│ 引用远程规则(Loyalsoldier/clash-rules 等) │
└────────────────────────────────────────────────────┘
📦 subconverter:开源订阅转换核心
subconverter 是什么?
subconverter 是目前最流行的开源订阅转换工具,由 Chinese 社区开发维护,C++ 编写,性能优异。
核心架构:
┌──────────────┐ ┌──────────────────────┐ ┌───────────────┐
│ 原始订阅链接 │ ──► │ subconverter 转换引擎 │ ──►│ 目标格式配置 │
│ (多种格式) │ │ - 协议解析 │ │ (Clash/Mihomo)│
└──────────────┘ │ - 节点标准化 │ └───────────────┘
│ - 规则模板应用 │
│ - 策略组注入 │
│ - Emoji/国旗标记 │
└──────────────────────┘
特点:
- ✅ 支持 50+ 订阅格式(各类协议、机场格式)
- ✅ 支持多种目标格式:Clash、Clash.Meta、Mihomo、Shadowrocket、sing-box、SagerNet、Surge
- ✅ 支持规则模板(ACL、自定义规则集)
- ✅ 支持节点重命名、去重、排序
- ✅ 支持自定义策略组和规则集
- ✅ 轻量级(Docker 容器 < 30MB),低资源占用
subconverter 安装部署
方式一:Docker 部署(推荐,最简单)
# 拉取最新镜像
docker pull tindy2013/subconverter:latest
# 启动容器
docker run -d \
--name=subconverter \
--restart=always \
-p 25500:25500 \
tindy2013/subconverter:latest
# 测试是否正常
curl http://127.0.0.1:25500/sub?target=clash
# 应返回一个 JSON 格式的 Clash 配置骨架方式二:二进制文件安装
# 下载最新版本(Linux amd64)
VERSION=$(curl -s https://api.github.com/repos/tindy2013/subconverter/releases/latest | grep tag_name | cut -d '"' -f 4)
curl -fsSL https://github.com/tindy2013/subconverter/releases/download/$VERSION/subconverter_linux64.tar.gz
# 解压
tar -xzvf subconverter_linux64.tar.gz
cd subconverter/
# 启动
./subconverter --backend &
# 后台运行(使用 systemd)
cat > /etc/systemd/system/subconverter.service << 'EOF'
[Unit]
Description=subconverter service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/subconverter
ExecStart=/opt/subconverter/subconverter
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now subconverter方式三:自建 Web UI 订阅转换(sub-web)
# 部署 sub-web(提供前端 UI)
docker run -d \
--name=sub-web \
--restart=always \
-p 80:80 \
-e API_URL=http://127.0.0.1:25500 \
careywong/subweb:latest
# 访问 http://your-server-ip 即可使用图形界面🔧 subconverter 核心参数详解
subconverter 通过 HTTP GET 请求的参数控制转换行为:
完整请求模板:
http://127.0.0.1:25500/sub?
target=clash&
url=URL编码后的订阅链接&
insert=true&
config=ACL模板&
emoji=true&
list=true&
sort=true&
tfo=true&
udp=true&
scv=true&
fdn=true&
file=自定义文件名
参数详解
| 参数 | 取值 | 说明 |
|---|---|---|
target |
clash/clashr/clashmeta/mixed/singbox/surge/surfboard/kitsunebi |
目标客户端格式 |
url |
Base64 编码的订阅链接(可用 ` | ` 分隔多个) |
config |
ACL 模板文件名 / URL | 规则模板 |
emoji |
true/false |
是否添加国旗 Emoji |
list |
true/false |
是否列出所有 Clash 支持的节点类型 |
sort |
true/false |
是否按延迟/负载排序 |
tfo |
true/false |
是否启用 TCP Fast Open |
udp |
true/false |
是否启用 UDP 支持 |
scv |
true/false |
是否启用 TLS SNI |
fdn |
true/false |
使用自定义域名(过滤域名) |
insert |
true/false |
是否添加附加节点(DIRECT/REJECT 等) |
file |
字符串 | 自定义下载文件名 |
实战:基础订阅转换
# 示例 1: 转换单个订阅为 Clash 格式,添加国旗
curl "http://127.0.0.1:25500/sub?target=clash&url=aHR0cHM6Ly9leGFtcGxlLmNvbS9zdWJzY3JpcHRpb24&emoji=true&list=true" -o config.yaml
# 示例 2: 合并多个订阅为 Clash.Meta 格式
# 假设 sub1_url 和 sub2_url 是两个订阅链接
SUB1=$(echo -n "https://example1.com/subscription" | base64 -w0)
SUB2=$(echo -n "https://example2.com/subscription" | base64 -w0)
curl "http://127.0.0.1:25500/sub?target=clashmeta&url=${SUB1}|${SUB2}&config=ACL4SSR_Online_NoAuto.ini&emoji=true" \
-o merged_config.yaml
# 示例 3: 指定 ACL 规则模板
curl "http://127.0.0.1:25500/sub?target=clash&url=${SUB_URL}&config=https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini&emoji=true" \
-o custom_config.yaml
# 示例 4: 启用 TFO + UDP(高性能)
curl "http://127.0.0.1:25500/sub?target=clash&url=${SUB_URL}&tfo=true&udp=true&sort=true" \
-o performance_config.yaml🎯 ACL 规则模板:自定义分流策略
ACL 模板是什么?
ACL(Access Control List)模板定义了转换后的 Clash 配置结构:
- 哪些域名直连(DIRECT)
- 哪些域名走代理(PROXY)
- 哪些域名被拦截(REJECT)
- 策略组的结构和选择逻辑
- 远程规则集的引用方式
常用 ACL 模板
# 方式一: 使用内置模板(subconverter 自带)
# 文件名: ACL4SSR_Online.ini、ACL4SSR_Online_Full.ini 等
# 方式二: 使用远程模板(实时更新)
# GitHub 上的高质量 ACL 模板:
# https://github.com/ACL4SSR/ACL4SSR/tree/master/Clash/config
# https://github.com/Loyalsoldier/clash-rules/tree/master
# https://github.com/GeQ1an/Rules/blob/master/Clash/ACL4SSR.ini
# 使用远程模板
curl "http://127.0.0.1:25500/sub?target=clash&url=${SUB_URL}&config=https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_NoAuto.ini"自定义 ACL 模板结构
; 完整 ACL 模板示例(ACL4SSR_Online.ini)
; 说明:以分号开头的行为注释
; ─────────────────────────────────────────
; 1. [custom] 节点自定义配置
; ─────────────────────────────────────────
[custom]
; 是否添加 Emoji 标志(已通过 emoji 参数控制)
; 设置自定义参数,会覆盖全局设置
; ─────────────────────────────────────────
; 2. [common] 通用配置
; ─────────────────────────────────────────
[common]
; 端口配置
port=7890
socks-port=7891
allow-lan=true
mode=rule
log-level=warning
external-controller=127.0.0.1:9090
; DNS 配置
dns-server=223.5.5.5, 119.29.29.29, 8.8.8.8, https://1.1.1.1/dns-query
; 其他配置
tcp-fast-open=true
udp=true
; ─────────────────────────────────────────
; 3. [proxy_group] 策略组配置
; ─────────────────────────────────────────
; 格式: 组名, 组类型, 节点选择规则
[proxy_group]
; 主策略组:手动选择
🚀 节点选择,select,[]
⚡ 自动选择,url-test,[]
♻️ 故障转移,fallback,[]
; 按地区策略组
🇭🇰 香港节点,select,[]
🇯🇵 日本节点,select,[]
🇺🇸 美国节点,select,[]
🇸🇬 新加坡节点,select,[]
🇹🇼 台湾节点,select,[]
; 特殊策略
🎯 全球直连,select,[]
🐟 漏网之鱼,select,[]
🛑 广告拦截,select,[]
; ─────────────────────────────────────────
; 4. [rule] 规则配置
; ─────────────────────────────────────────
; 格式: 规则文件 URL, 策略组名, 规则类型, 是否优先
[rule]
; 广告与追踪拦截
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/reject.txt,🛑 广告拦截
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/gfw.txt,🚀 节点选择
; 国内直连
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/cn.txt,🎯 全球直连
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/direct.txt,🎯 全球直连
; 代理规则
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/proxy.txt,🚀 节点选择
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/telegram.txt,🚀 节点选择
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/apple.txt,🚀 节点选择
; 流媒体规则
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/netflix.txt,🎬 流媒体
https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/spotify.txt,🎬 流媒体
; 默认规则(匹配所有未被上面规则命中的请求)
[]FINAL,🐟 漏网之鱼规则集的组织方式
Clash 规则有两种类型:经典规则行和规则集(Rule Provider):
规则结构对比:
┌──────────────────────────────────────────────────┐
│ 传统规则(完整嵌入配置) │
│ │
│ rules: │
│ - DOMAIN-SUFFIX,google.com,🚀 节点选择 │
│ - DOMAIN-SUFFIX,youtube.com,🚀 节点选择 │
│ - ... (数百行,占文件体积大) │
│ │
│ 优点: 无需额外请求 │
│ 缺点: 文件大、更新需要重新生成配置 │
└──────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────┐
│ Rule Provider(规则集远程引用) │
│ │
│ rule-providers: │
│ reject: │
│ type: http │
│ behavior: domain │
│ url: https://example.com/reject.list │
│ path: ./ruleset/reject.yaml │
│ interval: 86400 │
│ │
│ rules: │
│ - RULE-SET,reject,🛑 广告拦截 │
│ - RULE-SET,proxy,🚀 节点选择 │
│ - ... (仅需少量引用行) │
│ │
│ 优点: 文件小、自动更新、易于维护 │
│ 缺点: 首次启动需要下载规则集 │
└──────────────────────────────────────────────────┘
🎨 节点命名与管理
Emoji / 国旗标记
subconverter 能根据节点名称自动添加国旗 Emoji:
原始节点名: 转换后:
HK-Node-01 → 🇭🇰 HK-Node-01
JP-Tokyo-01 → 🇯🇵 JP-Tokyo-01
US-LA-01 → 🇺🇸 US-LA-01
Singapore-01 → 🇸🇬 Singapore-01
Taiwan-01 → 🇹🇼 Taiwan-01
Shanghai → 🇨🇳 Shanghai
参数控制:
# emoji=true # 添加国旗
# list=true # 使用完整规则列表(支持更多节点类型)
# sort=true # 按节点名称排序节点过滤与去重
# 通过参数或 ACL 过滤特定类型节点
# 1. 只保留特定协议节点(在 ACL 中配置)
# 2. 自定义过滤规则(在 ACL 的 [custom] 部分配置)
# 例如只保留香港、日本、美国节点
include=香港|日本|美国|新加坡|台湾
exclude=测试|过期|流量
# 3. 去重
# subconverter 自动根据服务器 IP + 端口去重重命名规则
可以在 ACL 模板中自定义节点重命名规则:
# 在 ACL 中自定义节点名称处理
# 配合 emoji 参数,把节点名变得更友好
原始: vless-tls-hk-node01.example.com:443
转换后: 🇭🇰 香港 01
🏗️ 自建订阅转换服务实战
方案一:VPS + Docker 完整部署
# 1. 部署 subconverter 后端
docker run -d \
--name=subconverter \
--restart=always \
-p 25500:25500 \
-v /opt/subconverter:/base \
tindy2013/subconverter:latest
# 2. 部署 sub-web 前端
docker run -d \
--name=sub-web \
--restart=always \
-p 80:80 \
-e API_URL=http://127.0.0.1:25500 \
careywong/subweb:latest
# 3. 添加 Nginx 反向代理(可选,便于 HTTPS)
# /etc/nginx/conf.d/subconverter.conf
server {
listen 443 ssl http2;
server_name sub.example.com;
ssl_certificate /etc/letsencrypt/live/sub.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sub.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:25500;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# 4. 测试
curl "https://sub.example.com/sub?target=clash&url=${SUB_URL}&config=ACL4SSR_Online.ini&emoji=true"方案二:本地部署 + 定时生成配置
#!/bin/bash
# /opt/scripts/update_subscription.sh
# 定期更新订阅的脚本
# 配置变量
SUB_URL="https://your-airport.com/subscription/link"
SUB_BASE64=$(echo -n "$SUB_URL" | base64 -w0)
OUTPUT_DIR="/opt/subscriptions"
SUB_HOST="http://127.0.0.1:25500"
# 创建输出目录
mkdir -p "$OUTPUT_DIR"
# 生成不同目标格式
echo "[1/5] 生成 Clash 配置..."
curl -s "${SUB_HOST}/sub?target=clash&url=${SUB_BASE64}&config=ACL4SSR_Online.ini&emoji=true&list=true&tfo=true&udp=true" \
-o "$OUTPUT_DIR/clash_config.yaml"
echo "[2/5] 生成 Clash.Meta 配置..."
curl -s "${SUB_HOST}/sub?target=clashmeta&url=${SUB_BASE64}&config=ACL4SSR_Online.ini&emoji=true&list=true&tfo=true&udp=true" \
-o "$OUTPUT_DIR/clashmeta_config.yaml"
echo "[3/5] 生成 Mihomo 配置..."
curl -s "${SUB_HOST}/sub?target=mihomo&url=${SUB_BASE64}&config=ACL4SSR_Online.ini&emoji=true&list=true&tfo=true&udp=true" \
-o "$OUTPUT_DIR/mihomo_config.yaml"
echo "[4/5] 生成 sing-box 配置..."
curl -s "${SUB_HOST}/sub?target=singbox&url=${SUB_BASE64}&config=ACL4SSR_Online.ini&emoji=true" \
-o "$OUTPUT_DIR/singbox_config.json"
echo "[5/5] 生成 Shadowrocket 配置..."
curl -s "${SUB_HOST}/sub?target=shadowrocket&url=${SUB_BASE64}&emoji=true" \
-o "$OUTPUT_DIR/shadowrocket_config.yaml"
# 输出统计
echo ""
echo "✅ 订阅更新完成: $(date +'%Y-%m-%d %H:%M:%S')"
ls -lh "$OUTPUT_DIR"/*.yaml "$OUTPUT_DIR"/*.json设置定时任务:
# 添加到 crontab,每 6 小时更新一次
crontab -e
# 0 */6 * * * /opt/scripts/update_subscription.sh >> /var/log/subscription.log 2>&1
# 或者使用 systemd timer
cat > /etc/systemd/system/subscription.service << 'EOF'
[Unit]
Description=Update subscription configs
After=network.target
[Service]
Type=oneshot
ExecStart=/bin/bash /opt/scripts/update_subscription.sh
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/systemd/system/subscription.timer << 'EOF'
[Unit]
Description=Update subscription every 6 hours
[Timer]
OnBootSec=5min
OnUnitActiveSec=6h
Unit=subscription.service
[Install]
WantedBy=timers.target
EOF
systemctl enable --now subscription.timer🔄 订阅合并:多订阅统一管理
为什么要合并?
如果你同时使用多个机场/服务提供商的订阅,合并订阅能带来这些好处:
- 统一出口:所有节点在一个配置文件中
- 统一策略:一套规则应用到所有节点
- 故障切换:一个机场故障时自动切换到另一个
- 最佳节点:从多个服务商的节点中选择最快的
合并命令
# 方式一:通过 subconverter 直接合并
# 使用 | 分隔多个订阅链接
SUB1=$(echo -n "https://airport1.com/sub" | base64 -w0)
SUB2=$(echo -n "https://airport2.com/sub" | base64 -w0)
SUB3=$(echo -n "https://airport3.com/sub" | base64 -w0)
# 合并三个订阅为一个 Clash 配置
curl "http://127.0.0.1:25500/sub?target=clash&url=${SUB1}|${SUB2}|${SUB3}&config=ACL4SSR_Online.ini&emoji=true&sort=true" \
-o merged_subscription.yaml
# 方式二:通过 shell 脚本合并(更灵活)
#!/bin/bash
# 合并多个订阅并保留各机场标记
MERGED=""
for i in 1 2 3; do
SUB_URL="https://airport${i}.com/sub"
SUB_B64=$(echo -n "$SUB_URL" | base64 -w0)
# 为每个机场的节点添加机场前缀
curl -s "http://127.0.0.1:25500/sub?target=clash&url=${SUB_B64}&emoji=true" \
-o /tmp/airport_${i}.yaml
# 从各配置中提取节点信息(复杂,需要 YAML 处理工具)
# ...
done
# 方式三:使用 Python/YAML 处理合并
# 适合需要精细控制的场景合并后的策略组设计
# 合并后的策略组结构示例
proxy-groups:
- name: "🚀 节点选择"
type: select
proxies:
- ⚡ 自动选择
- 🛫 机场A
- 🛫 机场B
- 🛫 机场C
- name: "⚡ 自动选择"
type: url-test
proxies:
- 🛫 机场A
- 🛫 机场B
- 🛫 机场C
- name: "🛫 机场A"
type: select
use:
- airport_a_provider # 来自订阅 A 的节点
- name: "🛫 机场B"
type: select
use:
- airport_b_provider # 来自订阅 B 的节点
- name: "🛫 机场C"
type: select
use:
- airport_c_provider # 来自订阅 C 的节点
# 使用 Proxy Provider 管理各机场的节点
proxy-providers:
airport_a:
type: http
url: https://airport1.com/subscription
path: ./proxy_providers/airport_a.yaml
interval: 3600
airport_b:
type: http
url: https://airport2.com/subscription
path: ./proxy_providers/airport_b.yaml
interval: 3600🔧 高级功能:自定义规则与模板
自定义 Clash 配置(完整示例)
# 自定义 ACL 模板输出的完整 Clash 配置
# 文件名: /opt/subconverter/configs/my_custom.ini
[common]
port=7890
socks-port=7891
allow-lan=true
mode=rule
log-level=warning
ipv6=false
external-controller=127.0.0.1:9090
tcp-fast-open=true
[dns]
enable=true
ipv6=false
enhanced-mode=fake-ip
fake-ip-range=198.18.0.1/16
nameserver=223.5.5.5,119.29.29.29
fallback=1.1.1.1,8.8.8.8
fallback-filter=geoip:cn,ipcidr:240.0.0.0/4
[proxy_group]
🚀 节点选择,select
⚡ 自动选择,url-test
🇭🇰 香港节点,select
🇯🇵 日本节点,select
🇺🇸 美国节点,select
🎯 全球直连,select
🐟 漏网之鱼,select
🛑 广告拦截,select
[rule]
; 广告拦截
https://example.com/rules/reject.list,🛑 广告拦截
; 国内直连
https://example.com/rules/cn.list,🎯 全球直连
https://example.com/rules/direct.list,🎯 全球直连
; 代理规则
https://example.com/rules/gfw.list,🚀 节点选择
https://example.com/rules/proxy.list,🚀 节点选择
; 默认规则
[]FINAL,🐟 漏网之鱼使用 Python 进行高级处理
适合对配置有完全控制需求的场景:
#!/usr/bin/env python3
# subscription_manager.py - 高级订阅管理器
import yaml
import requests
import base64
from datetime import datetime
class SubscriptionManager:
def __init__(self, subconverter_host="http://127.0.0.1:25500"):
self.host = subconverter_host
def convert(self, sub_url, target="clash", config="ACL4SSR_Online.ini"):
"""转换单个订阅"""
url_b64 = base64.b64encode(sub_url.encode()).decode()
params = {
"target": target,
"url": url_b64,
"config": config,
"emoji": "true",
"list": "true",
"tfo": "true",
"udp": "true",
}
resp = requests.get(f"{self.host}/sub", params=params)
return resp.text
def merge(self, subscriptions, output_path):
"""合并多个订阅为单个配置"""
all_configs = []
for name, url in subscriptions:
config_text = self.convert(url, target="clash")
config = yaml.safe_load(config_text)
# 为节点名添加机场前缀,避免重名
for proxy in config.get("proxies", []):
proxy["name"] = f"[{name}] {proxy['name']}"
all_configs.append(config)
# 合并所有节点
merged = {
"port": 7890,
"socks-port": 7891,
"allow-lan": True,
"mode": "rule",
"log-level": "warning",
"proxies": [],
"proxy-groups": [
{
"name": "🚀 节点选择",
"type": "select",
"proxies": [p["name"] for c in all_configs for p in c["proxies"]]
}
],
"rules": all_configs[0].get("rules", []) if all_configs else []
}
# 收集所有节点
for config in all_configs:
merged["proxies"].extend(config.get("proxies", []))
# 写入文件
with open(output_path, "w", encoding="utf-8") as f:
yaml.dump(merged, f, allow_unicode=True, default_flow_style=False)
print(f"✅ 合并完成: {output_path} ({len(merged['proxies'])} 个节点)")
return output_path
def generate_html_index(self, configs):
"""生成 HTML 索引页面(便于手机下载)"""
html = f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的订阅配置</title>
<style>
body {{ font-family: -apple-system, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; }}
h1 {{ color: #2c3e50; }}
ul {{ list-style: none; padding: 0; }}
li {{ margin: 10px 0; padding: 15px; background: #f8f9fa; border-radius: 8px; }}
a {{ color: #3498db; text-decoration: none; font-weight: 600; }}
a:hover {{ text-decoration: underline; }}
.updated {{ color: #7f8c8d; font-size: 12px; margin-top: 20px; }}
</style>
</head>
<body>
<h1>📱 我的订阅配置</h1>
<ul>
"""
for name, filename in configs:
html += f' <li><a href="{filename}">{name}</a></li>\n'
html += f""" </ul>
<div class="updated">最后更新: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</div>
</body>
</html>"""
return html
# 使用示例
if __name__ == "__main__":
manager = SubscriptionManager()
# 合并多个订阅
subscriptions = [
("机场A", "https://airport1.com/sub"),
("机场B", "https://airport2.com/sub"),
]
merged = manager.merge(subscriptions, "/var/www/subscriptions/merged.yaml")
html = manager.generate_html_index([("合并订阅", "merged.yaml")])
# 保存索引页
with open("/var/www/subscriptions/index.html", "w", encoding="utf-8") as f:
f.write(html)
print("完成!")🔍 故障排查手册
问题 1:subconverter 无法连接
# 检查容器是否运行
docker ps | grep subconverter
# 检查端口监听
ss -tlnp | grep 25500
# 直接测试转换服务
curl -v http://127.0.0.1:25500/
# 检查日志
docker logs subconverter --tail 50问题 2:订阅解析失败(返回空配置或错误)
常见原因:
1. 订阅链接本身无法访问
→ 用 curl 直接测试订阅链接是否可下载
curl -v "https://your-airport.com/subscription"
2. 订阅格式不被支持
→ 查看 subconverter 支持的格式
→ 尝试手动解析订阅内容(Base64 解码)
3. 编码问题
→ 确保 URL 中的订阅链接正确 Base64 编码
→ 如果订阅链接包含特殊字符,需要双重编码
4. 网络问题(VPS 无法访问订阅服务器)
→ 测试 VPS 的网络连通性
→ 检查 DNS 解析
问题 3:生成的配置无法使用
# 检查生成的 YAML 格式是否正确
python3 -c "import yaml; yaml.safe_load(open('config.yaml'))"
# 在 Clash/Mihomo 客户端测试
# 观察客户端日志中的错误信息
# 常见问题:
# 1. 节点名重复 → 在 ACL 中开启去重
# 2. 协议不被支持 → 更新客户端或调整转换目标
# 3. 规则集 URL 无法访问 → 检查 VPS 是否能访问 GitHub
# 4. DNS 配置问题 → 手动覆盖 DNS 配置部分
# 修复方法: 调整 ACL 模板
# 或者在生成的配置上进行后处理问题 4:规则集无法下载
# 确保 VPS 能访问 GitHub
curl -I https://raw.githubusercontent.com/Loyalsoldier/clash-rules/release/reject.txt
# 如果无法访问,考虑使用镜像或 CDN
# 替换为 FastGit 等国内镜像
# https://raw.fastgit.org/Loyalsoldier/clash-rules/release/reject.txt
# 或者使用本地规则文件
# 1. 下载规则文件到本地
# 2. 在 subconverter 配置中使用本地路径
# 使用 sing-box 规则集(如果 sing-box 作为客户端)
# 格式与 Clash 有所不同,需要调整问题 5:节点去重不工作
在 ACL 模板的 [custom] 部分添加去重规则
或在请求参数中添加 sort=true
问题通常出现在:
1. 同一节点使用不同名称/端口(例如 IP vs 域名)
2. 不同机场共用同一节点(CDN 架构)
3. UDP 与 TCP 被识别为不同节点
解决方案:
→ 使用 YAML 工具后处理去重
→ 在 ACL 模板中添加 include/exclude 规则
→ 手动指定保留/排除名单
问题 6:Emoji/国旗标记不正确
可能原因:
1. 节点名称不符合解析规则
2. subconverter 的国旗映射表不完整
3. 某些国家代码未被识别
解决方案:
→ 在 ACL 模板的 custom 部分自定义映射
→ 手动重命名节点(使用 Python/YAML 后处理)
→ 添加自定义国旗规则
配置示例:
在 subconverter 的配置中添加自定义节点名称处理:
[custom]
custom-host=
# 自定义节点名替换规则
custom=🇭🇰 香港|🇯🇵 日本|🇺🇸 美国|🇸🇬 新加坡|🇹🇼 台湾|🇬🇧 英国|🇩🇪 德国
📱 订阅订阅:手机端使用
iOS 端订阅
Shadowrocket (小火箭):
1. 打开 Shadowrocket → 配置 → 导入配置
2. 从 URL 导入: https://your-domain.com/config.yaml
3. 或使用内置的订阅功能: 配置 → 订阅 → 添加
4. 填入转换后的 Clash 配置 URL
注意: 推荐使用 subconverter 的 shadowrocket 目标格式
Android 端订阅
Clash for Android / Clash Meta for Android:
1. 配置 → 从 URL 导入
2. 填入: https://your-domain.com/clashmeta_config.yaml
3. 自动更新: 设置每 24 小时更新一次
NekoBox / sing-box:
1. 配置 → 分组或订阅
2. 添加转换后的配置 URL
3. sing-box 需要 sing-box 目标格式
自动更新订阅
# 在客户端配置中启用自动更新(Clash for Android)
# 1. 添加订阅配置
# 2. 设置更新间隔(推荐 6-12 小时)
# 3. 启用"自动更新"
# 使用 subconverter 的订阅链接格式:
https://your-subconverter-domain.com/sub?target=clashmeta&url=BASE64_URL&config=ACL4SSR_Online.ini&emoji=true&list=true&tfo=true&udp=true
# 客户端会周期性请求该 URL,获取最新配置🚀 最佳实践总结
1. 推荐的部署架构
┌──────────────────────────────────────────────────┐
│ 完整订阅管理架构 │
│ │
│ 原始订阅 (机场) │
│ │ │
│ ▼ │
│ ┌─────────────────────────┐ │
│ │ subconverter 转换服务 │ ← Docker 容器 │
│ │ + ACL 规则模板 │ │
│ │ + Emoji 标记 │ │
│ │ + 节点管理 │ │
│ └─────────┬──────────────┘ │
│ │ │
│ ┌──────┴─────────┐ │
│ ▼ ▼ │
│ 静态文件服务器 管理脚本 │
│ (Nginx) (Cron/Systemd) │
│ │ │ │
│ └────────┬───────┘ │
│ ▼ │
│ 生成的配置文件 │
│ - clash_config.yaml │
│ - clashmeta_config.yaml │
│ - singbox_config.json │
│ - shadowrocket_config.yaml │
│ │
│ 用户端(手机/电脑) │
│ - 配置 URL 自动更新 │
│ - 6-12 小时刷新一次 │
└──────────────────────────────────────────────────┘
2. 维护技巧
- ACL 模板定期更新:从 GitHub 拉取最新的规则模板,避免规则过时
- 节点健康监控:使用脚本定期测试节点连通性和延迟
- 多备份:保留多个订阅链接,避免单个机场故障
- 日志记录:保存订阅更新日志,便于排查问题
- 版本控制:对重要配置使用 Git 管理,便于回滚
3. 安全注意事项
⚠️ 自建订阅转换服务的安全要点:
1. 限制访问来源
- 使用 Nginx 的 allow/deny 规则
- 或使用基本认证 (Basic Auth)
2. 避免暴露订阅链接
- 不要在公开场合分享你的完整订阅链接
- 订阅转换服务应该只在内部或受控网络中运行
3. 使用 HTTPS
- 为订阅转换服务配置 TLS 证书
- 使用 Let's Encrypt 自动续期
4. 定期更新 subconverter
- 关注 GitHub Release
- 使用 Docker 时: docker pull tindy2013/subconverter:latest && docker restart subconverter
5. 节点去重与隐私
- 避免在节点名称中暴露敏感信息(如真实 IP)
- 使用 ACL 模板过滤不需要的协议和节点
结语
订阅转换是代理管理的"最后一公里"——它让零散的订阅链接变成整洁可用的客户端配置。掌握 subconverter 和 ACL 模板,你可以:
- ✅ 统一管理多订阅:多机场、多协议、多节点合并为一个配置
- ✅ 自定义分流规则:国内直连、国外代理、广告拦截精确控制
- ✅ 自动化订阅更新:配合 cron/systemd,配置每 6 小时自动刷新
- ✅ 支持多客户端:Clash、Mihomo、Shadowrocket、sing-box、NekoBox 一网打尽
- ✅ 节点标准化:自动添加国旗、去重、排序、重命名
建议的日常流程:
每天/每 6 小时:
subconverter 从各机场拉取订阅
↓
应用 ACL 规则模板(规则集自动从 GitHub 更新)
↓
生成不同客户端格式的配置文件
↓
部署到静态文件服务器 (Nginx)
↓
手机/电脑通过 URL 自动更新
订阅转换是一项"配置一次,长期受益"的工作。花几个小时搭建好你的私有订阅转换服务,就能获得自动化、稳定、灵活的代理配置管理体验。
愿你的订阅管理从此简单高效!🎯