server_config: 启用 UDP 传输(Hysteria2/TUIC)+ UDP 系统调优,如实记录 KVM/LXC/NAT/NSG 差异

- README 新增 §6.4:Hysteria2/TUIC 配置片段、带宽声明与 Brutal 取舍、客户端链接格式、端到端验证方法
- 如实记录各节点差异(2026-09-20 实测):
  * hk2 NAT 段 4301-4320 UDP 1:1
  * ru(LXC NAT)外部只有宿主映射的 UDP 端口可达(23336+ 实测 connection refused),最终复用与 TCP 同号的 23333/23334
  * jp(Azure)NSG 仅放行 UDP 8445 → 单节点只能承载一个 UDP 协议,保留 TUIC
  * aq 为 IPv6-only,listen 用 ::
- §2.6 UDP 策略修订:由「不部署 UDP」改为「已启用 UDP 传输,同时保留 UoT」
- sysctl 模板补 udp_rmem_min/udp_wmem_min;rrpp-qdisc.sh 增加 rx-udp-gro-forwarding / rx-gro-list(aq 内核 5.10 不支持前者,LXC 无法设置)
- §10 验证清单补 UDP 项,并强调「只看监听不足以证明外部可达」
This commit is contained in:
2026-09-20 22:05:57 +08:00
parent 375153b810
commit 8809e40ec1
4 changed files with 109 additions and 45 deletions
+82 -3
View File
@@ -226,9 +226,17 @@ sysctl --system 2>/dev/null | grep -n tcp_mtu_probing | tail -5 # 看谁在最
`rrpp-qdisc.service` 在开机后显式执行 `tc qdisc replace dev <默认路由网卡> root fq` 补齐; `rrpp-qdisc.service` 在开机后显式执行 `tc qdisc replace dev <默认路由网卡> root fq` 补齐;
脚本对容器(`noqueue`)会自动跳过。 脚本对容器(`noqueue`)会自动跳过。
**UDP 策略(2026-09 起)**:节点**不部署 UDP 传输**(Hysteria2 / TUIC / QUIC 等一律不用)。 **UDP 策略(2026-09-20 修订)**:节点**已启用 UDP 传输**(sing-box 内建 **Hysteria2** 与 **TUIC v5** 入站,见 §6.4),
客户端 UDP 需求统一走 **UoT v2**(见 §5.5):UDP 数据报封装进 TCP CONNECT 隧道, 用于对抗跨境链路的丢包/高 RTT;**同时保留 UoT v2** 路径(见 §5.5)——客户端 TUN 模式的 UDP
经 nginx magic 地址转到本机 `127.0.0.1:15201` relay 解封装。 仍可封装进 TCP CONNECT 隧道,两条路并存、互不影响。
节点侧 UDP 相关系统调优(与 6.4 配套):
| 项 | 值 / 说明 |
|---|---|
| `net.ipv4.udp_rmem_min` / `udp_wmem_min` | `8192`(容器内可写,实测 LXC 同样生效) |
| `net.core.rmem_max` / `wmem_max` | `33554432`(KVM 可写;**LXC 缺失/只读**) |
| `rx-udp-gro-forwarding` / `rx-gro-list`(ethtool) | 由 `rrpp-qdisc.sh` 开机开启;**实测支持情况**:us/jp ✅ 两项;aq(内核 5.10)仅 `rx-gro-list`;**LXC 容器无 netdev 权限,无法设置** |
| QUIC/UDP 吞吐 | 受宿主机 socket 缓冲上限约束——**LXC 节点上这是硬约束**,需服务商在宿主调 `rmem_max` |
**明确不采用的手段**:锐速/LotServer(闭源、绑定旧内核)、net-speeder(重复包、已废弃)、 **明确不采用的手段**:锐速/LotServer(闭源、绑定旧内核)、net-speeder(重复包、已废弃)、
`tcp_tw_recycle`(4.12 起内核已移除,开启会破坏 NAT 后客户端)、`tcp_notsent_lowat` 激进值 `tcp_tw_recycle`(4.12 起内核已移除,开启会破坏 NAT 后客户端)、`tcp_notsent_lowat` 激进值
@@ -515,6 +523,72 @@ EOF
--- ---
### 6.4 Hysteria2 / TUIC(UDP 传输,2026-09-20 起全节点启用)
TCP 系协议在跨境丢包链路上受拥塞控制限制(BBR 已缓解但仍有天花板);QUIC 系
(**Hysteria2** 的 Brutal CC、**TUIC v5**)能显著改善高丢包下的吞吐与时延。
两者都是 **sing-box 内建**,无需额外二进制;UDP 需求仍可走 UoT(§5.5),两条路并存。
```json
// Hysteria2(sing-box inbound)
{ "type": "hysteria2", "tag": "hy2-in-<端口>", "listen": "0.0.0.0", "listen_port": "<端口>",
"up_mbps": 100, "down_mbps": 100,
"obfs": { "type": "salamander", "password": "<obfs密码>" },
"users": [ { "name": "<节点>-hy2", "password": "<hy2密码>" } ],
"tls": { "enabled": true, "server_name": "<节点域名>",
"certificate_path": "/etc/nginx/ssl/<节点域名>/fullchain.pem",
"key_path": "/etc/nginx/ssl/<节点域名>/privkey.pem", "alpn": ["h3"] },
"masquerade": "file:///var/www/html" }
// TUIC v5
{ "type": "tuic", "tag": "tuic-in-<端口>", "listen": "0.0.0.0", "listen_port": "<端口>",
"users": [ { "name": "<节点>-tuic", "uuid": "<UUID>", "password": "<密码>" } ],
"congestion_control": "bbr",
"tls": { /* 同上 */ } }
```
**要点**
- **带宽声明决定 Brutal**:`up_mbps`/`down_mbps` 不写时,服务端会命令客户端改用 BBR;
写了才允许 Hysteria CC(Brutal)。默认 100 Mbps,计量流量的节点给 50。
Brutal **不遵守拥塞控制**,设错会占满链路甚至被服务商判定异常流量——务必按实际带宽设。
- `obfs: salamander` 给 QUIC 加一层混淆(对抗 QUIC 特征识别);`masquerade` 指向伪装页,
未认证访问返回与 nginx 一致的页面。
- TUIC 保持 `zero_rtt_handshake` 关闭(默认,0-RTT 可被重放)。
- 凭据**每节点独立**,与 VLESS/SS/CONNECT 同策略。
**各节点端口与部署差异(2026-09-20 实测,务必照抄结论)**
| 节点 | 虚拟化 | Hysteria2 (UDP) | TUIC (UDP) | 差异 / 坑 |
|---|---|---|---|---|
| hk2 | LXC(NAT) | 4305 | 4306 | NAT 段 4301-4320 UDP 1:1(探针 + 外部回扫实测) |
| us | KVM | 1208 | 1209 | 公网直连,UDP 任意端口可用 |
| ru | LXC(NAT) | 23333 | 23334 | **外部只有宿主已映射的 UDP 端口可达**:容器内 bind 任意端口都"正常",但 23336+ 实测直接 `connection refused`(ICMP port unreachable);最终复用 **23333/23334**——与 nginx/vless 占用的 **TCP 同号**,UDP 与 TCP 互不冲突 |
| aq | KVM(IPv6-only) | 8444 | 8445 | 节点为 IPv6 出口,`listen` 用 `"::"`;客户端须走 IPv6 |
| jp | Azure VM | 未部署 | 8445 | **Azure NSG 只放行 UDP 8445**(443/80/8080/8088/18080/8443/9444 的 UDP 面实测均不可达)→ 单节点只能承载一个 UDP 协议;要加 Hysteria2 须先在 NSG 放行第二个 UDP 端口 |
**客户端链接格式**
```
hysteria2://<password>@<域名>:<端口>/?sni=<域名>&alpn=h3&obfs=salamander&obfs-password=<obfs密码>#备注
tuic://<uuid>:<password>@<域名>:<端口>/?congestion_control=bbr&alpn=h3&sni=<域名>#备注
```
**验证方法(端到端,不能只看监听)**
```bash
# 在任意机器用 sing-box 作客户端:socks 入站 + 上述 outbound,然后
curl -s -m 20 -x socks5h://127.0.0.1:11080 -o /dev/null -w '%{http_code}\n' http://example.com/ # 期望 200
```
`ss -lunp` 看到端口在听**不足以**证明外部可达:ru(NAT 未映射)与 jp(NSG 未放行)
都是"监听正常但外部不可达"的真实案例。
⚠️ 代价与限制:UDP 在部分运营商会被 QoS/封禁;Brutal 对同链路其他流量不友好;
计量流量的节点(如 jp,15GB/月)注意消耗;LXC 容器内 socket 缓冲上限受宿主机约束。
---
## 7. mtg(MTProto 代理) ## 7. mtg(MTProto 代理)
Telegram 内置代理,Fake TLS 模式抗封锁。用 [mtg](https://github.com/9seconds/mtg)(Go 单二进制): Telegram 内置代理,Fake TLS 模式抗封锁。用 [mtg](https://github.com/9seconds/mtg)(Go 单二进制):
@@ -626,6 +700,11 @@ print('resp:',s.recv(8).hex())" # 期望首字节 15 (TLS alert)
# UoT relay(127.0.0.1:15201 监听 + CONNECT magic 地址) # UoT relay(127.0.0.1:15201 监听 + CONNECT magic 地址)
ss -tlnp | grep 15201 # => uot_relay.py 监听 127.0.0.1:15201 ss -tlnp | grep 15201 # => uot_relay.py 监听 127.0.0.1:15201
# UDP 传输(Hysteria2/TUIC,见 6.4)——必须端到端验证,不能只看监听
ss -lunp | grep -E ':<hy2端口>|:<tuic端口>' # 仅确认服务在听
# 再用 sing-box 客户端 + curl 经由 socks 实测(见 6.4「验证方法」)
ethtool -k <网卡> | grep -E 'rx-udp-gro-forwarding|rx-gro-list' # KVM 期望 on;LXC 容器不可设
# nginx CONNECT(带 Basic Auth,B64 = base64('<代理用户名>:<代理密码>')) # nginx CONNECT(带 Basic Auth,B64 = base64('<代理用户名>:<代理密码>'))
B64=$(printf '<代理用户名>:<代理密码>' | base64 -w0) B64=$(printf '<代理用户名>:<代理密码>' | base64 -w0)
curl -sk --proxy-insecure -x https://<节点域名>:<nginx端口> \ curl -sk --proxy-insecure -x https://<节点域名>:<nginx端口> \
+11 -6
View File
@@ -1,13 +1,18 @@
#!/bin/bash #!/bin/bash
# 把默认路由网卡的根 qdisc 设为 fq(BBR 的最佳搭档)。 # ============================================================
# 背景:net.core.default_qdisc=fq 只对"新创建"的网卡生效,已存在的网卡 # RRPP 网络接口调优脚本(开机执行)
# 重启后仍可能是 pfifo_fast/fq_codel,故用本脚本显式设置。 # 1) 把默认路由网卡的根 qdisc 设为 fq —— BBR 的最佳搭档
# 仅在 KVM/裸机可用;LXC 容器内网卡为 noqueue,本脚本会自行跳过。 # (net.core.default_qdisc=fq 只对"新创建"网卡生效,已存在网卡需显式 replace)
# 2) 开启 UDP GRO 转发 —— QUIC 系协议(Hysteria2 / TUIC)转发性能
# 容器(LXC/OpenVZ)内网卡为 noqueue、且无 netdev 权限,本脚本自动跳过。
# ============================================================
set -uo pipefail set -uo pipefail
IFACE=$(ip -4 route show default | awk '{print $5; exit}') IFACE=$(ip -4 route show default | awk '{print $5; exit}')
[ -n "${IFACE:-}" ] || { echo "未找到默认路由网卡,跳过"; exit 0; } [ -n "${IFACE:-}" ] || { echo "未找到默认路由网卡,跳过"; exit 0; }
if tc qdisc show dev "$IFACE" 2>/dev/null | grep -q " noqueue"; then if tc qdisc show dev "$IFACE" 2>/dev/null | grep -q " noqueue"; then
echo "$IFACE 为 noqueue(容器环境),跳过 qdisc 设置" echo "$IFACE 为 noqueue(容器环境),跳过 qdisc 与网卡 offload 设置"
exit 0 exit 0
fi fi
tc qdisc replace dev "$IFACE" root fq 2>/dev/null && echo "已设置 $IFACE root qdisc = fq" || echo "设置 $IFACE qdisc 失败(可忽略)" tc qdisc replace dev "$IFACE" root fq 2>/dev/null && echo "已设置 $IFACE root qdisc = fq" || echo "设置 qdisc 失败(可忽略)"
ethtool -K "$IFACE" rx-udp-gro-forwarding on 2>/dev/null && echo "已开启 $IFACE rx-udp-gro-forwarding" || echo "$IFACE 不支持 rx-udp-gro-forwarding"
ethtool -K "$IFACE" rx-gro-list on 2>/dev/null && echo "已开启 $IFACE rx-gro-list" || echo "$IFACE 不支持 rx-gro-list"
@@ -1,31 +1,22 @@
# ============================================================ # ============================================================
# RRPP 节点系统级网络优化(KVM / 完整虚拟机版,含 Azure 等) # RRPP 节点系统级网络优化(KVM / 完整虚拟机版)
# 部署位置:/etc/sysctl.d/99-zz-rrpp-network.conf # 部署位置:/etc/sysctl.d/99-zz-rrpp-network.conf
# 配套:systemd/rrpp-qdisc.service + scripts/rrpp-qdisc.sh(见 README §2.6) # 配套:systemd/rrpp-qdisc.service + scripts/rrpp-qdisc.sh(fq 队列 + UDP GRO)
# ------------------------------------------------------------ # 文件名 99-zz- 前缀保证最后生效;注意 /etc/sysctl.conf 会更晚加载(见 README §2.6)
# 文件名以 99-zz- 开头:sysctl 按文件名字典序加载、后者覆盖前者,
# 该命名保证本文件最后生效(避免被其它 99-*.conf 覆盖)。
#
# ⚠ 仍有一个坑:`sysctl --system` 会在所有 sysctl.d 之后**再次加载
# /etc/sysctl.conf**(实测某节点 2022 年的 /etc/sysctl.conf 把
# tcp_mtu_probing 覆盖回 0)。若目标机器上该文件含网络键,
# 必须同步注释掉冲突行,否则本文件不生效。
#
# 容器(LXC/OpenVZ)请改用 99-zz-rrpp-network.lxc.conf
# ============================================================ # ============================================================
# --- 拥塞控制与队列(BBR 需配 fq,否则易 bufferbloat)--- # --- 拥塞控制与队列 ---
net.ipv4.tcp_congestion_control = bbr net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq net.core.default_qdisc = fq
# --- PMTUD 黑洞缓解(跨境链路 TLS 握手稳定超时的常见元凶)--- # --- PMTUD 黑洞缓解 ---
net.ipv4.tcp_mtu_probing = 1 net.ipv4.tcp_mtu_probing = 1
# --- 握手 / 时延 --- # --- 握手 / 时延 ---
net.ipv4.tcp_fastopen = 3 net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_slow_start_after_idle = 0 net.ipv4.tcp_slow_start_after_idle = 0
# --- 连接生命周期(代理长连接 + 大量短连接)--- # --- 连接生命周期 ---
net.ipv4.tcp_tw_reuse = 2 net.ipv4.tcp_tw_reuse = 2
net.ipv4.tcp_fin_timeout = 15 net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300 net.ipv4.tcp_keepalive_time = 300
@@ -33,7 +24,7 @@ net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5 net.ipv4.tcp_keepalive_probes = 5
net.ipv4.ip_local_port_range = 10240 65000 net.ipv4.ip_local_port_range = 10240 65000
# --- 队列深度与缓冲(高并发 / 大 BDP)--- # --- 队列深度与缓冲(TCP)---
net.core.somaxconn = 32768 net.core.somaxconn = 32768
net.ipv4.tcp_max_syn_backlog = 32768 net.ipv4.tcp_max_syn_backlog = 32768
net.core.netdev_max_backlog = 32768 net.core.netdev_max_backlog = 32768
@@ -41,3 +32,7 @@ net.core.rmem_max = 33554432
net.core.wmem_max = 33554432 net.core.wmem_max = 33554432
net.ipv4.tcp_rmem = 4096 131072 33554432 net.ipv4.tcp_rmem = 4096 131072 33554432
net.ipv4.tcp_wmem = 4096 16384 33554432 net.ipv4.tcp_wmem = 4096 16384 33554432
# --- UDP(Hysteria2 / TUIC / UoT 的 socket 缓冲下限)---
net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192
@@ -1,37 +1,22 @@
# ============================================================ # ============================================================
# RRPP 节点系统级网络优化(LXC / OpenVZ 容器版) # RRPP 节点系统级网络优化(LXC / OpenVZ 容器版)
# 部署位置:/etc/sysctl.d/99-zz-rrpp-network.conf # 部署位置:/etc/sysctl.d/99-zz-rrpp-network.conf
# ------------------------------------------------------------ # 容器差异:net.core.rmem_max / wmem_max / default_qdisc / netdev_max_backlog
# 文件名以 99-zz- 开头:sysctl 按文件名字典序加载、后者覆盖前者, # 缺失或只读;eth0 为 noqueue,qdisc/网卡 offload 不可设(由宿主机控制)。
# 该命名保证本文件最后生效(避免被其它 99-*.conf 覆盖)。 # net.ipv4.udp_rmem_min / udp_wmem_min 在部分容器内只读,若报错可忽略。
#
# 容器差异(实测 2026-09):
# net.core.rmem_max / wmem_max → 不存在或只读(宿主机控制)
# net.core.default_qdisc → 不存在(sysctl 报 cannot stat)
# net.core.netdev_max_backlog → 缺失
# eth0 根 qdisc → noqueue,无法设置 fq
# /usr/lib/sysctl.d 的 kernel.pid_max、fs.protected_* → permission denied(正常)
# 故本文件只写容器内可写且有效的 netns 级项。
# ============================================================ # ============================================================
# --- 拥塞控制(qdisc 由宿主机控制,容器内无法设 fq)---
net.ipv4.tcp_congestion_control = bbr net.ipv4.tcp_congestion_control = bbr
# --- PMTUD 黑洞缓解(跨境链路 TLS 握手稳定超时的常见元凶)---
net.ipv4.tcp_mtu_probing = 1 net.ipv4.tcp_mtu_probing = 1
# --- 握手 / 时延 ---
net.ipv4.tcp_fastopen = 3 net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_slow_start_after_idle = 0 net.ipv4.tcp_slow_start_after_idle = 0
# --- 连接生命周期(代理长连接 + 大量短连接)---
net.ipv4.tcp_tw_reuse = 2 net.ipv4.tcp_tw_reuse = 2
net.ipv4.tcp_fin_timeout = 15 net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300 net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 30 net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5 net.ipv4.tcp_keepalive_probes = 5
net.ipv4.ip_local_port_range = 10240 65000 net.ipv4.ip_local_port_range = 10240 65000
# --- 队列深度(netns 级,容器内可写)---
net.core.somaxconn = 32768 net.core.somaxconn = 32768
net.ipv4.tcp_max_syn_backlog = 32768 net.ipv4.tcp_max_syn_backlog = 32768
net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192