臭名昭著aTrust隔离计划1.臭名昭著aTrust隔离计划2.VPN原理与aTrust隔离网络实践3.docker-easyconnect到底做了什么4.TUN(tunnel-隧道-虚拟网卡)模式
个人项目
personal(个人展示)GitHub Actions 自动部署个人展示项目
基于Quartz搭建的个人博客1.Quartz个人博客使用教程2.使用 rsync 增量部署 Quartz 博客3.使用 GitHub Actions 自动部署 Quartz 博客5.域名绑定6.CDN加速Obsidian、双向链接与知识图谱
旅行
行程攻略青岛三日游行程攻略
前端
NginxNginx配置与反向代理入门
Nodenpm与npx的区别
中华财险-公司项目
对外接口文档
基础数据码表对外接口(仅支持rpc调用)业务码表对外接口应用主数据对外接口
基础运营查询版本更新日志详情消息中心对外接口站内信对外接口站内信模板配置手册
权限中心权限中心对外接口文档(最新)权限中心对外接口文档前端ACL-CORE FACADE依赖版本
审计中心审计中心对外接口文档audit-center-facade版本
审批中心工作流迁审批流现状工作流迁审批流API能力替换方案老审批流接口文档审批中心接口文档审批中心业务回调FAQ
账号中心内部系统对接单点登录内部系统对接认证中心三方网页应用登录授权账号中心对外接口文档前端账号中心RPC接口文档账户变更对外广播消息文档账户中心对外接口HRMS外部员工变更广播消息文档HRMS外部员工对外接口
组织员工岗位🔥机构映射SDK接口文档员工岗位变更通知说明组织机构管营一体概念与用法组织员工对外广播消息文档组织员工岗位对外接口文档组织员工岗位对外接口文档前端组织员工岗位数据模型组织员工主数据业务场景案例organization-facade版本
hrms(大型人力资源外包管理系统)
项目架构说明HRMS Maven模块与依赖说明
项目说明0.流程中心模块0.组织模块说明1.业务线模块2.计划模块3.项目模块4.协议模块5.供应商模块6.合约域模块7.外包人员模块*核心:外包人员生命周期
项目运维外包人员项目编制差异排查与修复2.HRMS相关问题排查4.修改externalId(externalId和accountId不一致)
需求-系分
1.内部转外包0723外包人员关联历史内部账号系分新增外包人员关联历史账号内容(紧急0723上线)需求
2.工作岗位0820工作岗位0820需求工作岗位0820需求-系分
3.用工模式调整0917内部人员转外包用工系统需求2内部人员转外包用工系统需求-系分
sso(账号中心-单点登录)
项目架构说明aboss-sso项目架构入门AOP统一日志打印链路Maven多模块项目高级知识OAuth2.0
项目说明1.SSO-OAuth2.0与IDaaS登录流程2.外部账号创建流水号并发问题分析
AI
使用说明
第三方插件&技能简介Archify使用与安装指南Ponytail使用指南
CodexCodex CLI与IDE区别及使用指南Codex Hook单独配置与提交通知Codex MCP安装与使用指南Codex第三方插件安装与使用指南
Agent开发1.LLM、Token、上下文窗口与模型参数2.大模型 API、请求参数与响应结构3.Spring AI ChatClient4.Prompt、System Prompt、Prompt 模板6.结构化输出、JSON Schema7.SSE 流式响应8.会话 ID、聊天记录、Redis9.超时、重试、限流、降级10.完成可运行聊天接口
GitGit常用命令与Obsidian推送排查
Java
面试题Java基础与集合面试题
AtomicInteger原子计数与并发安全ConcurrentHashMap并发安全与计数Java线程、线程池与Future
python
基础Python基础语法
HTTPXHRMS员工详情接口调用(Python HTTPX)

原文地址

https://smc.im/post/macos-resolve-atrust-clash-tun-conflict-with-docker/#%e8%a7%a3%e5%86%b3%e6%80%9d%e8%b7%af%20%E8%BF%99%E4%B8%AA%E5%91%A2 蓬叶虫(金黄的样子)

在原作的基础上加了一些自己的制定化配置,我是网络小白,站在巨人的基础之上做了点小小的优化,请支持原作!

背景与起因

彻底解决 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 模式下才能正常加载模型列表和问问题。

这就导致了一个死循环:

  1. 打开 Clash 的 Tun 模式:接管系统网卡后,aTrust 的虚拟网卡被覆盖或路由失效,内网断连。
  2. 关闭 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 访问,省去了很多端口映射的麻烦。

整体流量走向如下:

macOS 上 aTrust 隔离与流量分流架构

打开交互式架构图 爆焰仔

架构理清了,下面记录一下具体的配置过程。

实战步骤

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的地址 打开终端 输入命令 启动容器:

在终端启动 aTrust 容器

docker-compose up -d

3. 登录 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 这款软件,可以直接在 配置 页面添加脚本:

进入配置- 选择 ‘更多’

进入 FlClash 配置页面

第二步 选择 ‘覆写’

选择覆写配置

选择 ‘脚本’

选择脚本配置

选择 ‘前往配置脚本’

前往配置脚本

选择 ‘添加’

添加 FlClash 配置脚本

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

编辑 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 容器隔离了。

疑问

既然本机可以,那我把这个镜像装到公网的虚拟机上,别人不也可以访问了?

致谢