目标:在国内一条软路由(Rocky9)上拉上 电信、联通、移动三条宽带,按目标 IP 所属的运营商自动选择对应出口线路,避免三大运营商之间跨网绕路导致的严重访问阻塞。
思路:用一台海外 Vultr 云主机接收 BGP 全表(它网络好、能拿到完整路由表),通过 WireGuard 隧道经 iBGP 把「按中国运营商 ASN 分好类」的路由下发给本地 Rocky9;本地再按 ASN 把目标 IP 分流到电信/联通/移动各自的拨号接口。
一、整体架构
[Internet BGP 全表]
│ eBGP(邻居 169.254.169.254 as 64515,Vultr 提供)
▼
Vultr 云主机 (BIRD) ── router id 108.61.219.200 / AS 4288000739
│ │
│ filter:只保留中国运营商 ASN 的路由
▼
│ WireGuard 隧道 (10.0.1.1) ←── BGP 承载链路
▼
本地 Rocky9 软路由 (BIRD) ── router id 10.0.1.2 / AS 64555
│
│ kernel:按目标 IP 所属运营商选择出口
├── ppp0 ── 电信宽带 ── 中国电信 ASN
├── ppp1 ── 联通宽带 ── 中国联通 ASN
└── ppp2 ── 移动宽带 ── 中国移动 ASN
为什么三线分流有用:国内三大运营商骨干网互联(跨网)带宽紧张、绕路多,电信访问联通、移动都很慢。我们自己拉三条宽带后,目标 IP 属于哪家运营商就走哪家的出口线路——同网直连,绕开跨网拥堵。
二、第一步:WireGuard 隧道(连接 Vultr 云端与本地 Rocky9)
BGP 会话通过这条隧道承载,隧道内网段规划 10.0.1.0/24:云端 10.0.1.1、本地 10.0.1.2。
云端 Vultr(/etc/wireguard/wg0.conf)
[Interface]
Address = 10.0.1.1/24
ListenPort = 51820
PrivateKey = <云端生成的私钥> # wg genkey 生成
[Peer]
# 本地 Rocky9
PublicKey = <本地公钥> # 来自本地 wg pubkey
AllowedIPs = 10.0.1.2/32
PersistentKeepalive = 25 # 保活,穿透 NAT,让本地能主动连出到云
本地 Rocky9(/etc/wireguard/wg0.conf)
[Interface]
Address = 10.0.1.2/24
PrivateKey = <本地生成的私钥>
[Peer]
# Vultr 云端
PublicKey = <云端公钥>
Endpoint = <Vultr公网IP>:51820 # 云端是公网固定地址,本地主动连出
AllowedIPs = 10.0.1.1/32
PersistentKeepalive = 25
启用隧道(两端)
# 生成密钥
wg genkey | tee privatekey | wg pubkey > publickey
# 启用并自启动
systemctl enable --now wg-quick@wg0
# 验证
wg show wg0
ping -c3 10.0.1.1 # 云端,本地测
ping -c3 10.0.1.2 # 本地,云端测
云端是公网固定 IP,用
Endpoint指向云端公网地址 +PersistentKeepalive保活,本地在 NAT 后面也能稳定维持隧道。
三、第二步:云端 Vultr 配置(收全表 + 按运营商分类)
文件 ebgp.conf.txt,运行在 Vultr 云主机的 BIRD 上。
1. 中国运营商 ASN 集合
define CTELECOM_ASN = [ 4134, 4809, 23764 ]; # 电信 (163/CN2/CTG)
define CUNICOM_ASN = [ 4837, 9929, 10099 ]; # 联通 (169/A网/CUG)
define CMOBILE_ASN = [ 9808, 58453, 58807 ]; # 移动 (CM/CMI)
# 可选:教育网等其他
# define CEDU_ASN = [ 4538 ];
2. 基础
router id 108.61.219.200;
log syslog all;
protocol device {}
protocol direct { ipv4; interface "enp1s0"; } # 本地直连接口,不同系统会变
3. 入站过滤器:把不同运营商的路径打上不同的本地优先级与 Community
filter vultr_in_filter {
if (bgp_path ~ CTELECOM_ASN) then { bgp_local_pref = 200; bgp_community = (64555,1001); accept; }
if (bgp_path ~ CUNICOM_ASN) then { bgp_local_pref = 200; bgp_community = (64555,1002); accept; }
if (bgp_path ~ CMOBILE_ASN) then { bgp_local_pref = 200; bgp_community = (64555,1003); accept; }
reject;
}
4. 与 Vultr 的 eBGP 会话(接收全表)
protocol bgp vultr {
local as 4288000739; # Vultr 控制面板提供的你的私有 ASN
neighbor 169.254.169.254 as 64515; # Vultr 固定邻居 IP 和 ASN
# password "此处填入你的BGP会话密码"; # 原密码已移除,需要认证请自行填回
multihop 2; # 必须:邻居是私有地址
source address 108.61.219.200; # 发起连接源 IP
ipv4 {
import filter vultr_in_filter; # 应用分类过滤
export none; # 不向 Vultr 宣告任何路由
import limit 1000000 action warn; # 收全表必须开
};
hold time 240;
keepalive time 80;
}
5. 经 WireGuard 隧道向本地下发 iBGP
protocol bgp homelab {
local as 64555;
neighbor 10.0.1.2 as 64555; # 经由 wg0 隧道的本地 Rocky9
ipv4 {
import none; # 不从本地收路由
export all; # 把分类后的回国全表下发给本地
};
}
四、第二步:本地 Rocky9 配置(按目标 IP 分流三大运营商)
文件 ibgp.conf.txt,运行在本地 Rocky9(软路由)上。
1. 基础与运营商 ASN
router id 10.0.1.2;
log syslog all;
protocol device {}
define CTELECOM_ASN = [ 4134, 4809, 23764 ]; # 电信
define CUNICOM_ASN = [ 4837, 9929, 10099 ]; # 联通
define CMOBILE_ASN = [ 9808, 58453, 58807 ]; # 移动
2. 内核协议:按目标 IP 所属运营商写进对应拨号接口
protocol kernel {
ipv4 {
table master4;
import none; # 不把本地路由灌进 BGP
export filter {
# dst 属于电信 → 走 ppp0(电信宽带)
if (bgp_path ~ CTELECOM_ASN) then { ifname = "ppp0"; accept; }
# dst 属于联通 → 走 ppp1(联通宽带)
if (bgp_path ~ CUNICOM_ASN) then { ifname = "ppp1"; accept; }
# dst 属于移动 → 走 ppp2(移动宽带)
if (bgp_path ~ CMOBILE_ASN) then { ifname = "ppp2"; accept; }
# 其余拒收
reject;
};
};
kernel table 2; # BGP拉过来的路由没有放到主路由表254,测试环境我就放在表2
}
含义:命中哪家运营商的路径条目标记为对应出口
ppp0/ppp1/ppp2并写入内核路由表,其余拒绝。这样目标 IP 属于电信就走电信出口、属于联通就走联通出口,同网直连不跨网。
3. 从云端(经 WireGuard)iBGP 接收分类路由
protocol bgp vultr {
local as 64555;
neighbor 10.0.1.1 as 64555; # 经由 wg0 隧道的 Vultr 云端
ipv4 {
import all; # 接收云端下发的分类回国路由
export none; # 不向云端发送路由
};
}
五、落地顺序建议
- 两端装好 WireGuard,
ping通10.0.1.x,确认隧道可用。 - 云端 Vultr 起
ebgp.conf.txt,birdc show protocols确认 vultr 与 homelab 会话都Established。 - 云端
birdc show route抽查,确认只收三大运营商且已被打上不同 Community/优先级。 - 本地配好三条 PPPoE 拨号(
ppp0/ppp1/ppp2),再起ibgp.conf.txt。 ip route确认命中三大运营商的路径出接口分别为ppp0/ppp1/ppp2。- 内网客户端 actraceroute 测试,验证同网直连、不跨网。
六、附:完整可直接运行的配置(三份)
配置文件 A:云端 Vultr —— ebgp.conf.txt
define CTELECOM_ASN = [ 4134, 4809, 23764 ];
define CUNICOM_ASN = [ 4837, 9929, 10099 ];
define CMOBILE_ASN = [ 9808, 58453, 58807 ];
log syslog all;
router id 108.61.219.200;
protocol device {}
protocol direct { ipv4; interface "enp1s0"; }
filter vultr_in_filter {
if (bgp_path ~ CTELECOM_ASN) then { bgp_local_pref = 200; bgp_community = (64555,1001); accept; }
if (bgp_path ~ CUNICOM_ASN) then { bgp_local_pref = 200; bgp_community = (64555,1002); accept; }
if (bgp_path ~ CMOBILE_ASN) then { bgp_local_pref = 200; bgp_community = (64555,1003); accept; }
reject;
}
protocol bgp vultr {
local as 4288000739;
neighbor 169.254.169.254 as 64515;
# password "此处填入你的BGP会话密码"; # 需要认证请填回
multihop 2;
source address 108.61.219.200;
ipv4 {
import filter vultr_in_filter;
export none;
import limit 1000000 action warn;
};
hold time 240;
keepalive time 80;
}
protocol bgp homelab {
local as 64555;
neighbor 10.0.1.2 as 64555; # 经 wg0 与本地 iBGP
ipv4 {
import none;
export all;
};
}
配置文件 B:本地 Rocky9 —— ibgp.conf.txt
router id 10.0.1.2;
log syslog all;
protocol device {}
define CTELECOM_ASN = [ 4134, 4809, 23764 ];
define CUNICOM_ASN = [ 4837, 9929, 10099 ];
define CMOBILE_ASN = [ 9808, 58453, 58807 ];
protocol kernel {
ipv4 {
table master4;
import none;
export filter {
if (bgp_path ~ CTELECOM_ASN) then { ifname = "ppp0"; accept; }
if (bgp_path ~ CUNICOM_ASN) then { ifname = "ppp1"; accept; }
if (bgp_path ~ CMOBILE_ASN) then { ifname = "ppp2"; accept; }
reject;
};
};
kernel table 2;
}
protocol bgp vultr {
local as 64555;
neighbor 10.0.1.1 as 64555; # 经 wg0 与云端 iBGP
ipv4 {
import all;
export none;
};
}
配置文件 C:WireGuard 隧道(两端)
云端 Vultr /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.1.1/24
ListenPort = 51820
PrivateKey = <云端私钥>
[Peer]
PublicKey = <本地公钥>
AllowedIPs = 10.0.1.2/32
PersistentKeepalive = 25
本地 Rocky9 /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.1.2/24
PrivateKey = <本地私钥>
[Peer]
PublicKey = <云端公钥>
Endpoint = <Vultr公网IP>:51820
AllowedIPs = 10.0.1.1/32
PersistentKeepalive = 25
把
<...>替换为实际密钥与 IP,用wg genkey/wg pubkey生成,systemctl enable --now wg-quick@wg0拉起即可。
七、常见坑
import limit必须要:运营商全表数据量极大,不设会内存/资源失控。multihop/source address不要漏:Vultr 邻居是链路本地私有地址。- 密码已移除:需要认证的会话请自行填回
password(当前文件里是占位)。 - 建立EBGP的本地ASN可能会变:具体请参考Vultr给的是多少。
- 接口名对不上:
ifname = "ppp0/ppp1/ppp2"必须与三条 PPPoE 拨号的实际接口名一致,否则路由装入但无法转发。 - WireGuard 保活:本地 NAT 要
PersistentKeepalive,否则隧道会被运营商 NAT 剪掉。 - BGP 走隧道:确认 iBGP 邻居地址是
10.0.1.x隧道网段,且两端 wg 已建立,BGP 才能Established。