扔台 VPS 给 AI,让它帮我搭梯子
开发者深夜配置代理服务器
我用了好几年商业 VPN,越用越别扭。原因很简单,你所有流量都过别人的服务器,对方是谁、数据怎么处理,你完全不知道,只能信它。我反正做了这么多服务端的活,按道理自己搭一套不难,就一直想找机会弄一下。
做法大概是这样的。先租一台 VPS,我用的是 Atlas Networks,洛杉矶,9929 线路,静态住宅 IP。然后把 SSH 凭据直接扔给 claude code,跟它说:帮我搭一套完整的代理服务,我自己用,也能分享给朋友用。后面有几个地方挺出乎我意料的。
shadowsocks 四个小时就被封了
claude code 第一步部署的是 shadowsocks。这很好理解,它是成熟方案,大家默认都先用它。
结果四个小时之后 IP 就被封了。不是限速那种,是整个 IP 直接封掉,流量全断。我去问了服务商,确认是被主动封的。
这里顺便讲一下 GFW 到底是怎么查的。大家好像都以为它就是个黑名单?其实早就不是了,它现在会主动探测。它看到你的流量不像任何已知协议,就会主动去探你的服务器,发一些异常报文过去,看你怎么回,回的方式像不像代理。shadowsocks 早年确实很难被认出来,但 GFW 对着它已经练了很多年了。2025 年你拿一个新 IP 去部署 shadowsocks,基本等于举个牌子告诉它「来探我」。
而且加密本身没出问题,GFW 到今天也读不了你传的内容。露馅的是流量指纹。密文熵很高,握手不标准,回应的方式一看就是代理,这几条 shadowsocks 全中。所以它根本不用知道你在传什么,光看你的流量长什么样就够了。
GFW 不靠黑名单,而是看到可疑流量指纹后主动探测你的服务器,模式吻合就封 IP
行吧,换台 VPS,换个思路。
换成 reality
新方案换成了 sing-box + VLESS-Reality。claude code 给我讲 reality 原理的时候,我觉得这个设计是真聪明。前面说了,流量看起来什么都不像,这本身就是特征。所以 reality 反过来,让你的流量看起来像在访问一个真实的大网站。它直接借那个网站的 TLS 指纹,你的握手和一个普通浏览器访问 microsoft.com 一模一样。这样 GFW 想封你,就得连 microsoft.com 一起封。它不会为了你去封微软,只能把你也一起放过去。
伪装成空白反而暴露被封;Reality 借用大网站的 TLS 指纹伪装成访问 microsoft.com,GFW 不敢连微软一起封,只能放行
除了 reality,还部署了三个备用协议。Hysteria2 和 TUIC-v5 都是走 QUIC 的 UDP 协议,速度快,但挺看网络质量。Vmess-WS 走 WebSocket,最弱,纯粹兜底用。四个协议占四个端口,防火墙只开这几个口,别的全关。
在 Clash Verge 的配置里,自动选择分组只放了 reality,另外三个协议在底下备着,日常路由不走它们。只要 reality 能用,就一直走 reality。
证书踩的坑
协议定下来以后,claude code 基本就一路往下推了。SSL 证书用 acme.sh + Cloudflare DNS API 验证,好处是不用开 80 端口。你给 acme.sh 一个只能改 DNS 的 Cloudflare API token,它自己去建一条 TXT 记录,证明域名是你的,验完再自动删掉。这样很干净,服务器不用为了验证多开端口。
中间踩了一个坑。sing-box 的一键脚本自己在里面跑过一次 acme.sh,把域名存进了缓存里的邮箱字段。后来单独给订阅服务器申请证书时,acme.sh 又拿这份缓存来用,Let's Encrypt 一看请求里的邮箱是个域名,直接拒了。报错信息写得还挺绕,来回三次才找到原因。最后删掉 CA 缓存目录,带上 --accountemail 重跑,才过了。
剩下的防火墙、BBR 加速、服务开机自启,claude code 顺手都弄好了,基本不用我管。
订阅服务器
这部分我自己挺满意的。很多自建代理做到这一步,就是给你生成一个 base64 字符串或者一个 QR code,你手动导进客户端就完事了。我想要完整一点,要一个正经的订阅 URL,客户端还能读到流量统计。Clash Verge 认一个叫 Subscription-Userinfo 的响应头,读到以后会显示一个流量条,用了多少、还剩多少、哪天到期都在上面。就多了这么个细节,整套服务看着就是完整的,不像东拼西凑出来的。
claude code 搭了一个 Python 服务,放在 nginx 后面。nginx 负责 443 端口的 TLS,再把请求转给本机的 8089。Python 服务读订阅配置文件,同时调 vnstat --json 拿 VPS 真实的上下行流量,现场生成响应头,格式是 upload=X; download=Y; total=Z; expire=T。Clash Verge 拿到以后自己就会显示出来,客户端什么都不用配。token 是一段十六位的随机 hex,存在服务器上,订阅 URL 就是 https://your.domain.com/{token}。
订阅请求经 nginx 443 转到本机 Python 服务,Python 调 vnstat 拿真实上下行数据,动态写进响应头,客户端据此渲染流量条
中间有个小插曲。Python 服务一开始没处理 HEAD 请求,偏偏 Clash Verge 就是用 HEAD 去拿 header 的,服务直接报错。加上 do_HEAD 方法就好了。这种问题不真跑一遍根本碰不上。
最后朋友那边看到的就是一个流量条,用了多少,3TB 的月额度还剩多少,哪天到期,跟商业服务没什么区别。用 Clash Verge 的话,粘贴 URL,点导入,激活配置,再开 TUN 模式。iOS 上用 Shadowrocket,直接把 URL 加成订阅,扫 QR code 也行。
它是怎么处理失败的
这一路上它碰到失败是怎么处理的,我想单独讲讲。证书因为缓存问题连着申请失败了三次,它没有一遍遍重跑同一条命令,先去查 acme.sh 的状态,找到那份坏缓存,清掉再跑。nginx 的 proxy 配置有时候传 header 有时候不传,它就把整条链路走一遍,一层一层看每个环节传了什么、缺了什么。每次失败大概花它十到十五分钟,它不绕过去,一直查到真正的原因为止。
Clash Verge 自己的行为算个例外。它一重启就会删掉手动改过的配置文件,只留从订阅 URL 导进来的那份。这是这个客户端特有的行为,claude code 不知道,最后是我和它一起测出来的。
所以哪些事能放手给它,界限大概是这样。如果任务有明确的验证标准,比如「这个 URL 应该返回包含 proxies: 字段的 YAML」,它自己调起来很干净,可以一直循环到通为止。客户端那种比较特殊、没法自动验证的行为,就得人去看、去判断。这个分工分清楚了,效率就挺高的。反正一个下午,一套自己托管的代理服务就搭出来了,朋友拿到链接就能用。
