这篇只保留 PVE 下运行 LXC sing-box 旁路网关时真正需要动手添加的内容。按顺序做即可:
- 在 PVE 宿主机添加宿主机网络参数。
- 在 PVE 宿主机关闭这个 LXC 的 PVE firewall,或者确认相关接口的
rp_filter已关闭。 - 在 LXC 容器里添加容器自己的转发和 sing-box 性能参数。
- 按本文方法从现有配置里取出 CTID、网桥、IP、网关、MAC、IPv6 等变量,替换示例命令。
下面示例使用:
- LXC ID:
101 - PVE 网桥:
vmbr0 - 容器 IPv4:
10.20.20.6/24 - IPv4 网关:
10.20.20.1 - 容器 IPv6:
fd88::6666/64 - IPv6 网关:
fd88::1111 - 容器网卡 MAC:
BC:24:11:1E:91:3C
这些值只是示例,必须按你自己的 pct config <CTID> 输出替换。
1. 先获取自己的变量
所有 pct 命令都在 PVE 宿主机 Shell 执行,不是在 LXC 容器里执行。
先列出容器,确认 sing-box 所在的 LXC ID:
pct list假设 sing-box 容器 ID 是 101,查看它当前的网卡配置:
pct config 101 | grep '^net0'你会看到类似输出:
net0: name=eth0,bridge=vmbr0,firewall=1,gw=10.20.20.1,gw6=fd88::1111,hwaddr=BC:24:11:1E:91:3C,ip=10.20.20.6/24,ip6=fd88::6666/64,type=veth这里每个字段都可以直接对应到后面的 pct set 命令:
| 字段 | 示例值 | 怎么获取 |
|---|---|---|
| CTID | 101 |
pct list 第一列 |
| name | eth0 |
`pct config 101 |
| bridge | vmbr0 |
同一行里的 bridge= |
| gw | 10.20.20.1 |
同一行里的 gw= |
| gw6 | fd88::1111 |
同一行里的 gw6=,没有 IPv6 就不要写 gw6 |
| hwaddr | BC:24:11:1E:91:3C |
同一行里的 hwaddr=,这就是原来的 MAC 地址 |
| ip | 10.20.20.6/24 |
同一行里的 ip= |
| ip6 | fd88::6666/64 |
同一行里的 ip6=,没有 IPv6 就不要写 ip6 |
| type | veth |
同一行里的 type= |
hwaddr 后面的参数不需要重新生成,直接从当前 net0 的 hwaddr= 抄出来即可。这样关闭 PVE firewall 后,容器 MAC 不会变化,路由器 DHCP 静态绑定、邻居表、ACL 也不会被打乱。
再确认这个 LXC 在 PVE 宿主机侧对应的接口名:
ip -br link | grep -E 'veth101|fwbr101|fwpr101|fwln101|vmbr0'常见情况:
vmbr0 UP ...
veth101i0@if2 UP ... master vmbr0 ...含义是:
vmbr0是容器挂载的 PVE 网桥。veth101i0是 LXC 101 在 PVE 宿主机侧的虚拟网卡。- 如果还能看到
fwbr101i0、fwpr101p0、fwln101i0,说明这个 LXC 还在 PVE firewall 路径里。
2. PVE 宿主机要添加什么
这一部分只在 PVE 宿主机 做。
2.1 添加全局网关性能参数
编辑 PVE 宿主机文件:
nvim /etc/sysctl.d/99-sing-box-gateway.conf写入:
# PVE 宿主机承载 sing-box LXC 网关时使用,负责宿主机桥接、物理网卡队列和全局转发。
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding = 1
# TCP 出站使用 fq + BBR;Hysteria2/TUIC/QUIC 主链路是 UDP,BBR 不会直接优化 UDP。
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# 提高宿主机收包积压队列和 TCP 监听队列,适合旁路网关突发流量。
net.core.netdev_max_backlog = 250000
net.core.somaxconn = 8192
net.ipv4.tcp_max_syn_backlog = 8192
# 提高 TCP/UDP socket 缓冲上限,避免高速 UDP 先撞到系统缓冲限制。
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.udp_rmem_min = 16384
# 保留基础连接健壮性,不使用过激 TIME_WAIT 回收参数。
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_fastopen = 3
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200应用:
sysctl -p /etc/sysctl.d/99-sing-box-gateway.conf2.2 添加 PVE 旁路网关 rp_filter 配置
编辑 PVE 宿主机文件:
nvim /etc/sysctl.d/98-sing-box-pve-bypass.conf如果你的 CTID 是 101,网桥是 vmbr0,宿主机侧接口是 veth101i0,写入:
# PVE 宿主机侧关闭反向路径过滤,避免 TProxy、FakeIP、策略路由的非对称路径被桥接层误丢。
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.vmbr0.rp_filter = 0
net.ipv4.conf.veth101i0.rp_filter = 0如果 ip -br link 里实际存在 PVE firewall 接口,再额外追加:
# 只有这些接口真实存在时才添加;不存在就不要写,避免 sysctl 加载时报错。
net.ipv4.conf.fwbr101i0.rp_filter = 0
net.ipv4.conf.fwpr101p0.rp_filter = 0
net.ipv4.conf.fwln101i0.rp_filter = 0应用:
sysctl -p /etc/sysctl.d/98-sing-box-pve-bypass.conf2.3 关闭这个 LXC 的 PVE firewall
如果这个 LXC 专门做 sing-box 网关,且不依赖 PVE firewall 过滤入站,建议关闭该 LXC 网卡的 PVE firewall,减少 fwbr/fwpr/fwln 这一层。
先用当前配置取值:
pct config 101 | grep '^net0'再按原值改写 pct set。示例:
pct set 101 -net0 name=eth0,bridge=vmbr0,firewall=0,gw=10.20.20.1,gw6=fd88::1111,hwaddr=BC:24:11:1E:91:3C,ip=10.20.20.6/24,ip6=fd88::6666/64,type=veth替换规则:
101:换成你的 CTID。bridge=vmbr0:换成pct config里原来的bridge=。gw=、gw6=、ip=、ip6=:照抄原来的值;没有 IPv6 就删除gw6=...和ip6=...。hwaddr=...:照抄原来的hwaddr=,不要随便换 MAC。firewall=0:这是这条命令唯一主动修改的目标。
改完确认:
pct config 101 | grep '^net0'
ip -br link | grep -E 'veth101|fwbr101|fwpr101|fwln101'理想结果是 net0 里显示 firewall=0,运行态只剩 veth101i0,不再出现 fwbr101i0、fwpr101p0、fwln101i0。
3. LXC 容器里要添加什么
这一部分只在 sing-box 所在的 LXC 容器内 做。
3.1 添加容器转发参数
编辑容器内文件:
vi /etc/sysctl.d/local.conf写入:
# LXC 容器作为旁路网关时必须开启转发,并关闭容器内 eth0 的反向路径过滤。
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.eth0.rp_filter = 0
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding = 1
net.ipv6.conf.eth0.forwarding = 1
net.ipv6.conf.eth0.accept_ra = 2
net.ipv6.conf.eth0.accept_ra_defrtr = 1Alpine / BusyBox 的 sysctl 通常不支持 --system,直接指定文件加载:
sysctl -p /etc/sysctl.d/local.conf如果容器不用 IPv6,可以删除所有 net.ipv6.* 行。
3.2 添加 sing-box 性能参数
编辑容器内文件:
vi /etc/sysctl.d/98-sing-box-performance.conf写入:
# sing-box 在容器内发起 TCP/UDP 出站连接,这些参数要在容器命名空间内单独设置。
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_rmem = 4096 131072 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.udp_rmem_min = 16384
net.ipv4.tcp_slow_start_after_idle = 0应用:
sysctl -p /etc/sysctl.d/98-sing-box-performance.conf如果提示 bbr 不可用,先看可用算法:
sysctl net.ipv4.tcp_available_congestion_control如果输出里没有 bbr,就把这一行注释掉:
# net.ipv4.tcp_congestion_control = bbr3.3 设置开机自动加载
Alpine LXC 使用 OpenRC 时,在容器内执行:
rc-update add sysctl boot如果手动验证:
rc-service sysctl start非特权 LXC 里可能看到 kernel.*、fs.* 的 Read-only file system 提示,这是系统默认参数碰到容器不可写项。只要下面的检查值正确,就说明本文添加的网关参数已经生效。
4. 最后验证
4.1 PVE 宿主机验证
在 PVE 宿主机执行:
sysctl net.ipv4.ip_forward
sysctl net.ipv6.conf.all.forwarding
sysctl net.ipv4.tcp_congestion_control
sysctl net.core.default_qdisc
sysctl net.core.rmem_max net.core.wmem_max
sysctl net.ipv4.udp_rmem_min
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.vmbr0.rp_filter
sysctl net.ipv4.conf.veth101i0.rp_filter预期关键值:
net.ipv4.ip_forward = 1
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.vmbr0.rp_filter = 0
net.ipv4.conf.veth101i0.rp_filter = 04.2 LXC 容器验证
在 LXC 容器内执行:
sysctl net.ipv4.ip_forward
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.eth0.rp_filter
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem
sysctl net.ipv4.udp_rmem_min预期关键值:
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.tcp_congestion_control = bbr
net.ipv4.udp_rmem_min = 163844.3 UDP 丢包检查
在 LXC 容器内观察 sing-box UDP socket:
ss -unmp连续观察:
watch -n 1 'ss -unmp | grep -E "sing-box|drops|udp"'如果测速或高峰下载时 drops 持续增长,优先检查:
- 容器内
net.ipv4.udp_rmem_min是否生效。 - PVE 宿主机
net.core.rmem_max、net.core.wmem_max是否生效。 - sing-box / Hysteria2 / TUIC 自身是否还有 socket buffer 或带宽参数需要调整。
- PVE 宿主机 CPU、物理网卡和 veth offload 能力。
4.4 offload 检查
offload 在 PVE 宿主机检查,不是在 LXC 容器里检查。
先找物理网卡和容器 veth:
ip -br link看 master vmbr0 的接口。常见关系如下:
enp2s0 UP ... master vmbr0 ...
vmbr0 UP ...
veth101i0 UP ... master vmbr0 ...检查:
ethtool -k enp2s0
ethtool -k veth101i0重点看:
generic-segmentation-offload
generic-receive-offload
tx-udp-segmentation如果物理网卡或 veth 的关键项是 off,并且驱动允许修改,再尝试:
ethtool -K enp2s0 gso on gro on
ethtool -K enp2s0 tx-udp-segmentation on
ethtool -K veth101i0 gso on gro on
ethtool -K veth101i0 tx-udp-segmentation on有些 veth 不允许打开 GRO,有些网卡不支持 tx-udp-segmentation。这不是 sysctl 能解决的问题,按实际输出判断即可。
5. 不要添加这些旧参数
下面这些参数不建议为了“优化”照抄:
net.ipv4.tcp_congestion_control = hybla
fs.file-max = 100000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_tw_buckets = 5000原因很简单:
hybla不适合作为现代代理网关默认拥塞控制,优先用bbr。fs.file-max = 100000可能反而低于现代 Linux 默认值。tcp_tw_reuse不是透明代理和 UDP 性能问题的通用解法。tcp_max_tw_buckets = 5000太小,可能导致内核过早回收连接状态。
最终只记住两层边界:PVE 宿主机负责 vmbr0、veth101i0、PVE firewall 路径、物理网卡和全局缓冲;LXC 容器负责自己的 eth0、转发、容器命名空间 sysctl,以及 sing-box 进程实际使用的 TCP/UDP 参数。