原文地址
在原作的基础上加了一些自己的制定化配置,我是网络小白,站在巨人的基础之上做了点小小的优化,请支持原作!
背景与起因
这篇文章记录了我在 macOS 上利用 OrbStack 和 Docker 隔离 aTrust VPN、配合 Clash Tun 模式实现内外网分流的过程,目标是同时流畅访问公司内网和 Google 等外部服务。
起因很简单:公司的网络限制严格到访问哪个网站都得登记,实在让人忍无可忍。在我的使用环境中,不开 Tun 模式,基本访问不了白名单以外的网站。Tun 模式与普通代理模式的区别会在下文介绍,感兴趣的小伙伴可以配置完再看。
最近在 macOS 上开发时,这两套工具的冲突尤其让我头疼。
访问公司内部资源,必须通过 aTrust 连接 VPN。它是深信服开发的 VPN 工具,EasyConnect 也是他们家的产品。而日常查资料、做开发,我又离不开 Clash 来访问外部站点。
我原本以为两者共存没什么大问题,后来使用 Google 的 AI 编辑器 Antigravity 才发现:在我的配置下,必须开启 Clash 的 Tun 模式,才能正常加载模型列表和发送问题。
这就陷入了一个死循环:
- 打开 Clash 的 Tun 模式:外部服务可以正常使用,但它与 aTrust 的路由配置发生冲突,导致公司内网断连。
- 关闭 Tun 模式:aTrust 恢复正常,但 Google 等外部服务又无法正常使用。
来回切换实在太折腾,干脆把 aTrust 隔离起来!
解决思路
既然两者在 macOS 上容易发生冲突,那就把 aTrust 单独隔离起来。docker-easyconnect
这个项目正好提供了在 Docker 中运行 aTrust 的方案。
我采用的方案是将 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 前面:
⚠️ 平台注意:下面的钉钉进程规则仅适用于 macOS!
Windows 必须改用带
.exe后缀的实际进程名,例如DingTalk.exe。
- macOS:
PROCESS-NAME,DingTalk,DIRECT- Windows:
PROCESS-NAME,DingTalk.exe,DIRECT辅助进程以 Windows 版 FlClash“请求详情”中显示的实际名称为准,不能只给 macOS 的
DingTalk Helper名称追加.exe。此处的平台差异针对钉钉进程规则,公司域名和 IP 的分流规则可以沿用。
// 钉钉直连规则
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 前面。
想省事可以直接粘我的配置
⚠️ Windows 用户请先修改,再复制使用!
下方完整脚本中的钉钉进程名是 macOS 版本,Windows 不能原样使用。
Windows 请将脚本中的
DINGTALK_RULES替换为:const DINGTALK_RULES = [ "PROCESS-NAME,DingTalk.exe,DIRECT" ];其他钉钉辅助进程需要直连时,再按 FlClash“请求详情”中的实际进程名补充,名称须包含
.exe后缀。
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)