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` 补齐;
脚本对容器(`noqueue`)会自动跳过。
**UDP 策略(2026-09 起)**:节点**不部署 UDP 传输**(Hysteria2 / TUIC / QUIC 等一律不用)。
客户端 UDP 需求统一走 **UoT v2**(见 §5.5):UDP 数据报封装进 TCP CONNECT 隧道,
经 nginx magic 地址转到本机 `127.0.0.1:15201` relay 解封装。
**UDP 策略(2026-09-20 修订)**:节点**已启用 UDP 传输**(sing-box 内建 **Hysteria2** 与 **TUIC v5** 入站,见 §6.4),
用于对抗跨境链路的丢包/高 RTT;**同时保留 UoT v2** 路径(见 §5.5)——客户端 TUN 模式的 UDP
仍可封装进 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(重复包、已废弃)、
`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 代理)
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 地址)
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('<代理用户名>:<代理密码>'))
B64=$(printf '<代理用户名>:<代理密码>' | base64 -w0)
curl -sk --proxy-insecure -x https://<节点域名>:<nginx端口> \