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

 

文章讲述了作者为解决同时维护Home、Work、Remote三份Clash配置的痛点,从手动切换到引入自定义语法的过程。作者最初为适应不同网络环境(如公司内网、家庭网络)和VPN需求,将一份配置拆分为三份,但增加了维护难度。为简化管理,作者尝试了第三方工具,但因语法复杂、可读性差而未果。最终,作者借鉴C++预处理器,通过`envsubst`和自定义`ifdef/ifndef`语法,实现了一套能够根据不同环境生成定制化Clash配置的解决方案,并展望了进一步实现自动化切换的可能。这一过程不仅解决了实际问题,也带来了创造专属工具的成就感。

📦 **多配置维护的痛点与拆分**:作者最初为适应不同网络环境(如192.168.1.0/24和10.0.0.0/8网段)及VPN需求,同时维护Home、Work、Remote三份Clash配置文件,以实现不同出口和DNS设置。这种拆分虽然解决了某些问题,但导致维护工作量成倍增加,且容易出错。

💡 **引入自定义语法解决管理难题**:为克服多文件维护的低效,作者尝试了使用`envsubst`工具,通过环境变量动态替换配置中的变量。进一步地,受C++预处理器的启发,作者在YAML中引入了类似`ifdef/ifndef`的自定义条件编译语法,允许在同一份配置文件中根据不同环境(如WORK、REMOTE、HOME)选择性地包含或排除配置片段。

🛠️ **自制工具的实现与优势**:作者利用Cursor等工具实现了对自定义语法的解析和生成脚本,能够一键生成多份定制化的Clash配置文件,并能实现配置的自动重载。这种方式不仅提高了配置的可读性和可维护性,还赋予了作者极大的灵活性,可以根据未来需求自由扩展语法。

🚀 **自动化切换的未来展望**:通过此次对配置管理流程的优化,作者看到了进一步实现全自动化配置切换的可能。未来计划通过监控WiFi网络变化,自动向Clash GUI发送URL Scheme命令,动态加载对应的配置文件,从而彻底解放手动切换配置的繁琐操作。

长久以来,我都同时维护着三份 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 配置管理 自定义语法 自动化 程序员
相关文章