原文地址
在原作的基础上加了一些自己的制定化配置,我是网络小白,站在巨人的基础之上做了点小小的优化,请支持原作!
背景与起因
彻底解决 macOS 上 aTrust 与 Clash Tun 模式冲突:Docker 隔离与全能分流指南(由于我的公司变态到想要访问哪个网站必须要登记的地步,实在忍无可忍),在不开tun模式的情况下基本上访问不了白名单外的网站,tun模式和普通代理模式的区别下文有讲,感兴趣的小伙伴配置完可以看看
详解如何利用 OrbStack 和 Docker 隔离 aTrust VPN,配合 Clash Tun 模式彻底解决 macOS 下的路由冲突。实现同时流畅访问公司内网和google等服务服务的终极网络方案。
最近在 macOS 上开发时遇到一个很烦人的网络冲突问题。
这就造成了一个麻烦点,访问公司内部资源时必须使用 aTrust 开启 VPN(aTrust 是臭名昭著的深信服开发的一个 VPN 工具,EasyConnect 也是他们公司的),而日常查资料和开发又离不开 Clash 来访问国际站点。
本来这两者共存也没什么大问题(我本来以为的,具体的下文再聊),但最近 Google 新推出的 AI 编辑器 Antigravity,必须在使用 Tun 模式下才能正常加载模型列表和问问题。
这就导致了一个死循环:
- 打开 Clash 的 Tun 模式:接管系统网卡后,aTrust 的虚拟网卡被覆盖或路由失效,内网断连。
- 关闭 Tun 模式:aTrust 正常了,但google等服务 无法正常使用。
aTrust 太恶心!
一个好玩的项目:docker-easyconnect
。
解决思路
既然宿主机的路由表太拥挤,解决办法就是把“脏活”隔离开。
我采用的方案是将 aTrust 扔进 Docker 容器里运行。容器内部通过 Tun 连接公司内网,然后暴露一个 SOCKS5 端口给宿主机。这样在 macOS 看来,aTrust 不再是一个修改系统网络配置的 VPN 软件,而只是一个普通的本地代理服务(Proxy)。接下来,在宿主机的 Clash 中添加这个 SOCKS5 代理,再把公司内网访问的 IP 分流到这个代理上就行了。
最后,由宿主机的 Clash 统一接管流量:
- 访问
公司内网 IP-> 转发给 Docker 容器的 SOCKS5 端口。 - 访问
google.com或其他外网 -> 转发给机场节点。 - Clash 开启 Tun 模式 -> 解决 Antigravity 的流量劫持问题。
拓扑结构
在这个方案中,OrbStack 是个关键。相比 Docker Desktop,它的网络桥接更直观,容器可以直接通过 IP 或 mDNS 访问,省去了很多端口映射的麻烦。
整体流量走向如下:

架构理清了,下面记录一下具体的配置过程。
实战步骤
1. 准备工作
-
OrbStack: macOS 上 Docker Desktop 的最佳替代品,轻量且网络互通性极好。

-
VNC Viewer: 用于访问容器内的图形界面(aTrust 登录框)。 -我用的是TigerVNC https://tigervnc.org/


-
Clash: 我使用的是 FlClash,支持 Tun 模式即可。
2. 部署 aTrust 容器
这里使用 docker-easyconnect
这个项目。相比于直接 docker run,我更习惯用 docker-compose 管理,方便后续调整参数。
在任意目录下创建 docker-compose.yml:
services:
atrust:
image: hagb/docker-atrust:latest
container_name: atrust
# [新增] 特权模式:解决路由表报错和网络不稳定的关键
privileged: true
restart: unless-stopped
devices:
- /dev/net/tun
# 虽然有了 privileged,保留 cap_add 也没坏处
cap_add:
- NET_ADMIN
ports:
# SOCKS5 端口:Clash 将通过这个端口连接内网
- "1080:1080"
# VNC 端口
- "5901:5901"
# HTTP 端口备用,这里可以注释掉或留着
- "8888:8888"
environment:
- PASSWORD=123456
- URLWIN=1
volumes:
- ./data:/root
sysctls:
- net.ipv4.conf.default.route_localnet=1进入保存yml的地址 打开终端 输入命令 启动容器:

docker-compose up -d3. 登录 VPN
容器启动后,aTrust 已经在后台运行,但还没登录。
- 下载 VNC Viewer
,然后打开。 - 地址栏输入:
127.0.0.1:5901。 - 输入密码(对应上面 yaml 里的
PASSWORD)。 - 此时你应该能看到熟悉的 aTrust 登录界面。输入服务器地址、用户名、密码。
- 登录成功后,不要关闭容器,直接关掉 VNC 窗口即可。
验证连接: 在终端里测试一下容器内部是否通了:
curl --max-time 10 \
--proxy socks5h://127.0.0.1:1080 \
http://platform.cic.inter/如果能 curl 通,说明容器内的 VPN 隧道已经建立。
4. 配置 Clash 分流
这是最关键的一步。我们需要告诉宿主机的 Clash:“凡是公司 IP 的请求,都转发给本地 1080 端口”。
我使用 FlClash 这款软件,可以直接在 配置 页面添加脚本:
进入配置- 选择 ‘更多’

第二步 选择 ‘覆写’

选择 ‘脚本’

选择 ‘前往配置脚本’

选择 ‘添加’

将下列脚本复制粘贴到里面并保存

新增脚本,然后直接填写如下代码:
function main(config) {
// =====================================================
// 基础配置
// =====================================================
// 主力代理组名称。
// 除公司内网之外,其他所有流量都会交给这个代理组。
// 名称必须与 FlClash 中显示的代理组名称完全一致。
const MAIN_GROUP_NAME = "FlyBit";
// 公司内网 SOCKS5 节点名称。
// 后续公司域名和公司 IP 规则都会使用这个名称。
const COMPANY_PROXY_NAME = "🏢 公司内网";
// 强制使用规则模式。
// 全局模式会忽略下面的分流规则,因此不能使用全局模式。
config.mode = "rule";
// =====================================================
// 公司内网 SOCKS5 代理
// =====================================================
// ATrust 在本机 1080 端口提供的 SOCKS5 服务。
// 当前 SOCKS5 不需要用户名和密码。
const COMPANY_PROXY = {
name: COMPANY_PROXY_NAME,
type: "socks5",
server: "127.0.0.1",
port: 1080
};
// =====================================================
// 公司内网匹配规则
// =====================================================
const COMPANY_RULES = [
// 所有以 cic.inter 结尾的域名走公司内网代理。
// 例如:platform.cic.inter、esso.cic.inter。
`DOMAIN-SUFFIX,cic.inter,${COMPANY_PROXY_NAME}`,
// 整个 10.197.x.x 网段走公司内网代理。
// /16 表示匹配 10.197.0.0 至 10.197.255.255。
// no-resolve 表示匹配时不额外进行域名解析。
`IP-CIDR,10.197.0.0/16,${COMPANY_PROXY_NAME},no-resolve`
];
// =====================================================
// 添加公司代理节点
// =====================================================
// 如果原配置没有 proxies 数组,则先创建空数组。
if (!config.proxies) config.proxies = [];
// 删除可能已经存在的同名节点,防止重复添加。
config.proxies = config.proxies.filter(
proxy => proxy.name !== COMPANY_PROXY_NAME
);
// 把公司代理节点添加到节点列表最前面。
config.proxies.unshift(COMPANY_PROXY);
// =====================================================
// 调整规则顺序
// =====================================================
// 保存机场原有规则。
const ORIGINAL_RULES = Array.isArray(config.rules)
? config.rules
: [];
config.rules = [
// 第一优先级:公司域名和公司 IP 走公司内网代理。
...COMPANY_RULES,
// 第二优先级:其余所有流量全部走 FlyBit。
// MATCH 会匹配所有尚未被前面规则匹配的请求。
`MATCH,${MAIN_GROUP_NAME}`,
// 保留机场原有规则。
// 由于 MATCH 已经匹配所有剩余请求,这些规则实际上不会执行,
// 仅保留在最终配置中。
...ORIGINAL_RULES
];
// 返回修改完成的 FlClash 配置。
return config;
}此时,你不需要开启 Tun 模式,浏览器应该已经可以同时访问 google.com 和公司内网 IP 了。
有些软件走代理很卡(要走直连的话可以参考)
在 COMPANY_RULES 后面增加钉钉进程规则,并放在 MATCH 前面:
// 钉钉直连规则
const DINGTALK_RULES = [
"PROCESS-NAME,DingTalk,DIRECT",
"PROCESS-NAME,DingTalk Helper,DIRECT",
"PROCESS-NAME,DingTalk Helper (Renderer),DIRECT",
"PROCESS-NAME,DingTalk Helper (GPU),DIRECT"
];然后把规则部分改成:
config.rules = [
// 公司内网优先走 ATrust
...COMPANY_RULES,
// 钉钉的其他请求直连
...DINGTALK_RULES,
// 剩余全部流量走 FlyBit
`MATCH,${MAIN_GROUP_NAME}`,
...ORIGINAL_RULES
];最终顺序是:
公司域名和 10.197.x.x → 🏢 公司内网
钉钉进程 → DIRECT
其他所有流量 → FlyBit钉钉的实际进程名称可以在 FlClash“请求详情”的“进程”字段查看。如果显示的名称不在上面,就按实际名称补充一条:
"PROCESS-NAME,请求详情中显示的进程名,DIRECT"如果希望钉钉访问公司域名时也强制直连,把 ...DINGTALK_RULES 放到 ...COMPANY_RULES 前面。
想省事可以直接粘我的配置
function main(config) {
// =====================================================
// 基础配置
// =====================================================
// 主力代理组名称。
// 除公司内网和钉钉外,其他流量全部走这个代理组。
// 必须与 FlClash 中的代理组名称完全一致。
const MAIN_GROUP_NAME = "FlyBit";
// 公司内网代理节点名称。
const COMPANY_PROXY_NAME = "🏢 公司内网";
// 强制使用规则模式。
// 全局模式会忽略自定义分流规则。
config.mode = "rule";
// =====================================================
// 公司内网 SOCKS5 代理
// =====================================================
// ATrust 在本机提供的 SOCKS5 服务。
// 127.0.0.1 表示本机,1080 是 SOCKS5 监听端口。
// 当前服务不需要用户名和密码。
const COMPANY_PROXY = {
name: COMPANY_PROXY_NAME,
type: "socks5",
server: "127.0.0.1",
port: 1080
};
// =====================================================
// 公司内网规则
// =====================================================
const COMPANY_RULES = [
// cic.inter 及其所有子域名走公司代理。
// 例如:platform.cic.inter、esso.cic.inter。
`DOMAIN-SUFFIX,cic.inter,${COMPANY_PROXY_NAME}`,
// 整个 10.197.x.x 网段走公司代理。
// /16 匹配 10.197.0.0 至 10.197.255.255。
`IP-CIDR,10.197.0.0/16,${COMPANY_PROXY_NAME},no-resolve`
];
// =====================================================
// 钉钉直连规则
// =====================================================
// 钉钉主进程及其辅助进程不走 FlyBit,直接连接网络。
// 实际进程名称可以在 FlClash 的请求详情中确认。
const DINGTALK_RULES = [
"PROCESS-NAME,DingTalk,DIRECT",
"PROCESS-NAME,DingTalk Helper,DIRECT",
"PROCESS-NAME,DingTalk Helper (Renderer),DIRECT",
"PROCESS-NAME,DingTalk Helper (GPU),DIRECT"
];
// =====================================================
// 添加公司代理节点
// =====================================================
// 如果原配置没有代理节点数组,则创建空数组。
if (!config.proxies) config.proxies = [];
// 删除可能已经存在的同名公司节点,防止重复添加。
config.proxies = config.proxies.filter(
proxy => proxy.name !== COMPANY_PROXY_NAME
);
// 把公司代理节点加入代理列表最前面。
config.proxies.unshift(COMPANY_PROXY);
// =====================================================
// 设置规则顺序
// =====================================================
// 保存机场原有规则。
const ORIGINAL_RULES = Array.isArray(config.rules)
? config.rules
: [];
config.rules = [
// 第一优先级:
// 公司域名和公司 IP 始终走 ATrust SOCKS5。
...COMPANY_RULES,
// 第二优先级:
// 钉钉进程直连。
// 因为公司规则在前,所以钉钉访问公司内网时仍走公司代理。
...DINGTALK_RULES,
// 第三优先级:
// 其他所有流量全部走 FlyBit。
`MATCH,${MAIN_GROUP_NAME}`,
// 保留机场原有规则。
// 由于前面的 MATCH 已匹配所有剩余流量,
// 这些规则实际上不会执行,仅保留在配置预览中。
...ORIGINAL_RULES
];
// 返回修改后的 FlClash 配置。
return config;
}总结
这套方案把“脏乱差”的 VPN 客户端关进了 Docker,还给了 macOS 一个清爽的网络环境。 虽然前期配置稍微麻烦点(写 Compose、配 Clash),但一旦跑通,后续的使用体验就是无感的。不再需要手动开关软件,也不用担心路由表爆炸,这才是开发环境该有的样子。
注意:我在本文前面提到,我本来以为 aTrust 和 Clash Tun 这两者共存也没什么大问题,但是后来别人提醒,aTrust 只要启动了,无论是否退出,都会有进程在后台监控流量。虽然“在后台监控流量”这件事,我没有去验证,但是我确实发现,当完全退出 aTrust 后,在 macOS 自带的活动监视器中,发现仍然有名为 aTrust Agent 的进程在后台活跃,这就让我产生了疑心。
所以,我最终决定,无论是否使用 Clash Tun 模式,aTrust 这个垃圾软件,注定必须要使用 Docker 容器隔离了。
疑问
既然本机可以,那我把这个镜像装到公网的虚拟机上,别人不也可以访问了?
.webp)




.webp)