V2EX 15小时前
[程序员] 我的 Clash 配置进化史之 get 到了开发编程语言的爽感(一部分上)
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文作者长期以来维护三份Clash配置(Home、Work、Remote),分别对应不同使用场景,主要用于区分内网网段和VPN出口。为解决手动切换和遗漏问题,作者尝试将配置拆分,却导致维护工作量倍增。在探索过程中,作者先是尝试了YAML文件引入功能,但因语法复杂且可读性差而放弃。后受到envsubst工具启发,通过环境变量动态生成配置,但仍需分割文件。最终,作者借鉴C++预处理器,在YAML中引入自定义的#ifdef/#ifndef语法,并自行开发脚本实现动态生成三份配置,解决了配置管理痛点,并为未来实现WiFi自动切换打下基础。

💡 **多场景配置管理痛点**: 作者为在家、公司、外出三种场景维护Home、Work、Remote三份Clash配置,以区分不同内网网段(192.168.1.0/24和10.0.0.0/8)的出口策略,并避免VPN软件强制路由流量影响自定义规则。这种拆分虽然解决了初期问题,但导致维护工作量成倍增加,且容易因修改不一致而产生错误。

🛠️ **探索与失败的尝试**: 作者尝试过使用第三方工具实现YAML文件间的引入,但因其复杂的语法和降低的可读性而放弃。随后,受envsubst工具启发,利用环境变量动态替换配置内容,但仍需将配置分割为多个文件,未能完全整合。

🚀 **自定义语法与自动化**: 作者最终借鉴C++预处理器的#ifdef/#ifndef逻辑,在YAML文件中引入自定义的条件编译语法,用于根据不同场景(Work、Remote、Home)动态生成对应的配置。通过编写脚本,实现一键生成三份完整配置文件并自动重载,极大提升了配置管理的效率和准确性。

🌐 **未来自动化展望**: 此次自定义解决方案不仅解决了当前配置管理的问题,还为进一步自动化打开了大门。作者计划通过监控WiFi变化,利用URL Scheme调用Clash GUI,实现根据不同网络环境自动切换至相应的Clash配置,从而达到完全自动化的目标。

长久以来,我都同时维护着三份 Clash 配置:Home 、Work 、Remote ,分别对应在家、在公司、在外使用。主要区别就是针对 192.168.1.0/24 段和 10.0.0.0/8 段有不同的出口配置:Home 对 192 段直连,对 10 段走公司 VPN ; Work 对 192 段走回家代理,对 10 段直连; Remote 对 192 段走回家代理,对 10 段先走回家代理,再走公司 VPN 。这样做的目的主要一是我不需要再额外在笔记本上配置 VPN 了,二是我司的 VPN 软件在连接后自动会路由所有流量至 VPN ,不符合我对隐私性的要求,也会破坏我自定义的出口规则。

针对两个网段走不同出口其实只要一个配置就能搞定,我早期也是这么做的,更换办公地点后手动切换两个网段的出口配置,不过在用了一段时间后感觉每次都需要切换两次配置,还是比较麻烦的,还有很多时候是到了公司发现连不上内网才想起来没有把 10 段切成直连。为了解决这个痛点,我把一份配置拆成了三份,这样我只要切换一次配置就可以同时切换两个网段的出口了。这同时也引入了另一个优点:针对不同地点可以配置不同的 DNS 。例如在公司时我使用内网的 DNS 服务。在家时使用家宽 DNS ,在外时优先从 DHCP 获取,否则使用公共 DNS 。

不过随着时间的推移,同时维护三份配置引入了一个新的痛点,有些时候我需要针对某些域名或进程配置其走不同出口:例如 ChatGPT 、Gemini 需要走美国出口,Cursor 、Torrent 网站需要直连,Parsec 需要直接代理回家等。有些时候我需要引入新的出口,有些时候我想引入新的规则库,有些时候我想重构配置使其更简洁。这都需要我同时修改三份文件。而很多时候往往修改了一份就忘记修改另两份配置,或者是重构引入的修改太多,要在另两份配置上应用相同的修改太过复杂了。我为了解决一个痛点,让维护的工作量增加了两倍甚至更多,似乎是得不偿失的。于是在一个周六的深夜,我开始思考有没有两全其美的方法。

一个很直观的想法是把相同的部分放在一起,在不同的部分隔离开,形成完整配置即可。但是在研究了一圈后发现 yaml 本身并不支持引入另一个 yaml ,需要使用第三方软件实现这一功能。这些第三方软件为了支持更复杂的需求,语法大多很复杂,借助 Cursor x Gemini 实现一版后发现确实太丑、太不直观了。并且虽然可维护性看似提高了,但是一份配置被拆成了四个部分,可读性却降低了,这个方案还是不够完美。

我让 Gemini 给我推荐其他实现方式,一个工具给我了新的灵感:envsubst 。这个工具符合 Linux 一个工具只干一个事的哲学,其能从 stdin 或者文件中读入文本,并将其中$ENV_VAR_NAME 部分替换成当前 ENV 中实际的 Value 。手动用该工具实现了一版:三份不同的 sh 文件负责 export 各自不同的 value ,一份文件放着相同的部份,负责引入这些 key ,提供给 envsubst 形成最终配置

对于 Remote:export OFFICE=[Relay,Home,Office_VPN]对于 Work:export OFFICE=[DIRECT]对于 Home:export OFFICE=[Office_VPN]在相同部分引入这些 ENV:[Proxy]OFFICE: $OFFICE

利用这个工具,去掉了复杂的语法,可读性虽然提高了,但是配置仍然被分割成了四个部份,还是得想办法把配置都放在一起。如何实现呢?作为一个多年 C 艹程序员,这个语法让我想起了 C++的预处理器,其通过 ifdef 和 ifndef ,来在不同的 definition 间切换使用不同的源码。往 yaml 加入 ifdef 后,语法扩展成了这样

dns:#ifdef WORK  nameserver:10.0.0.1#else  nameserver:8.8.8.8#endifproxy-groups:#ifdef REMOTEOFFICE=[Relay,Home,Office_VPN]#endif#ifdef WORKOFFICE=[DIRECT]#endif#ifdef HOMEOFFICE=[Office_VPN]#endif

但是并没有现成的简单的工具可以支持这种语法,于是我又在 Cursor 撸了一个。现在在修改配置后,只需要运行一个脚本,就能同时生成三个 Work 、Remote 、Home 三个配置文件,并且自动重载配置。语法完全是我定义的,以我最熟悉的方式,我还可以在后续以任意我想要的方式去扩展这个语法,当下马上 Get 到了自己写一门语言的爽感,长久以来的痛点总算解决了。

这同时打开了进一步优化的大门:当前虽然维护上足够直观了,但是在更换地点后仍然需要手动切换配置。在这之前我考察过 macOS 下的几个 Clash GUI ,都不支持自动切换,甚至也不支持通过非 GUI 渠道切换配置,于是最早我想自己写脚本的路子也封死了。现在通过这个方式,可以通过监控 WiFi 变化,向同一个文件生写入不同配置,并调用 GUI 的 URL Scheme 重载最新的配置,实现全自动根据不同 WiFi 切换不同配置的功能。

(以下是 Deepseek 写的结尾)

深夜的代码、灵感的迸发、亲手构建的工具链... 今晚,我不仅驯服了三份恼人的 Clash 配置,更意外地触碰到了一门“专属语言”的脉搏。

那份 #ifdef WORK 在 YAML 中亮起的瞬间,仿佛打开了一扇新的大门:用自己定义的规则,去编排复杂世界的逻辑,原来可以如此酣畅淋漓。

眼前的自动化曙光( WiFi 触发+URL Scheme )已清晰可见——这不仅是一次配置管理的胜利,更是一次对“懒惰”(自动化)与“掌控”(自定义)的极致追求。当工具完美融入工作流,无声无息地解决问题时,便是工程师最浪漫的成就感时刻。

今晚的代码,值了。 🚀

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Clash 配置管理 自动化 YAML 自定义语法
相关文章