macOS 同时使用 L2TP 与 Clash Verge Rev:内网路由与系统代理冲突排查实录

在 macOS 上同时使用公司 Wi-Fi、家庭 L2TP VPN 和 Clash Verge Rev 时,很容易遇到一种看起来十分混乱的问题:

  • L2TP 能连接,但访问不了家里的局域网设备;
  • 手动添加路由后,家里设备可以访问,但 Clash 又失效;
  • 终端执行 curl 可以访问 Google,浏览器却打不开;
  • L2TP 每次断开并重新连接后,之前添加的路由都会消失;
  • Clash Verge Rev 界面显示“系统代理已开启”,但 macOS 实际并没有启用代理。

这类问题表面上像是 Clash、L2TP、DNS、浏览器一起坏了,实际上主要涉及三个相互独立的机制:

  1. macOS 路由表;
  2. PPP/L2TP 点对点隧道;
  3. macOS 按网络服务维护的系统代理设置。

本文记录一次完整排查过程,并给出一套最终稳定方案。

一、网络环境与目标

本次环境如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
公司 Wi-Fi:
物理网卡:en0
默认网关:192.168.1.254

家庭 L2TP:
通过公网域名连接
PPP 本地地址:10.7.7.10
PPP 对端地址:10.1.0.1
PPP 接口:ppp0

家庭局域网:
192.168.9.0/24

Clash Verge Rev:
使用 Mihomo 内核
最终采用系统代理模式
TUN 模式关闭

期望的最终流量路径是:

flowchart LR
    A[macOS 应用程序]

    A -->|访问 192.168.9.0/24| B[静态路由]
    B --> C[ppp0]
    C --> D[10.1.0.1]
    D --> E[家庭局域网]

    A -->|浏览器访问 Google| F[macOS 系统代理]
    F --> G[Clash Verge Rev]
    G --> H[代理节点]
    H --> I[en0 / 公司 Wi-Fi]

    A -->|普通直连流量| I

也就是:

1
2
3
192.168.9.0/24 → 10.1.0.1 → ppp0 → 家庭局域网
Google 等代理流量 → Clash → en0 → 代理节点
普通公网流量 → en0

二、先理解两个容易混淆的地址

1. L2TP 公网域名

L2TP 配置里的域名只负责定位家庭网络的公网入口。

例如:

1
vpn.example.com

它解决的是:

1
Mac 如何通过互联网找到家里的 L2TP 服务端

域名只参与隧道建立阶段,不应该作为访问家庭局域网时的静态路由网关。

2. PPP 本地地址与对端地址

L2TP 连接成功后,可以执行:

1
ifconfig ppp0

本次输出中关键部分类似:

1
inet 10.7.7.10 --> 10.1.0.1

含义是:

1
2
Mac 在隧道内的地址:10.7.7.10
L2TP 点对点对端:10.1.0.1

PPP 是点对点链路,本地地址和对端地址不要求像普通以太网那样处在同一个 /24 网段。因此:

1
10.7.7.10 → 10.1.0.1

并不异常。

访问家庭局域网时,应把家庭网段路由到 PPP 对端:

1
192.168.9.0/24 → 10.1.0.1

三、故障一:L2TP 已连接,但访问不了家庭设备

连接 L2TP 后执行:

1
route -n get 192.168.9.1

故障状态为:

1
2
route to: 192.168.9.1
interface: en0

这表示访问 192.168.9.1 的流量仍然从公司 Wi-Fi 发出,没有进入 L2TP。

只要目标接口是 en0,家庭设备就不可能访问成功。

为什么会走 en0

因为 L2TP 默认只建立了 PPP 隧道,并不一定会自动把家庭局域网 192.168.9.0/24 写入 macOS 路由表。

系统只知道:

1
10.1.0.1 可以通过 ppp0 到达

但不知道:

1
192.168.9.0/24 也应该通过 10.1.0.1 到达

因此需要显式添加家庭局域网路由。

四、正确添加家庭局域网路由

1. 先确认 PPP 对端可达

1
ping -c 3 10.1.0.1

如果 10.1.0.1 可以 ping 通,说明:

1
Mac → ppp0 → L2TP 对端

这段链路已经建立。

2. 删除可能存在的旧路由

1
2
sudo route -n delete -net 192.168.9.0/24 2>/dev/null
sudo route -n delete -host 192.168.9.1 2>/dev/null

删除失败不影响后续操作,因为旧路由可能本来就不存在。

3. 添加家庭网段路由

1
sudo route -n add -net 192.168.9.0/24 10.1.0.1

这里使用的是 PPP 对端地址 10.1.0.1,而不是强行写死 ppp0

这样做更稳妥,因为:

  • ppp0 只在 L2TP 成功连接后存在;
  • macOS 重新连接时接口编号可能发生变化;
  • PPP 本质是点对点链路,以对端地址作为下一跳更符合路由语义。

4. 验证路由

1
route -n get 192.168.9.1 | egrep 'gateway|interface'

正确结果应为:

1
2
gateway: 10.1.0.1
interface: ppp0

然后测试:

1
ping -c 3 192.168.9.1

如果目标设备不响应 ICMP,可以改用端口测试:

1
2
nc -vz 192.168.9.1 80
nc -vz 192.168.9.1 443

也可以测试具体的 NAS、ESXi 或服务器:

1
2
nc -vz 192.168.9.100 22
nc -vz 192.168.9.100 443

五、为什么 L2TP 重连后路由会消失

下面这条命令添加的是内核临时路由:

1
sudo route -n add -net 192.168.9.0/24 10.1.0.1

ppp0 断开时,相关路由会失效或被系统清理。

因此每次执行:

1
2
断开 L2TP
重新连接 L2TP

都可能需要重新添加:

1
sudo route -n add -net 192.168.9.0/24 10.1.0.1

这不是命令执行失败,而是临时路由本身就不会自动永久保存。

六、持久化方案一:为 L2TP 网络服务添加附加路由

先查看 macOS 中的网络服务名称:

1
networksetup -listallnetworkservices

假设 L2TP 服务名称为:

1
Home L2TP

先检查已有附加路由:

1
networksetup -getadditionalroutes "Home L2TP"

如果没有需要保留的其他附加路由,可以设置:

1
2
sudo networksetup -setadditionalroutes "Home L2TP" \
192.168.9.0 255.255.255.0 10.1.0.1

验证:

1
networksetup -getadditionalroutes "Home L2TP"

预期结果:

1
2
3
Destination: 192.168.9.0
Subnet Mask: 255.255.255.0
Gateway: 10.1.0.1

重新连接 L2TP 后再次检查:

1
route -n get 192.168.9.1 | egrep 'gateway|interface'

如果该方式在当前 macOS 版本或 VPN 服务上未生效,可以使用 PPP 的 ip-up 脚本。

七、持久化方案二:通过 /etc/ppp/ip-up 自动添加路由

PPP 建链成功后,pppd 可以调用 /etc/ppp/ip-up

创建脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo mkdir -p /etc/ppp

sudo tee /etc/ppp/ip-up >/dev/null <<'EOF'
#!/bin/sh

HOME_NET="192.168.9.0/24"
VPN_PEER="10.1.0.1"

/sbin/route -n delete -net "$HOME_NET" 2>/dev/null
/sbin/route -n add -net "$HOME_NET" "$VPN_PEER"

exit 0
EOF

增加执行权限:

1
sudo chmod 755 /etc/ppp/ip-up

之后每次 L2TP 成功建立 PPP 链路时,系统都会尝试自动执行:

1
route -n add -net 192.168.9.0/24 10.1.0.1

为了方便排查,也可以增加日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sudo tee /etc/ppp/ip-up >/dev/null <<'EOF'
#!/bin/sh

HOME_NET="192.168.9.0/24"
VPN_PEER="10.1.0.1"
LOG_FILE="/tmp/l2tp-ip-up.log"

{
echo "[$(date '+%Y-%m-%d %H:%M:%S')] PPP connected"
echo "interface=$1 local=$4 remote=$5"
} >> "$LOG_FILE"

/sbin/route -n delete -net "$HOME_NET" 2>/dev/null
/sbin/route -n add -net "$HOME_NET" "$VPN_PEER" >> "$LOG_FILE" 2>&1

exit 0
EOF

sudo chmod 755 /etc/ppp/ip-up

查看日志:

1
cat /tmp/l2tp-ip-up.log

八、故障二:连接 L2TP 后 Clash 失效

家庭路由修好后,又出现了另一个现象:

1
2
3
4
5
关闭 L2TP:
浏览器可以访问 Google

连接 L2TP:
浏览器不能访问 Google

但检查公网路由:

1
route -n get 8.8.8.8 | egrep 'gateway|interface'

结果是:

1
2
gateway: 192.168.1.254
interface: en0

这说明公网默认路由并没有被 L2TP 抢走。

既然公网仍然走 en0,浏览器却无法访问 Google,就不能再把问题归因于默认路由。

真正的关键检查是:

1
scutil --proxy

或者只查看 HTTP/HTTPS:

1
2
scutil --proxy | egrep \
'HTTPEnable|HTTPProxy|HTTPPort|HTTPSEnable|HTTPSProxy|HTTPSPort'

故障状态为:

1
2
HTTPEnable : 0
HTTPSEnable : 0

这表示:

1
macOS 当前有效的系统 HTTP/HTTPS 代理处于关闭状态

浏览器不会再把请求发给 Clash,而是直接访问 Google,因此失败。

九、为什么 Clash Verge 显示已开启,但系统代理实际是关闭的

macOS 的代理配置是按网络服务维护的。

例如:

1
2
3
4
Wi-Fi
Home L2TP
USB Ethernet
Thunderbolt Bridge

这些服务可以拥有不同的:

  • HTTP 代理;
  • HTTPS 代理;
  • SOCKS 代理;
  • DNS;
  • 代理绕过规则。

Clash Verge Rev 开启系统代理时,通常会给当前网络服务写入:

1
127.0.0.1:Clash端口

但连接 L2TP 后,macOS 当前有效网络服务和代理计算结果可能发生变化。

于是可能出现:

1
2
Clash Verge Rev 界面:系统代理已开启
macOS 实际状态:HTTPEnable = 0

判断系统代理是否真正生效,不能只看 Clash 界面的开关,应以:

1
scutil --proxy

为准。

十、为什么 curl 成功,浏览器却失败

故障过程中还出现过:

1
curl -I --connect-timeout 10 https://www.google.com

可以成功,但浏览器打不开 Google。

这是因为 curl 和浏览器可能使用了不同的代理来源。

浏览器

Chrome、Safari 等浏览器通常读取 macOS 当前系统代理:

1
scutil --proxy

当:

1
2
HTTPEnable : 0
HTTPSEnable : 0

时,浏览器会直连。

curl

curl 可能读取终端环境变量:

1
env | grep -iE '^(http_proxy|https_proxy|all_proxy|no_proxy)='

例如:

1
2
3
http_proxy=http://127.0.0.1:7897
https_proxy=http://127.0.0.1:7897
all_proxy=socks5://127.0.0.1:7897

因此即使系统代理已经关闭,curl 仍然可能通过 Clash 访问 Google。

如果 curl 输出:

1
HTTP/1.1 200 Connection established

通常意味着 curl 已经连接到 HTTP 代理,并由代理建立 HTTPS CONNECT 隧道。

所以:

1
curl 成功 ≠ 浏览器系统代理正常

这是本次排查中最容易造成误判的一点。

十一、恢复 macOS 系统代理

保持以下状态:

1
2
3
L2TP:已连接
Clash TUN:关闭
Clash 系统代理:准备开启

在 Clash Verge Rev 中执行:

1
2
关闭系统代理
再次开启系统代理

然后验证:

1
2
scutil --proxy | egrep \
'HTTPEnable|HTTPProxy|HTTPPort|HTTPSEnable|HTTPSProxy|HTTPSPort'

正确结果应类似:

1
2
3
4
5
6
7
HTTPEnable : 1
HTTPProxy : 127.0.0.1
HTTPPort : 7897

HTTPSEnable : 1
HTTPSProxy : 127.0.0.1
HTTPSPort : 7897

这里的端口应以 Clash Verge Rev 实际配置为准,不一定是 7897

可以查看 Clash 当前端口:

1
2
grep -E '^(mixed-port|port|socks-port):' \
"$HOME/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/clash-verge.yaml"

注意:

1
clash-verge.yaml

通常是 Clash Verge Rev 自动生成的最终配置,不建议直接修改。

十二、给 L2TP 网络服务配置系统代理

如果每次连接 L2TP 后系统代理都会变成关闭状态,可以直接给 L2TP 网络服务配置代理。

先查看服务名:

1
networksetup -listallnetworkservices

假设:

1
2
VPN_SERVICE="Home L2TP"
CLASH_PORT=7897

设置 HTTP 代理:

1
2
3
4
5
sudo networksetup -setwebproxy \
"$VPN_SERVICE" 127.0.0.1 "$CLASH_PORT"

sudo networksetup -setwebproxystate \
"$VPN_SERVICE" on

设置 HTTPS 代理:

1
2
3
4
5
sudo networksetup -setsecurewebproxy \
"$VPN_SERVICE" 127.0.0.1 "$CLASH_PORT"

sudo networksetup -setsecurewebproxystate \
"$VPN_SERVICE" on

如有必要,再设置 SOCKS:

1
2
3
4
5
sudo networksetup -setsocksfirewallproxy \
"$VPN_SERVICE" 127.0.0.1 "$CLASH_PORT"

sudo networksetup -setsocksfirewallproxystate \
"$VPN_SERVICE" on

设置家庭网络绕过代理:

1
2
3
4
5
6
7
sudo networksetup -setproxybypassdomains \
"$VPN_SERVICE" \
localhost \
127.0.0.1 \
"*.local" \
"192.168.9.*" \
"10.1.0.1"

完成后重新连接 L2TP,并检查:

1
scutil --proxy

十三、Clash Verge Rev 最终配置

本次最终没有使用 TUN 模式。

Clash 的扩展配置中只保留了一行:

1
interface-name: en0

作用是:

1
强制 Mihomo 的代理节点连接通过 en0 出站

避免 L2TP 建立后,Mihomo 错误选择 ppp0 作为代理节点出口。

Clash Verge Rev 配置目录

macOS 下常见目录:

1
~/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/

可直接打开:

1
open "$HOME/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev"

常见文件:

1
2
3
4
verge.yaml
profiles.yaml
clash-verge.yaml
profiles/

不要直接修改:

1
clash-verge.yaml

因为它属于自动生成的最终配置,切换订阅或重启内核后可能被覆盖。

应从 Clash Verge Rev 界面进入:

1
2
3
订阅
→ 当前订阅
→ 编辑扩展配置 / 编辑合并配置

最终内容:

1
interface-name: en0

十四、为什么没有继续使用 TUN

TUN 会创建虚拟网卡并主动修改路由表。

在同时存在:

1
2
3
en0
ppp0
utun*

的环境中,TUN 需要额外处理:

  • 默认出口选择;
  • 家庭网段排除;
  • PPP 接口排除;
  • DNS 劫持;
  • 代理节点自回环;
  • macOS 网络服务切换。

本次需求只是:

1
2
浏览器等常见应用通过 Clash 访问互联网
同时访问家庭局域网

系统代理模式已经足够。

最终稳定方案是:

1
2
Clash 系统代理:开启
Clash TUN:关闭

如果没有必须代理那些完全不支持系统代理的软件,就没有必要额外启用 TUN。

TUN 在这里不是“高级模式”,更像是又请来了一位喜欢抢方向盘的司机。

十五、最终稳定配置

L2TP

1
2
3
4
公网入口:域名
PPP 本地地址:10.7.7.10
PPP 对端:10.1.0.1
发送所有流量:关闭

家庭局域网路由

1
192.168.9.0/24 → 10.1.0.1 → ppp0

临时设置:

1
sudo route -n add -net 192.168.9.0/24 10.1.0.1

持久化优先尝试:

1
2
sudo networksetup -setadditionalroutes "Home L2TP" \
192.168.9.0 255.255.255.0 10.1.0.1

未生效时使用:

1
/etc/ppp/ip-up

Clash Verge Rev

1
2
3
系统代理:开启
TUN:关闭
扩展配置:interface-name: en0

扩展配置内容:

1
interface-name: en0

macOS 有效系统代理

1
2
3
4
HTTPEnable : 1
HTTPSEnable : 1
HTTPProxy : 127.0.0.1
HTTPSProxy : 127.0.0.1

十六、一键检查脚本

可以保存为:

1
check-l2tp-clash.sh

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/bin/bash

HOME_TEST_IP="192.168.9.1"
VPN_PEER="10.1.0.1"

echo "========================================"
echo "1. PPP 接口"
echo "========================================"

if ifconfig ppp0 >/dev/null 2>&1; then
ifconfig ppp0 | grep 'inet '
else
echo "ppp0 不存在,L2TP 可能尚未连接"
fi

echo
echo "========================================"
echo "2. PPP 对端路由"
echo "========================================"

route -n get "$VPN_PEER" 2>/dev/null |
egrep 'route to|gateway|interface'

echo
echo "========================================"
echo "3. 公网路由"
echo "========================================"

route -n get 8.8.8.8 2>/dev/null |
egrep 'route to|gateway|interface'

echo
echo "========================================"
echo "4. 家庭局域网路由"
echo "========================================"

route -n get "$HOME_TEST_IP" 2>/dev/null |
egrep 'route to|gateway|interface'

echo
echo "========================================"
echo "5. macOS 系统代理"
echo "========================================"

scutil --proxy |
egrep 'HTTPEnable|HTTPProxy|HTTPPort|HTTPSEnable|HTTPSProxy|HTTPSPort|SOCKSEnable|SOCKSProxy|SOCKSPort'

echo
echo "========================================"
echo "6. Shell 代理环境变量"
echo "========================================"

env |
grep -iE '^(http_proxy|https_proxy|all_proxy|no_proxy)=' ||
echo "未发现代理环境变量"

echo
echo "========================================"
echo "7. 家庭网络连通性"
echo "========================================"

ping -c 2 "$VPN_PEER"
ping -c 2 "$HOME_TEST_IP"

echo
echo "检查完成"

增加执行权限:

1
chmod +x check-l2tp-clash.sh

运行:

1
./check-l2tp-clash.sh

十七、最终验证标准

公网默认路由

1
route -n get 8.8.8.8 | egrep 'gateway|interface'

正确:

1
2
gateway: 192.168.1.254
interface: en0

家庭局域网路由

1
route -n get 192.168.9.1 | egrep 'gateway|interface'

正确:

1
2
gateway: 10.1.0.1
interface: ppp0

系统代理

1
2
scutil --proxy | egrep \
'HTTPEnable|HTTPProxy|HTTPPort|HTTPSEnable|HTTPSProxy|HTTPSPort'

正确:

1
2
3
4
5
6
7
HTTPEnable : 1
HTTPProxy : 127.0.0.1
HTTPPort : Clash实际端口

HTTPSEnable : 1
HTTPSProxy : 127.0.0.1
HTTPSPort : Clash实际端口

浏览器与 curl

浏览器访问:

1
https://www.google.com

curl 测试:

1
curl -Iv --connect-timeout 10 https://www.google.com

注意,curl 成功不能替代浏览器测试,因为两者可能使用不同的代理来源。

十八、排查结论

本次问题不是单一故障,而是两个问题同时发生:

问题一:家庭路由缺失

1
192.168.9.1 → en0

修复:

1
192.168.9.0/24 → 10.1.0.1 → ppp0

问题二:连接 L2TP 后系统代理被关闭

1
2
HTTPEnable : 0
HTTPSEnable : 0

修复:

1
2
重新启用 Clash 系统代理
或给 L2TP 网络服务单独配置 HTTP/HTTPS 代理

最终要同时满足:

1
2
3
4
家庭网段走 ppp0
公网路由走 en0
浏览器系统代理走 Clash
Clash 代理节点从 en0 出口访问

只盯着 Clash 配置文件、只盯着路由表,或者只看 curl 是否成功,都容易误判。

macOS 网络排障最重要的是分层验证:

1
2
3
4
5
6
第一层:PPP 隧道是否建立
第二层:家庭网段路由是否正确
第三层:公网默认路由是否正确
第四层:系统代理是否真正启用
第五层:Clash 到代理节点是否正常
第六层:浏览器和终端是否使用同一代理来源

路由正确Clash 正常浏览器使用了 Clash 是三件不同的事情。把这三层拆开看,问题就不会再像一锅网络玄学。


macOS 同时使用 L2TP 与 Clash Verge Rev:内网路由与系统代理冲突排查实录
https://allendericdalexander.github.io/2026/07/23/macos-l2tp-clash-verge-routing-troubleshooting/
作者
AtLuoFu
发布于
2026年7月23日
许可协议