本文需要读者对 Clash 配置文件有基本的了解,知道 proxy
, proxy-group
, rule
和 订阅
的概念。
CFW 预处理
起因
我经常需要使用 ChatGPT 解决问题,但是由于 ChatGPT 的 Web 服务使用了 Cloudflare 服务拦截了所有大陆地区的访问和全球各地很多的代理节点,我的节点提供商提供了一批可以访问 ChatGPT 的节点,并在它们的名字中添加了 chatGPT
字段,如 【I】日本 VIP 4 - chatGPT
。这让我可以在想要使用 ChatGPT 的时候,通过更换节点的方式访问,进而避免被 Cloudflare 拦截。
不过,这是一件非常麻烦的事情。首先,每次想要使用 ChatGPT,我都必须记得切换节点,否则会被 ChatGPT 警告:“所在地区不提供服务”、“违反规定使用代理访问” 等等,出现这种警告过后还需要清理浏览器缓存。其次,如果我在使用完 ChatGPT 的使用忘记切换回原本的节点,这会让我后续所有网络连接延迟增加。此外,我在使用 ChatGPT 的时候,所有节点的流量均从 chatGPT
节点流出,这对我当时其他 Web 服务的使用产生了影响。
其实,要想解决这个问题是非常简单的,只需要节点提供商在提供的配置文件中将这些节点整理到一个策略组,再让所有有关 openai.com
的流量从这个策略组走就解决了,不过它并没有这么做。既然节点提供商没有写这个策略组,那我就自己写。
需求分析
- 将所有包含
chatGPT
字段的节点整理在一个叫OpenAI
的策略组中 - 将所有与
openai.com
的流量导向OpenAI
策略组 - 在节点提供商的配置文件更新时,
OpenAI
策略组也需要更新
使用 Parsers
CFW 提供了一个处理 Profile
的工具 —— Parsers
路径:Settings => Profiles => Parsers
关于 Parsers
官方描述如下:
Modify and customize your profiles after download but before Diff
翻译:
在你的配置文件下载完成后、进行 Diff 操作前,修改和定制你的配置文件
文档描述得非常详细,也提供了很多操作配置文件的方法,这里简单列出几个:
参数说明
键 值类型 操作 append-rules 数组 数组合并至原配置 rules
数组后prepend-rules 数组 数组合并至原配置 rules
数组前append-proxies 数组 数组合并至原配置 proxies
数组后prepend-proxies 数组 数组合并至原配置 proxies
数组前append-proxy-groups 数组 数组合并至原配置 proxy-groups
数组后prepend-proxy-groups 数组 数组合并至原配置 proxy-groups
数组前mix-proxy-providers 对象 对象合并至原配置 proxy-providers
中mix-rule-providers 对象 对象合并至原配置 rule-providers
中mix-object 对象 对象合并至原配置最外层中 commands 数组 在上面操作完成后执行简单命令操作配置文件 Commands 使用方法(beta)
commands 是一组简单的命令,作为上面操作的补充
我的 Parsers
在这里我使用了 prepend-proxy-groups
和 commands
实现我的需求。配置如下:
parsers:
- url: https://example.com/config.yaml # 必须和 Profile 的订阅链接一致
yaml:
prepend-proxy-groups: # 数组合并至原配置`proxies`数组**前**
- name: OpenAI # 策略组的名字叫做 “OpenAI”
type: select # 策略组的类型是 “手动选择”
commands: # 命令
- proxy-groups.OpenAI.proxies+[]proxyNames|.*chatGPT.* # 在所有策略组中找到 “OpenAI” 策略组,在该策略组中添加所有定义的节点名,并按“.*chatGPT.*”正则表达式过滤
- rules.-18+DOMAIN-SUFFIX,openai.com,OpenAI # 在规则的倒数18的位置上添加 DOMAIN-SUFFIX,openai.com,OpenAI
简单解释一下每一行的作用是什么:
- url 用于告诉 CFW 当这个订阅更新时执行预处理
- prepend-proxy-groups 用于添加一个策略组,因为使用 commands 添加策略组并不方便
- 正则表达式
.*chatGPT.*
的意思是包含chatGPT
字段为真 -18
并不泛用,这是我根据节点提供商的配置文件确定的位置,关于如何确定位置,只需要避免相关域名被前面的规则拦截就好了DOMAIN-SUFFIX
是判断域名中是否包括后面的字段,包括为真,不包括为假
测试
在强制更新相关订阅之后,在 Proxies 栏下,我们可以找到这个名为 OpenAI
的策略组
在尝试访问 ChatGPT 的网页时
可以发现规则也生效了,实现了分流
痛点
经过一段时间的使用,我发现使用 Parsers 有一些不方便的地方
- 只能将新的策略组添加在原策略组的首部或者尾部,不能在中间添加,也不能对原策略组排序
- 新规则的添加要在原配置文件的基础上数列表的位置
commands
存在 bug,在使用-
时可能失效- 不支持多个订阅合成为一个配置文件
Clash 配置文件的使用
虽然 CFW 预处理很强大,但是它现阶段并不能完全满足我的需求,详见痛点。
所以我打算自己写 Clash 原生的配置文件。
仿写
仿照我现有的三家节点提供商的配置文件,我写好了配置文件的基本结构
port: 7890
socks-port: 7891
allow-lan: true
mode: Rule
log-level: info
external-controller: :9090
dns:
enable: true
ipv6: false
default-nameserver: [223.5.5.5, 119.29.29.29]
fake-ip-range: 198.18.0.1/16
use-hosts: true
nameserver: ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query']
fallback: ['https://doh.dns.sb/dns-query', 'https://dns.cloudflare.com/dns-query', 'https://dns.twnic.tw/dns-query', 'tls://8.8.4.4:853']
fallback-filter: { geoip: true, ipcidr: [240.0.0.0/4, 0.0.0.0/32] }
proxies:
proxy-groups:
rules:
添加 Proxy-Providers
参考官方文档 的关于 provider1
的写法
我将两家节点提供商的所有节点添加进了我的配置文件中(为了避免广告嫌疑,我将节点提供商的信息简单处理了一下)
proxy-providers:
Sxxxxxxm:
type: http
path: ./profile/proxies/sxxxxxxm.yml
url: "https://example1.com/config1.yml"
interval: 86400
health-check:
enable: true
url: http://www.gstatic.com/generate_204
interval: 1800
nxxxxxxt:
type: http
path: ./profile/proxies/nxxxxxxt.yml
url: "https://example2.com/config2.yml"
interval: 86400
health-check:
enable: true
url: http://www.gstatic.com/generate_204
interval: 900
编写 Proxy-Groups
在查阅相关文档后,我决定在 Proxy-Groups
中使用 filter
官方示例:
# select is used for selecting proxy or proxy group # you can use RESTful API to switch proxy is recommended for use in GUI. - name: Proxy type: select # disable-udp: true # filter: 'someregex' proxies: - ss1 - ss2 - vmess1 - auto
我的 Proxy-Groups:
proxy-groups:
- name: 手动选择
type: select
use:
- Sxxxxxxm
filter: '^((?!GAME).)*(VIP|IEPL).*$'
- name: 节点选择
type: select
proxies:
- 手动选择
- 自动选择
- 大流量
- OpenAI
- 回国
- DIRECT
- name: 大流量
type: url-test
url: 'http://www.gstatic.com/generate_204'
interval: 300
use:
- nxxxxxxt
- name: OpenAI
type: url-test
url: 'http://www.gstatic.com/generate_204'
interval: 3600
use:
- Sxxxxxxm
filter: '(.*chatGPT.*)'
- name: 回国
type: select
proxies:
- Vxxxxxxd
- name: 自动选择
type: url-test
url: http://www.gstatic.com/generate_204
interval: 1800
use:
- Sxxxxxxm
filter: '^((?!GAME).)*(VIP|IEPL).*$'
我设置了六个策略组分别处理我的需求
组名 | 功能 |
---|---|
手动选择 | 将我可能手动选择的节点放在这里,用以应对紧急情况 |
节点选择 | 这是所有其他策略组的集合,是规则的主干道,所有未分流的流量均从这里选定的策略组中经过 |
大流量 | 让所有较大的、不考虑稳定性和不考虑延迟的流量从这个策略组经过 |
OpenAI | 包含了所有可以访问 ChatGPT 的节点 |
回国 | 顾名思义,用于回国的节点 |
自动选择 | 跟手动选择的内容几乎是一样的,区别在于自动选择会挑选延迟最低的那个,而手动不会 |
除了我上面使用 select
和 url-test
之外,type
字段还有其他选择,这里简单整理一下:
字段 | 官方描述 |
---|---|
relay | relay chains the proxies. proxies shall not contain a relay. No UDP support. |
url-test | url-test select which proxy will be used by benchmarking speed to a URL. |
fallback | fallback selects an available policy by priority. The availability is tested by accessing an URL, just like an auto url-test group. |
load-balance | load-balance: The request of the same eTLD+1 will be dial to the same proxy. |
select | select is used for selecting proxy or proxy group |
添加 Rule-Providers
Rule-Providers 的官方描述:
Rule Providers are pretty much the same compared to Proxy Providers. It enables users to load rules from external sources and overall cleaner configuration. This feature is currently Premium core only.
这是固定的配置,基本没有什么变化:
rule-providers:
reject:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/reject.txt"
path: ./ruleset/reject.yaml
interval: 86400
icloud:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/icloud.txt"
path: ./ruleset/icloud.yaml
interval: 86400
apple:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/apple.txt"
path: ./ruleset/apple.yaml
interval: 86400
google:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/google.txt"
path: ./ruleset/google.yaml
interval: 86400
proxy:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/proxy.txt"
path: ./ruleset/proxy.yaml
interval: 86400
direct:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/direct.txt"
path: ./ruleset/direct.yaml
interval: 86400
private:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/private.txt"
path: ./ruleset/private.yaml
interval: 86400
gfw:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/gfw.txt"
path: ./ruleset/gfw.yaml
interval: 86400
tld-not-cn:
type: http
behavior: domain
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/tld-not-cn.txt"
path: ./ruleset/tld-not-cn.yaml
interval: 86400
telegramcidr:
type: http
behavior: ipcidr
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/telegramcidr.txt"
path: ./ruleset/telegramcidr.yaml
interval: 86400
cncidr:
type: http
behavior: ipcidr
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/cncidr.txt"
path: ./ruleset/cncidr.yaml
interval: 86400
lancidr:
type: http
behavior: ipcidr
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/lancidr.txt"
path: ./ruleset/lancidr.yaml
interval: 86400
applications:
type: http
behavior: classical
url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/applications.txt"
path: ./ruleset/applications.yaml
interval: 86400
这里面所有的配置信息均来自 Loyalsoldier/clash-rules,作者使用 GitHub Actions 北京时间每天早上 6:30 自动构建,保证规则最新。
编写 Rules
按照我的理解,rule-providers
相当于把一些网站整理成了一个集合,进而方便我们在 rules
中调用
我的 Rules:
rules:
- RULE-SET,applications,DIRECT
- RULE-SET,private,DIRECT
- RULE-SET,reject,REJECT
- RULE-SET,icloud,DIRECT
- RULE-SET,apple,DIRECT
- DOMAIN-SUFFIX,openai.com,OpenAI
- DOMAIN-SUFFIX,terabox.com,大流量
- DOMAIN-KEYWORD,civitai,大流量
- RULE-SET,proxy,节点选择
- RULE-SET,direct,DIRECT
- RULE-SET,lancidr,DIRECT
- RULE-SET,cncidr,DIRECT
- RULE-SET,telegramcidr,大流量
- MATCH,节点选择
我使用的白名单的结构,这可以更好的保证访问的安全性
更多详细的内容可以参考 https://github.com/Loyalsoldier/clash-rules 和 https://dreamacro.github.io/clash/configuration/rules.html
踩坑
下载 Rule-Providers 超时
在我完成完成配置文件的编写之后,我尝试运行,却出现了报错 initial rule provider reject error: context deadline exceeded
尝试询问万能的 Google 后,我确定了这个问题的根源是下载下来的内容是不完整的,而且只有第一次使用时会出现这个问题
在尝试更换多个 cdn 无果后,我偶然发现了我的 Config 文件中有一部分在 url
字段上面显示 Show actual file
而另一部分显示 Copy URL MD5
,点击 Show actual file
后在资源管理器中打开了 C:/Users/{Username}/.config/clash/providers/rule
这个路径,里面的所有 yaml
文件均是以 MD5
的格式命名
这意味着我可以使用以前的配置文件上网,将所有未下载完成的文件手动下载
再根据 URL
的 MD5
值对文件重命名,并将 txt
文件拓展名修改为 yaml
,最后复制到 C:/Users/{Username}/.config/clash/providers/rule
路径下
说人话会有点绕,换成 bash
命令可能容易理解,这里以 reject
为例:
COPY ./reject.txt C:/Users/{Username}/.config/clash/providers/rule/a9362c87ee45f5f47434d44f5aab0c33.yaml
记得请将 {Username}
替换成你自己的 Username
虽然有点麻烦,但是一次成功,配置文件就不在这里报错了
正则表达式
事先说明一下,我当时的版本是 CFW v0.20.24
问题总是一个接着一个,刚解决 Rule-Providers 的问题,又出现了新的报错 Could not switch to this profile
找不到当时报错的图了,这是别人在相关 ISSUES 中提供的图片
报错的意思是语法不支持,我当时很疑惑,因为这段正则是我从 Parsers
原样搬过来的,在 Parsers
中都是正常的,怎么在 Config
中就报错了呢?
众所周知,Clash 内核是使用 Go 语言编写的
它处理正则表达式时会调用 regexp
包,然而这个包不支持零宽断言,诸如 ^((?!GAME).)*(VIP|IEPL).*$
的语法是会报错的,这意味着我们不能使用 “包含A且不包含B” 的逻辑,对于筛选节点的操作而言影响是比较大的
在查找了大量资料后,我找到了 [Feature] 希望 clash 可以支持使用 regex2 第三方库过滤节点 #2673,提出这个 Issue 的网友遇到了和我一样的问题
Description
用的机场有个节点一直会出问题,希望可以在 proxy-providers 的 filter 中过滤掉。但由于 golang 的 regex 库不支持零宽断言,导致
(!proxy1|proxy2)
这样的正则表达式语法也不被支持,而 Parser 功能似乎也只是 Clash for Windows 才有的功能,所以这边希望将 regex 库替换为 regex2,谢谢
然后很顺利地找到了 替换正则库为github.com/dlclark/regexp2 #2802 这个 PR
不过当时的我依然非常不解,因为这个 Issue
和 Pr
已经 Closed
了,而且看上去非常顺利,这意味着 Clash 内核已经使用了支持零宽断言的 regex2
包,而我的配置文件确实是在零宽断言处报错了
直到我注意到了 Pr 的时间是 Jun 21, 好家伙,差点赶上首发了
在 Clash v1.17.0 是更新日志中写道:
Change
- replace std regex with regexp2 (#2802) @dyf991645
在 Clash Premium 的更新日志有:
2023.06.30
- upgrade to v1.17.0
在 CFW v 0.20.28 的更新日志里写道:
v 0.20.28
Clash Core: Upgraded to the v2023.06.30 Premium.
这链式关系瞬间就清晰了
在升级了 CFW 的版本之后,我成功使用上了自己的配置文件
后记
为什么会有多个节点提供商
主要是为了省钱,C站上面随便一个 checkpoint
模型就是几个G。
由于一些不能说的原因,节点分优质和普通,优质节点的流量比较贵,相反,普通节点的流量比较便宜,所以我选择了两家节点提供商,一家能够提供相对宽松的专线,一家基本不限流,通过使用 Clash 的静态分流,我可以在省钱的同时,获得不错的冲浪体验。
当然,使用多个节点提供商也有一定的扛风险能力。
想法
喜欢折腾、讨厌麻烦真的是我不断学习的动力,也是我愿意将这份经历记录下来的原因,希望这篇关于 CFW 配置文件的博客能够帮到你。