mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 17:10:43 +00:00
用户要求:服务器端文件里放一个 .sh,双击就能检查 cloudflared 装没装、
自动部署、配好公网,以后全自动。
== 新增 ==
relay/deploy.sh 一键部署主脚本,7 步全自动:
环境检查 -> 装 cloudflared -> 部署程序 -> 网络调优
-> 写 4 个 systemd 服务 -> 配隧道 -> 启动自检打公网地址
relay/deploy-tune.sh 网络调优,可单独重跑:
keepalive 30/10/3 + 路径 MTU 探测 + MSS 1360
+ 接口 MTU 1400 + mask networkd-wait-online
每一项都写明了实测依据
用法:
bash deploy.sh 复用已有凭据,全自动
TUNNEL_TOKEN=eyJh... bash deploy.sh Token 模式
bash deploy.sh --hostname relay.你的域名 换域名
bash deploy.sh --skip-tunnel 只装中转
bash deploy.sh --help 全部参数
重跑 = 升级;已有数据/配对码/管理密码/凭据/手改过的 config.yml 都不动。
== 自动化到什么程度 ==
* cloudflared 不在就自动下载装上(并校验能执行)
* 隧道支持两种模式:已有凭据文件、或 TUNNEL_TOKEN
* **不传 --hostname 且没有 Token 时明确提示要填**,不会静默用一个写死的值
(用户明确说过:这个中转站是他自己用的,不对外开放,
绝不能把私人域名烧成默认值)
* deploy-tune.sh 的 MTU 取 1400:路径 MTU 实测 1472,
而 MSS 钳制只管 TCP、QUIC 走 UDP 完全不受保护;
接口 MTU 降到 1400 后 QUIC 建齐 10 条连接从 28 秒缩到 12 秒
== 顺带修掉两个真 bug ==
1. write_tunnel_unit 写的文件名漏了 .service 后缀 ——
文件写下去了但 systemd 完全看不见,enable 还会安静地失败。
2. 发布包一直缺 site_shots/(老 bug):
package_remote.py 用 iterdir() + is_file() 收文件,目录进不去。
新机器装完官网截图全是 404。只有从 zip 解压真跑一遍才暴露。
同时把 deploy.sh 里 site_shots 的检查降级成警告(缺截图不该让部署失败)。
另外给 deploy-tune.sh 清旧 MSS 规则的循环加了 10 次上限 ——
原写法在 -D 报成功但规则仍在时会死循环把整个部署卡死。
== 验证 ==
* _build/test_deploy_sh.sh 沙箱 65 项,全通过
* _build/test_zip_deploy.sh 从发布 zip 解压再跑,30 项,全通过
* _build/test_deploy_real.sh **真机 Debian 上实测**(新增):
zip 解出 17 个文件 -> 语法/LF/无 BOM 通过
--help 退出码 0 且无副作用、未知参数退出码 2
沙箱安装成功、幂等重跑哨兵不被冲
现有三个中转服务全程 active,自检 200
169 lines
8.8 KiB
Bash
169 lines
8.8 KiB
Bash
#!/bin/bash
|
||
# 网络调优:修路径 MTU 问题 + 给 QUIC 隧道留出安全包长。
|
||
#
|
||
# 这个脚本是 **MSS / 接口 MTU / 路径 MTU 探测** 的唯一出处。
|
||
# deploy-tune.sh 会调它;不要在别处再设一遍 ——
|
||
# "到底哪个值生效" 一旦有两处来源就会变得很难查。
|
||
#
|
||
# ════════════════════════════════════════════════════════════════
|
||
# 证据链
|
||
# ════════════════════════════════════════════════════════════════
|
||
# 现象:新建 TLS 连接约 30% 失败,但连接一旦建立就接近 100% 成功
|
||
# -> 典型的大包被丢、小包能过
|
||
#
|
||
# ping 实测(到 1.1.1.1,-M do 禁止分片):
|
||
# 包 1448 通 包 1488 丢 包 1500 全丢
|
||
# 接口 MTU 写着 1500,但实际路径扛不住。
|
||
# TLS 握手要发大证书包 -> 被丢 -> 握手失败。
|
||
#
|
||
# ════════════════════════════════════════════════════════════════
|
||
# 实测效果(同一台设备,各 24 次)
|
||
# ════════════════════════════════════════════════════════════════
|
||
# 不夹 MSS(1500) 87%
|
||
# MSS 1300 100%
|
||
# MSS 1360 100% <- 采用(和 MTU 1400 配套)
|
||
# MSS 1400 100%
|
||
# MSS 1440 100%
|
||
#
|
||
# ════════════════════════════════════════════════════════════════
|
||
# 为什么接口 MTU 也要压到 1400(早期结论是错的,这里更正)
|
||
# ════════════════════════════════════════════════════════════════
|
||
# 早先这里写的是「不要改接口 MTU,实测降到 1400 反而掉到 50%」。
|
||
# 那个结论只考虑了 TCP,**漏掉了 QUIC**:
|
||
#
|
||
# * MSS 钳制走的是 iptables 的 TCPMSS 目标,**只对 TCP 生效**;
|
||
# * 隧道用 QUIC 时跑在 UDP 上,整套 TCPMSS 规则对它毫无作用。
|
||
#
|
||
# QUIC 的包一旦超过路径 MTU 就会被中间设备丢掉,而 UDP 丢包
|
||
# 不会回 ICMP,客户端只能干等到握手超时 —— cloudflared 日志里就是
|
||
# "failed to dial to edge with quic: timeout: no recent network activity"
|
||
#
|
||
# 把 wlan0 MTU 从 1500 降到 1400 之后(实测):
|
||
# 建齐 6 条 QUIC 连接 28 秒 -> 13 秒
|
||
# 建齐 10 条 QUIC 连接 28 秒 -> 12 秒
|
||
# 建连期间 dial 失败 2 次 -> 1 次
|
||
#
|
||
# 【重要】MTU 和 MSS 必须配套:
|
||
# MTU 1400 => TCP 段最大 1360(1400 - 20 IP头 - 20 TCP头)
|
||
# 如果 MTU 压到 1400 却还把 MSS 设成 1400,
|
||
# TCP 段(1440) 就超过接口 MTU(1400),包在本地就被分片,等于白改。
|
||
# 两个值在本脚本里一起设,改一个必须改另一个。
|
||
set -u
|
||
|
||
MSS_VALUE=${MSS_VALUE:-1360}
|
||
MTU_VALUE=${MTU_VALUE:-1400}
|
||
|
||
# ────────────────────────────────────────────────────────────────
|
||
# 找对外的那张网卡
|
||
# ────────────────────────────────────────────────────────────────
|
||
# 以前这里写死 wlan0。写死的问题是换机器(或者用 usb0 上网)就错了,
|
||
# 而 MTU 设错网卡是没有任何提示的 —— 改了等于没改。
|
||
IFACE=${IFACE:-}
|
||
if [ -z "$IFACE" ] && command -v ip >/dev/null 2>&1; then
|
||
IFACE=$(ip -4 route show default 2>/dev/null \
|
||
| awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' \
|
||
| head -1)
|
||
fi
|
||
if [ -z "$IFACE" ]; then
|
||
for cand in /sys/class/net/*; do
|
||
name=$(basename "$cand")
|
||
case "$name" in lo|pan0|docker*|veth*|br-*) continue ;; esac
|
||
[ -r "$cand/operstate" ] || continue
|
||
[ "$(cat "$cand/operstate" 2>/dev/null)" = "up" ] || continue
|
||
IFACE="$name"
|
||
break
|
||
done
|
||
fi
|
||
[ -z "$IFACE" ] && IFACE=wlan0
|
||
|
||
echo " 1) 打开路径 MTU 探测"
|
||
if [ -w /proc/sys/net/ipv4/tcp_mtu_probing ]; then
|
||
sysctl -w net.ipv4.tcp_mtu_probing=1 >/dev/null
|
||
echo " tcp_mtu_probing = $(cat /proc/sys/net/ipv4/tcp_mtu_probing)"
|
||
else
|
||
echo " [跳过] 读不到 /proc(不是 Linux 环境)"
|
||
fi
|
||
|
||
echo " 2) 夹 MSS 到 $MSS_VALUE(只限制 TCP 段,不改链路层)"
|
||
if command -v iptables >/dev/null 2>&1; then
|
||
for chain in OUTPUT POSTROUTING; do
|
||
# 先清掉所有旧值,避免重启后越积越多。
|
||
# ⚠ 这个 while 必须有次数上限:
|
||
# 正常情况下 -D 删掉之后 -C 就返回非 0,循环自然结束。
|
||
# 但如果哪天 -D 报成功而规则还在(被包了一层、或 iptables 出异常),
|
||
# 原写法就是死循环,把整个部署卡死。
|
||
# 实测踩过:桩命令一律返回 0,脚本真的转不出来了。
|
||
for old in 1300 1360 1400 1440 1460; do
|
||
guard=0
|
||
while iptables -t mangle -C "$chain" -p tcp --tcp-flags SYN,RST SYN \
|
||
-j TCPMSS --set-mss "$old" 2>/dev/null; do
|
||
guard=$((guard + 1))
|
||
if [ "$guard" -gt 10 ]; then
|
||
echo " ⚠ 清理旧 MSS 规则($old) 超过 10 次仍报存在,停手"
|
||
break
|
||
fi
|
||
iptables -t mangle -D "$chain" -p tcp --tcp-flags SYN,RST SYN \
|
||
-j TCPMSS --set-mss "$old" 2>/dev/null || break
|
||
done
|
||
done
|
||
iptables -t mangle -A "$chain" -p tcp --tcp-flags SYN,RST SYN \
|
||
-j TCPMSS --set-mss "$MSS_VALUE" 2>/dev/null
|
||
done
|
||
iptables -t mangle -L -n 2>/dev/null | grep -i mss | sed 's/^/ /'
|
||
else
|
||
echo " [跳过] 没有 iptables"
|
||
fi
|
||
|
||
echo " 3) 接口 MTU -> $MTU_VALUE(这一条是给 QUIC 用的,见文件头说明)"
|
||
if command -v ip >/dev/null 2>&1; then
|
||
CUR=$(cat "/sys/class/net/$IFACE/mtu" 2>/dev/null || echo "?")
|
||
if [ "$CUR" = "$MTU_VALUE" ]; then
|
||
echo " $IFACE 已经是 $MTU_VALUE,不用改"
|
||
elif ip link set dev "$IFACE" mtu "$MTU_VALUE" 2>/dev/null; then
|
||
echo " $IFACE 的 MTU: $CUR -> $(cat "/sys/class/net/$IFACE/mtu" 2>/dev/null)"
|
||
else
|
||
echo " ⚠ 改 $IFACE 的 MTU 失败(权限或网卡不支持),继续"
|
||
fi
|
||
else
|
||
echo " [跳过] 没有 ip 命令"
|
||
fi
|
||
|
||
# 持久化:wlan0 归 NetworkManager 管,光用 ip 改重启就丢。
|
||
# 写进 NM 自己的连接配置,比塞 rc.local 干净。
|
||
if command -v nmcli >/dev/null 2>&1; then
|
||
CONN=$(nmcli -t -f NAME,DEVICE connection show --active 2>/dev/null \
|
||
| awk -F: -v dev="$IFACE" '$2==dev {print $1; exit}')
|
||
if [ -n "$CONN" ]; then
|
||
nmcli connection modify "$CONN" 802-11-wireless.mtu "$MTU_VALUE" \
|
||
2>/dev/null \
|
||
|| nmcli connection modify "$CONN" ethernet.mtu "$MTU_VALUE" \
|
||
2>/dev/null || true
|
||
echo " 已写进 NetworkManager 连接「$CONN」(重启后仍然生效)"
|
||
fi
|
||
fi
|
||
|
||
# ════════════════════════════════════════════════════════════════
|
||
# 4) 关键:让已经在跑的隧道重建连接
|
||
# ════════════════════════════════════════════════════════════════
|
||
# MSS 和 MTU 只对**新建连接**生效(MSS 改的是 SYN 包里的选项,
|
||
# MTU 影响的是新建的 socket)。隧道如果建在规则生效之前,
|
||
# 它那条连接还带着旧参数 ——
|
||
# 实测:隧道 17:01 建、规则 17:22 生效,可用率一直卡在 76%;
|
||
# 重启隧道之后立刻回到 100%。
|
||
#
|
||
# 开机时不会走到这一步(nettune 服务 Before=lanremote-tunnel.service,
|
||
# 规则先于隧道生效);但**手动重跑本脚本**时必须重建,
|
||
# 否则改了等于没改。
|
||
echo " 4) 让已经建立的隧道用上新参数"
|
||
RESTARTED=0
|
||
for svc in lanremote-tunnel lanremote-tunnel-h2; do
|
||
if command -v systemctl >/dev/null 2>&1 \
|
||
&& systemctl is-active --quiet "$svc" 2>/dev/null; then
|
||
echo " $svc 正在跑,重启它让新参数生效"
|
||
systemctl restart "$svc" >/dev/null 2>&1 && RESTARTED=1
|
||
fi
|
||
done
|
||
[ "$RESTARTED" = "0" ] && echo " 没有正在跑的隧道,跳过"
|
||
|
||
echo " 网络调优已应用(MSS=$MSS_VALUE, MTU=$MTU_VALUE, 网卡=$IFACE)"
|