← 返回 Atlas代理服务器代理部署
凌晨两点, 一台境外 VPS 的告警邮件把你从被窝里捞起来: 「We detected unusual outbound traffic on your IP, mainly port 7890.」 顺着日志一查, 是上礼拜图省事把 mihomo 的 mixed-port 绑成了 0.0.0.0:7890, 又没配防火墙, 公网扫描器几分钟就把你当成了免费代理, 出口 IP 被刷进风控名单。这不是段子, 是 2023-2024 年无数“把 Clash 搬上服务器”的人踩过的同一个坑。proxy-deploy 讲的正是这件事: mihomo 从你桌面双击的进程, 变成一台无头机器上开机自启、崩溃自愈、替整网出网的常驻服务, 中间隔着一整套 systemd 单元、权限能力和防火墙的工程细节。
服务器 · 代理
从 `clash -d` 到 systemd: 一台机器的三个阶段
2019 年的典型用法是 clash -d /etc/clash 手动起一个进程, 终端里 export http_proxy=https_proxy=127.0.0.1:7890 就够桌面场景, 但一关终端代理就没了。2020 年, Premium 闭源线把 TUN 模式和 iptables 透明代理带进来, allow-lan 一开, 内核直接变成软路由, 一个局域网共享一个出口。2021 年之后, mihomo 内核加 systemd 成为服务器和软路由的标准姿势。三个阶段的分水岭是同一个问题: 要不要无人值守地活着。单机模式死了你随时重开, 服务器模式死了整网断网。所以把 mihomo 想成 nginx 最顺手——它不是一个程序, 是一个服务, 部署的全部工作就是让它被 systemd 托管、按信号热重载、按配置自愈。
systemd 单元里最容易翻车的三个字段
抄来的单元文件, 翻车点集中在三个字段。第一是能力: TUN 建虚拟网卡要摸内核网络栈, 必须给 AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE, 少一个都是建 tun 时报 permission denied。第二是文件描述符: LimitNOFILE 默认 1024, 高并发连接一上来就是 too many open files, 很多人直接塞到 1000000。第三是重载方式: ExecReload 配成 /bin/kill -HUP $MAINPID, systemctl reload 走的是热重载, 只换配置不换进程; 而 systemctl restart 会把在途连接全部掐断, 线上切节点那一下全线闪断。记住这个口诀: reload 换配置, restart 换进程。为什么这么较真? 因为 restart 会先杀进程再拉新进程, 监听端口重新 bind, 正在传的大文件和保持的 SSH 会话全被打断; 而 HUP 只是重读配置, 连接池原地重建, 用户无感, 改配置从此变得廉价。再配上 Restart=on-failure 和 RestartSec=5, 进程崩溃五秒内自己爬起来, 这才是常驻该有的样子。
allow-lan: true 不等于网关, 也不等于安全
很多人以为开个 allow-lan 就能让局域网共享出口, 结果是把 mixed-port 整个暴露给了全世界。2023 年删库潮之后, 软路由和 VPS 部署激增, 公网扫描器对着 7890 这种默认端口全端口扫, 一旦撞上没配 secret 的 external-controller, 陌生人不仅能蹭你的流量, 还能直接 PUT /proxies 把你的节点改成他的, 出口 IP 被人拿去跑爬虫, 第二天节点就被封了。正确收口是三层: 第一, bind-address 只绑内网 IP, 别用星号; 第二, 云安全组或 ufw 只放行指定网段进来的流量; 第三, external-controller 配强随机 secret。防火墙放行端口的粒度, 决定了你是“软路由”还是“免费代理”。
部署不是终点: 自检与热载之间的运维日常
部署完别急着收工, 先自检一遍。curl -x http://127.0.0.1:7890 http://cp.cloudflare.com/generate_204 应该返回 204; 再 curl -x socks5h://127.0.0.1:7890 https://api.ipify.org, 出口 IP 必须等于你选的节点, 不一致就说明代理链路压根没生效。之后订阅更新、节点测速、规则集刷新这些“跑起来之后的事”都交给 interval 和 cron(见 clash-schedule 词条), 部署层只负责一件长期的事: 观察。journalctl -u mihomo -f 盯启动日志, ss -tlnp 看端口监听, 必要时 tcpdump 抓包确认有没有直连了不该直连的域名。还有一条别漏: 服务器上没有 GUI 的进程名, 订阅里桌面向的 PROCESS-NAME 规则和 external-ui 要在部署时清掉, 否则就是“看似有规则实则不生效”。习惯之后你会发现, 部署是一次性的活, 运维才是长跑: 靠日志、端口、抓包三样工具把内核盯住, 它才有资格谈节点续期、订阅更新这些后续的事。
实战示例
一台刚重置的 Ubuntu VPS, 任务只有一个: 让这台机器自己走日本节点出网。别急着写服务, 先在命令行跑一遍 mihomo -d /etc/mihomo, 看日志有没有报错, 再写 systemd 单元、daemon-reload、enable --now。等它起来, 按顺序敲两行:
curl -s -o /dev/null -w '%{http_code}\n' -x http://127.0.0.1:7890 http://cp.cloudflare.com/generate_204
204
curl -s -x socks5h://127.0.0.1:7890 https://api.ipify.org
45.76.8.1
看到 204 和那个日本 IP 同时出现, 悬着的心才放下, 这才敢把 ssh 的 ProxyCommand 和 docker daemon 的代理指过去, 宣告部署完成。最后别忘了 systemctl enable 开机自启, 免得重启后出口静悄悄消失。
子关键词
TUN 模式部署 虚拟网卡全局接管
TUN 会建一张虚拟网卡接管整机流量, 配合 auto-route 抢路由表、dns-hijack 抢 DNS 查询。systemd 下必须先给 CAP_NET_ADMIN 和 CAP_NET_RAW, 否则建 tun 直接 permission denied。如果没劫持 DNS, fake-ip 就失效, 域名规则全部架空(详见 fakeip 词条)。
网关模式(allow-lan) 局域网共享代理出口
把 allow-lan 开成 true, 内核就开始监听局域网, 本机和内网机器把 http_proxy 指过去就能共享出口。但必须同时做三件事: bind-address 绑内网 IP、安全组只放行指定网段、external-controller 加 secret, 否则就是裸奔的开放代理。
systemd 常驻 开机自启崩溃自愈
单元用 Type=simple, 配 Restart=on-failure 和 RestartSec=5, 崩溃后自动拉起; ExecReload 指向 /bin/kill -HUP $MAINPID 做热重载。再加 After=network-online.target, 保证有网才启动, 免得开机那一下没有网络全失败。写成单元之后, 关机再开机它自己会回来, 日志统一进 journald, 排查也顺手。
热重载 vs 重启 热重载换配置不断流
kill -HUP 让内核重读配置、重建连接池, 在途连接不断; systemctl restart 是先杀进程再起, 全线闪断。所以线上改订阅、改规则、换节点一律走 systemctl reload, 别图省事用 restart。
开放代理事故 裸奔被扫描成免费代理
2023 到 2024 年的部署潮里, mixed-port 绑 0.0.0.0 又不设防火墙的服务器, 被公网扫描器扫到后当免费代理用, 出口 IP 被滥用、节点被封、境外 VPS 被风控。典型特征: 日志里一坨陌生 IP 在连 7890 端口。
环境变量代理 让不认代理的进程走代理
export https_proxy=http://127.0.0.1:7890 这类变量只对认环境变量的进程生效, 对不认变量的程序完全透明, 想全局接管只能靠 TUN。而且变量是进程级继承, systemd 拉起的服务不受你终端 export 影响, Docker daemon 得单独写 drop-in 文件。记得配 no_proxy, 否则 169.254.169.254 的云 metadata 被塞进代理, 鉴权直接失败。
衍生角度
设计模式:服务守护
把内核当 nginx 托管: systemd 的 Type=simple 加 Restart=on-failure 保证崩溃自愈, ExecReload 指向 kill -HUP 做热重载, 再按最小权限给能力。部署成败, 看的是无人值守时它能不能自己活下去。配好之后, 重启服务器、内核崩溃、订阅更新都不用人守着。
概念拆解:三种接管方式
mixed-port 是应用层代理, 必须进程认代理才会走; TUN 是虚拟网卡, 连不认代理的程序也全局接管; iptables 透明代理活在转发面, 要 root 且必须防火墙收口。桌面用前者, 服务器和软路由用中间那个, 别混。
风格架构:无头 vs 桌面
桌面端 Clash Verge Rev、Mihomo Party 把配置塞进 GUI; OpenClash 则把 mihomo 打包成 OpenWrt 插件。服务器走的是无头形态: 纯配置文件加守护进程, 配置进 git 可版本管理、可 diff、可 mihomo -t 校验。说白了, 服务器上每一行配置都值得进 git 留痕, 出问题能回滚。
原理分析:HUP 热重载
内核主循环一直握着在途连接, 收到 SIGHUP 只重读配置、重建连接池, 进程不退出; restart 则是先 SIGTERM 杀掉再拉起, 在途 TCP 全部 RST。这就是 reload 和 restart 的本质差别, 也是线上敢用前者的底气。
实际用法与坑
- 部署前先跑 mihomo -t -d 校验配置, 看到 test successful 再写进 systemd, 别把坏配置直接 enable, 坏了先在本机改
- systemd 单元里 AmbientCapabilities 三件套和 LimitNOFILE 一个都不能省, 否则 TUN 建不起来、高并发爆文件描述符
- mixed-port 用 bind-address 绑内网段, 安全组和 ufw 只放行指定网段, external-controller 配上强随机 secret, 端口开得越宽风险越高
- 部署后用 curl 打 generate_204 验链路通不通, 再用 api.ipify.org 核对出口 IP, 不一致就是链路没生效
- 给终端和 CI 配 no_proxy, 排除 localhost、内网和云厂商 metadata 地址, 防止请求环路和鉴权失败
下一步动手做
第一步, mihomo -t -d 校验配置; 第二步, 写 systemd 单元, 补齐能力、文件描述符、HUP 重载三件套; 第三步, 收紧网络面, 收 bind-address、防火墙、secret 三道口; 第四步, enable --now 后用 generate_204 和 ipify 自检; 第五步, 把订阅更新和节点测速交给 interval 或 cron, 详见 clash-schedule 词条。
相关书籍
深入理解 Linux 网络技术内幕服务器网络栈、防火墙与端口转发的落地基础,配合 systemd 守护理解服务生命周期与故障排查。