多线 VPS(一台机器挂多个 IP、多个运营商出口)最常踩的坑不是「不通」,而是「从哪个 IP 出去不受控」。表现往往很迷惑:
- 服务明明绑定了 A 网卡,对端看到的却是 B 的 IP
- 从 A IP 进来,回包却从 B 出去,导致连接被丢
- 想让代理从「干净的那个 IP」出口,结果一直用的是主 IP
这篇讲清三件事:内核怎么选源地址、怎么查当前选的是谁、怎么强制指定(从简单到精确三种手段)。
本文属于 VPS 网络与代理链路系列,该系列共六篇,可从此页查看完整阅读顺序与全部索引。
一、问题的根源:源地址是谁决定的
很多人以为「绑定网卡就等于指定出口 IP」,其实不是。Linux 选源地址有固定顺序:
- 路由表条目里的
src字段(优先级最高) - 如果没有
src,用出口网卡的主 IP - 都不满足则报错
Network is unreachable
所以如果路由表里没写 src,内核就按网卡主 IP 走——这往往是错的,因为多线机器每块网卡都有独立的 IP 和网关。
| 典型多线配置 | 网卡 | IP 段 | 网关 |
|---|---|---|---|
| 电信线路 | eth0 | 1.1.1.0/24 | 1.1.1.1 |
| 联通线路 | eth1 | 2.2.2.0/24 | 2.2.2.1 |
| 移动线路 | eth2 | 3.3.3.0/24 | 3.3.3.1 |
如果只配了一条默认路由,那所有流量都从一个出口走,另外两条线的 IP 就是「摆设」——收包能用,发包不用。
二、先查清现状:三条命令
# 1) 看所有 IP 和网卡
ip -4 addr show
# 2) 看路由表(注意每条 default 有没有 src 字段)
ip route show
# 3) 最关键:去某个目标,实际会用哪个源 IP
ip route get 8.8.8.8
第 3 条命令的输出长这样:
8.8.8.8 via 1.1.1.1 dev eth0 src 1.1.1.10 uid 0
cache
读法:via 1.1.1.1 是网关,dev eth0 是出口网卡,src 1.1.1.10 就是实际用的源 IP。
想验证某个特定源 IP 会走哪条路,加 from 参数:
ip route get 8.8.8.8 from 2.2.2.10
三、手段一:路由表加 src 字段(最简单)
适合「只想要一个固定出口」的场景。
# 指定默认路由的源地址
ip route replace default via 1.1.1.1 dev eth0 src 1.1.1.10
# 验证
ip route get 8.8.8.8
局限:只能设一个默认出口。想让「访问 A 网段走电信、访问 B 网段走联通」就做不到,得上策略路由。
四、手段二:策略路由(按规则分流)
策略路由的核心是 ip rule + 多张路由表。规则按优先级(数字小的先匹配)决定用哪张表。
4.1 建两张自定义路由表
# 表名只是便于阅读,数字是实际标识
echo "100 telecom" >> /etc/iproute2/rt_tables
echo "200 unicom" >> /etc/iproute2/rt_tables
4.2 给每张表配默认路由
# 电信表
ip route add default via 1.1.1.1 dev eth0 src 1.1.1.10 table telecom
# 联通表
ip route add default via 2.2.2.1 dev eth1 src 2.2.2.10 table unicom
# 表内还要能到达自己的网段(否则回包出不去)
ip route add 1.1.1.0/24 dev eth0 src 1.1.1.10 table telecom
ip route add 2.2.2.0/24 dev eth1 src 2.2.2.10 table unicom
4.3 加规则
# 从电信 IP 发出的流量,查电信表
ip rule add from 1.1.1.10 table telecom priority 100
# 从联通 IP 发出的流量,查联通表
ip rule add from 2.2.2.10 table unicom priority 200
# 查看规则顺序(priority 小的在前)
ip rule list
这样配置后,源 IP 决定了走哪条线:服务绑定 1.1.1.10 就从电信出去,绑定 2.2.2.10 就从联通出去。
4.4 也可以按目标地址分流
# 去 8.8.8.0/24 的流量强制走联通
ip rule add to 8.8.8.0/24 table unicom priority 150
五、手段三:应用层绑定(最精确)
如果只想让某个程序从特定 IP 出去,不动系统路由,用应用层绑定最省事。
5.1 命令行工具
# curl 指定源 IP
curl --interface 1.1.1.10 -4 https://ifconfig.me
# ping 指定源 IP
ping -I 1.1.1.10 8.8.8.8
# ssh 指定源 IP
ssh -b 1.1.1.10 用户@目标
5.2 Xray 出站绑定
{
"outbounds": [{
"protocol": "freedom",
"sendThrough": "1.1.1.10",
"settings": { "domainStrategy": "UseIP" },
"tag": "direct"
}]
}
sendThrough 就是指定出站源 IP。搭配 domainStrategy: UseIP 能确保先解析再绑定,避免域名解析阶段走错出口。
5.3 sing-box 出站绑定
{
"outbounds": [{
"type": "direct",
"tag": "direct",
"inet4_bind_address": "1.1.1.10"
}]
}
六、验证:三处都要对
| 检查点 | 命令 | 期望 |
|---|---|---|
| 内核选路 | ip route get 8.8.8.8 from 1.1.1.10 |
src 是你指定的 IP |
| 实际出口 | curl --interface 1.1.1.10 https://ifconfig.me |
返回该 IP |
| 代理出口 | 客户端连上后 curl ifconfig.me |
返回期望的 IP |
三处都对才算配好。只改路由不看实际出口,很容易出现「路由看着对、实际发出去还是主 IP」的情况。
七、四个必踩的坑
7.1 只配路由,没配 src → 回程从别的 IP 出
最常见。路由指向了 eth1 的网关,但没写 src,内核用 eth1 主 IP 发包;如果对端按源 IP 做白名单,直接拒绝。
解法:路由条目里显式写 src。
7.2 rp_filter 严格模式丢弃非对称回包
多线机器天然存在非对称路由(从 A 进、从 B 出)。内核默认的严格 rp_filter 会认为「这个包不该从这张网卡回来」,直接丢弃——表现为「能连上但收不到响应」。
# 查看当前值(1 = 严格,2 = 松散,0 = 关闭)
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.eth0.rp_filter
# 改成松散模式(推荐,比直接关更安全)
sysctl -w net.ipv4.conf.all.rp_filter=2
sysctl -w net.ipv4.conf.default.rp_filter=2
# 按网卡设置
for i in eth0 eth1 eth2; do
sysctl -w net.ipv4.conf.$i.rp_filter=2
done
# 持久化
cat >> /etc/sysctl.conf <<EOF
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
EOF
7.3 策略路由没考虑已建立的连接
用 ip rule + from 时,规则对新建连接有效,但已建立的连接仍走旧路径。改完规则后旧连接会僵住,看起来像「改了没生效」。
解法:改完策略路由后重启相关服务,或等旧连接超时。用 fwmark 做规则时更要注意这点。
7.4 重启后全部失效
ip route / ip rule 命令都是运行时配置,重启即丢。
解法:写成一个 systemd service,开机自动执行:
cat > /usr/local/bin/setup-multiline.sh <<'EOF'
#!/bin/bash
# 清掉旧规则(幂等)
ip rule del table telecom 2>/dev/null
ip rule del table unicom 2>/dev/null
ip route replace default via 1.1.1.1 dev eth0 src 1.1.1.10 table telecom
ip route replace default via 2.2.2.1 dev eth1 src 2.2.2.10 table unicom
ip route replace 1.1.1.0/24 dev eth0 src 1.1.1.10 table telecom
ip route replace 2.2.2.0/24 dev eth1 src 2.2.2.10 table unicom
ip rule add from 1.1.1.10 table telecom priority 100
ip rule add from 2.2.2.10 table unicom priority 200
EOF
chmod +x /usr/local/bin/setup-multiline.sh
cat > /etc/systemd/system/multiline-routing.service <<'EOF'
[Unit]
Description=Multi-WAN source routing
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/setup-multiline.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now multiline-routing.service
systemctl status multiline-routing.service
八、三种手段怎么选
| 手段 | 粒度 | 适合 | 复杂度 |
|---|---|---|---|
路由加 src |
全局默认出口 | 单出口机器,只想固定源 IP | 低 |
| 策略路由 | 按源 IP / 目标网段 | 多线分流,不同业务走不同线 | 中 |
| 应用层绑定 | 单个进程 | 只让某个服务走特定 IP | 低 |
推荐顺序:能用应用层绑定解决就不动系统路由(影响面最小);需要整机默认出口就加 src;只有真正需要按规则分流时才上策略路由。
九、小结
多线机器的核心认知就一句话:源地址是内核按路由表选的,不是按你绑定的网卡选的。
排查顺序固定三步:ip -4 addr 看有哪些 IP → ip route get 看实际用哪个 → 用 src/ip rule/sendThrough 强制指定。
配完一定用 curl --interface 验证真实出口,别只看路由表——这两个不一致是这类问题最常见的翻车点。
相关阅读
- 路由追踪怎么读:traceroute、mtr 与 AS 路径判读 —— 先学会看路径,再谈改路由
- 路由优化实战:回程怎么看,线路怎么选,中转怎么加 —— 多线的目的是用上更好的线路
- 线路机、落地机、家宽、前置、IX、专线(IPLC/IEPL)都是什么 —— 概念层基础
- 中转家宽代理搭建实战:三种架构与完整配置 —— 中转场景下的出口 IP 控制

Comments NOTHING