一直用一个很小众的 VPN 服务,从 2014 年用到现在,这也快 10 年了。vpnso 提供最原始的 https 的方式代理,也没有各种流行的订阅服务,但是好在稳定,不跑路。
今天做个 sing-box 的模版,自动按照国家分组,测速,自动选择,指定 GPT 服务。因为提供的 JP 服务器最多,所以默认就节点使用 jp-自动选择。最后效果
自动按照 group_keys = ['sg', 'hk', 'jp', 'us','de','uk'] 分组
规则比较简单,cnsite、cnip 会走直连,其它全部走手工选择的节点。
默认使用 JP 延迟最小的节点
GPT 使用额外的 2 台服务
可以按照地区随时切换
vpnso-templage.json
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212{ "log": { "disabled": false, "level": "warn", "output": "sing-box.log", "timestamp": true }, "dns": { "servers": [ { "tag": "default-dns", "address": "223.5.5.5", "detour": "direct-out" }, { "tag": "system-dns", "address": "local", "detour": "direct-out" }, { "tag": "block-dns", "address": "rcode://name_error" }, { "tag": "google", "address": "https://dns.google/dns-query", "address_resolver": "default-dns", "address_strategy": "ipv4_only", "strategy": "ipv4_only", "client_subnet": "1.0.1.0" } ], "rules": [ { "outbound": "any", "server": "default-dns" }, { "query_type": "HTTPS", "server": "block-dns" }, { "clash_mode": "direct", "server": "default-dns" }, { "clash_mode": "global", "server": "google" }, { "rule_set": "cnsite", "server": "default-dns" } ], "strategy": "ipv4_only", "disable_cache": false, "disable_expire": false, "independent_cache": false, "final": "google" }, "inbounds": [ { "type": "tun", "tag": "tun-in", "interface_name": "utun0", "inet4_address": "172.19.0.1/30", "inet6_address": "fdfe:dcba:9876::1/126", "mtu": 9000, "auto_route": true, "strict_route": true, "sniff": true, "stack": "system", "platform": { "http_proxy": { "enabled": true, "server": "127.0.0.1", "server_port": 2080 } } }, { "type": "mixed", "tag": "mixed-in", "listen": "127.0.0.1", "listen_port": 2080, "sniff": true, "users": [] } ], "outbounds": [ { "type": "direct", "tag": "direct-out", "routing_mark": 100 }, { "type": "block", "tag": "block-out" }, { "type": "dns", "tag": "dns-out" }, { "tag": "chatgpt1", "type": "http", "server": "xxxxxxxxxxxxxxxxxx", "server_port": 443, "username": "xxxxxxxxxxxxxxxxxx", "password": "xxxxxxxxxxxxxxxxxx", "path": "", "headers": {}, "tls": { "enabled": true } }, { "tag": "chatgpt2", "type": "http", "server": "xxxxxxxxxxxxxxxxxx", "server_port": 443, "username": "xxxxxxxxxxxxxxxxxx", "password": "xxxxxxxxxxxxxxxxxx", "path": "", "headers": {}, "tls": { "enabled": true } }, { "type": "urltest", "tag": "gpt-自动选择", "outbounds": [ "chatgpt1", "chatgpt2" ] } ], "route": { "rules": [ { "inbound": "dns-in", "outbound": "dns-out" }, { "protocol": "dns", "outbound": "dns-out" }, { "protocol": "quic", "outbound": "block-out" }, { "clash_mode": "direct", "outbound": "direct-out" }, { "clash_mode": "global", "outbound": "GLOBAL" }, { "rule_set": [ "cnip", "cnsite" ], "outbound": "direct-out" }, { "rule_set": [ "openai" ], "outbound": "gpt-自动选择" } ], "rule_set": [ { "type": "remote", "tag": "cnip", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/sing/geo-lite/geoip/cn.srs", "download_detour": "jp-自动选择" }, { "type": "remote", "tag": "openai", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/sing/geo-lite/geosite/openai.srs", "download_detour": "jp-自动选择" }, { "type": "remote", "tag": "cnsite", "format": "binary", "url": "https://github.com/MetaCubeX/meta-rules-dat/raw/sing/geo-lite/geosite/cn.srs", "download_detour": "jp-自动选择" } ], "auto_detect_interface": true, "final": "手动选择" }, "experimental": { "cache_file": { "enabled": true, }, "clash_api": { "external_controller": "127.0.0.1:9090", "external_ui": "ui", "external_ui_download_detour": "jp-自动选择", "default_mode": "rule" } }}
处理脚本
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182import requestsimport reimport jsonurl = "https://xxxxxxxxxxxxxxxxxx" # 订阅地址data = requests.get(url).textwith open('vpnso-template-openwrt.json','r') as f: vpnso = json.loads(f.read())# 找到 [Proxy] 部分的索引match = re.search(r'\[Proxy\](.*?)\n\n', data, re.DOTALL)proxy_lines = match.group(1).strip().split('\n')# 初始化一个空列表存储结果service_list = []# 处理每行数据for line in proxy_lines: # 拆分每行数据 parts = line.split(',') # 创建字典 proxy_dict = { 'tag': parts[0].split('=')[0], 'type': 'http', 'server': parts[1], 'server_port': int(parts[2]), 'username': parts[3], 'password': parts[4], "path": "", "headers": {}, "tls": { "enabled": True } } # 添加到结果列表 service_list.append(proxy_dict)# 分组关键字列表group_keys = ['sg', 'hk', 'jp', 'us','de','uk']# 初始化分组字典groups = {key: [] for key in group_keys}# 遍历数据并分组for entry in service_list: for key in group_keys: if key in entry.get('tag', ''): groups[key].append(entry['tag']) break# 构建目标数据结构service_auto_list = [ {"type": "urltest", "tag": f"{key}-自动选择", "outbounds": groups[key]} for key in group_keys if groups[key]]# 全自动选择auto_select = {"type": "urltest","tag": "自动选择","outbounds": []}auto_select['outbounds'] = [f"{key}-自动选择" for key in group_keys[:4]]# 手动选择manu_select = {"type":"selector","tag":"手动选择","outbounds":["direct-out","block-out","自动选择"],"default":"自动选择"}manu_select['outbounds']+=[f"{key}-自动选择" for key in group_keys]# GLOBALglobal_select = {"type":"selector","tag":"GLOBAL","outbounds":["direct-out","手动选择"],"default":"手动选择"}global_select['outbounds']+=[f"{key}-自动选择" for key in group_keys]# 拼接一下outbounds = service_list+service_auto_listoutbounds += [auto_select,manu_select,global_select]# 写入配置vpnso['outbounds'] += outboundsdata_json = json.dumps(vpnso, ensure_ascii=False, indent=4)with open("config.json", 'w', encoding='utf-8') as f: f.write(data_json)