mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-19 10:40:44 +00:00
2.1.2:隧道稳定性加固(继续修「网站还是容易挂」)
2.1.1 修掉了 nettune 死锁之后,公网上到 200,但**过一阵又 530**。
这次抓到的是隧道自己:
cloudflared 的 precheck 输出(tunnel.log):
| UDP Connectivity region1.v2.argotunnel.com FAIL QUIC connection failed |
| TCP Connectivity region1.v2.argotunnel.com FAIL HTTP/2 connection is blocked or unreachable |
| Cloudflare API api.cloudflare.com:443 PASS API is reachable |
| ERROR: Allow outbound QUIC traffic on port 7844 or use HTTP2. |
也就是 **443 通、7844 不通**,而且是**间歇性**的(过几分钟自己又好了,
然后再次断)。Cloudflare 隧道的边缘连接走 7844(QUIC 走 UDP 7844、
HTTP/2 走 TCP 7844)。这条线路对它是间歇性阻断 —— 属于运营商那一侧,
设备改不了,但可以让 cloudflared 自己去适应。
== 两个改动 ==
1. **协议从写死改成 auto**
lanremote-tunnel --protocol quic -> --protocol auto
lanremote-tunnel-h2 --protocol http2 -> --protocol auto
原来两条实例各赌一个协议:那一刻 7844 的 UDP 和 TCP 都不通就一起死,
没有退路(实测连接数掉到 1/0、公网 530)。改成 auto 之后
cloudflared 自己在 QUIC / HTTP/2 之间挑当前能通的那条,
10 条连接全都有自适应能力。
2. **--retries 5 -> 1000000**
原来失败 5 次就退出、靠 systemd Restart=always 拉起来,
每次退出到重启之间网站都是断的。而这条线路的抖动是分钟级的 ——
实测隧道每 3~10 分钟就被重启一次(19:37 / 19:40 / 19:43 / 19:50 / 19:52),
公网跟着一起断。拉大之后抖动期间连接自己恢复,整条隧道不退出。
3. 顺手加日志轮转(tunnel.log 已经 2.98 MB,这台机器硬盘不大)。
== 实测 ==
改前:连接数 1/0,公网 530
改后:连接数 7+2(接近满配 10),公网连测 5 次全部 200
== 同步 ==
relay/deploy.sh 里的 MAIN_PROTO / ALT_PROTO 也改成 auto、
TUNNEL_BASE 的 --retries 也拉到 1000000,新机器装出来就是加固过的。
全量回归 46 个阶段全部通过。
This commit is contained in:
@@ -1,3 +1,35 @@
|
||||
## 2.1.2
|
||||
|
||||
- **隧道稳定性加固**(继续修「网站还是容易挂」)。查到隧道自己的诊断输出:
|
||||
|
||||
```
|
||||
| UDP Connectivity Cloudflare 边缘 FAIL 连不上 |
|
||||
| TCP Connectivity Cloudflare 边缘 FAIL 连不上或被挡住 |
|
||||
| Cloudflare API api.cloudflare.com:443 PASS 通的 |
|
||||
| ERROR: Allow outbound QUIC traffic on port 7844 or use HTTP2. |
|
||||
```
|
||||
|
||||
也就是说:**443 通,7844 不通**,而且是**一阵一阵的**
|
||||
(过几分钟自己又好了,然后再次断)。Cloudflare 隧道的边缘连接走 7844,
|
||||
这条线路对它是间歇性阻断 —— 这属于运营商那一侧,设备改不了。
|
||||
|
||||
**但可以让它自己去适应**:
|
||||
|
||||
- 两条隧道实例原来**各自写死一个协议**(一条只走 QUIC、一条只走 HTTP/2)。
|
||||
那一刻如果 7844 的 UDP 和 TCP 都不通,两条一起死,没有退路。
|
||||
现在都改成 **自动选择**,cloudflared 自己在 QUIC / HTTP/2 之间挑
|
||||
当前能通的那条。等于所有连接都有自适应能力,而不是
|
||||
"8 条赌 UDP、2 条赌 TCP"。
|
||||
|
||||
- 重试次数从 5 提到「一直重试」。原来失败 5 次就退出、靠系统重新拉起,
|
||||
每次退出到重启之间网站都是断的;而这条线路的抖动是分钟级的,
|
||||
5 次根本扛不过去(实测隧道每 3~10 分钟就被重启一次,公网跟着 530)。
|
||||
现在抖动期间连接自己恢复,整条隧道不退出。
|
||||
|
||||
**改完实测**:连接数 7+2(接近满配 10),公网连测 5 次全部 200。
|
||||
|
||||
- 顺手加了日志轮转(隧道日志已经涨到 3 MB,这台小机器硬盘不大)。
|
||||
|
||||
## 2.1.1
|
||||
|
||||
- **修一个会让网站整个挂掉的死锁**(这是「网站还是容易挂」的真因)。
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
2.1.2:隧道稳定性加固(继续修「网站还是容易挂」)
|
||||
|
||||
2.1.1 修掉了 nettune 死锁之后,公网上到 200,但**过一阵又 530**。
|
||||
这次抓到的是隧道自己:
|
||||
|
||||
cloudflared 的 precheck 输出(tunnel.log):
|
||||
|
||||
| UDP Connectivity region1.v2.argotunnel.com FAIL QUIC connection failed |
|
||||
| TCP Connectivity region1.v2.argotunnel.com FAIL HTTP/2 connection is blocked or unreachable |
|
||||
| Cloudflare API api.cloudflare.com:443 PASS API is reachable |
|
||||
| ERROR: Allow outbound QUIC traffic on port 7844 or use HTTP2. |
|
||||
|
||||
也就是 **443 通、7844 不通**,而且是**间歇性**的(过几分钟自己又好了,
|
||||
然后再次断)。Cloudflare 隧道的边缘连接走 7844(QUIC 走 UDP 7844、
|
||||
HTTP/2 走 TCP 7844)。这条线路对它是间歇性阻断 —— 属于运营商那一侧,
|
||||
设备改不了,但可以让 cloudflared 自己去适应。
|
||||
|
||||
== 两个改动 ==
|
||||
|
||||
1. **协议从写死改成 auto**
|
||||
lanremote-tunnel --protocol quic -> --protocol auto
|
||||
lanremote-tunnel-h2 --protocol http2 -> --protocol auto
|
||||
原来两条实例各赌一个协议:那一刻 7844 的 UDP 和 TCP 都不通就一起死,
|
||||
没有退路(实测连接数掉到 1/0、公网 530)。改成 auto 之后
|
||||
cloudflared 自己在 QUIC / HTTP/2 之间挑当前能通的那条,
|
||||
10 条连接全都有自适应能力。
|
||||
|
||||
2. **--retries 5 -> 1000000**
|
||||
原来失败 5 次就退出、靠 systemd Restart=always 拉起来,
|
||||
每次退出到重启之间网站都是断的。而这条线路的抖动是分钟级的 ——
|
||||
实测隧道每 3~10 分钟就被重启一次(19:37 / 19:40 / 19:43 / 19:50 / 19:52),
|
||||
公网跟着一起断。拉大之后抖动期间连接自己恢复,整条隧道不退出。
|
||||
|
||||
3. 顺手加日志轮转(tunnel.log 已经 2.98 MB,这台机器硬盘不大)。
|
||||
|
||||
== 实测 ==
|
||||
|
||||
改前:连接数 1/0,公网 530
|
||||
改后:连接数 7+2(接近满配 10),公网连测 5 次全部 200
|
||||
|
||||
== 同步 ==
|
||||
|
||||
relay/deploy.sh 里的 MAIN_PROTO / ALT_PROTO 也改成 auto、
|
||||
TUNNEL_BASE 的 --retries 也拉到 1000000,新机器装出来就是加固过的。
|
||||
|
||||
全量回归 46 个阶段全部通过。
|
||||
@@ -0,0 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
r'''查隧道为什么掉连接(公网 530,连接数 1/0)。
|
||||
|
||||
上一轮才刚修掉 nettune 死锁、把公网拉到 200;这次重启 nettune 之后
|
||||
又变成 530 了。要分清是:
|
||||
* nettune 又卡了(那个死锁没修干净?)
|
||||
* 还是隧道自己掉了(cloudflared 的问题)
|
||||
'''
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "_build"))
|
||||
from devssh import run # noqa: E402
|
||||
|
||||
REMOTE = r'''
|
||||
echo "════ 1. 服务状态 + 有没有卡住的 ════"
|
||||
for s in lanremote-relay lanremote-tunnel lanremote-tunnel-h2 lanremote-nettune; do
|
||||
printf ' %-24s %s\n' "$s" "$(systemctl is-active $s)"
|
||||
done
|
||||
echo " --- nettune 卡住吗 ---"
|
||||
systemctl show -p SubState -p MainPID -p ExecMainStartTimestamp lanremote-nettune 2>&1 | sed 's/^/ /'
|
||||
echo " --- 有没有卡住的 systemctl ---"
|
||||
ps -eo pid,etime,cmd 2>/dev/null | grep -E 'systemctl|net-tune' | grep -v grep | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════ 2. net-tune 的修复在设备上吗 ════"
|
||||
grep -c NETTUNE_SERVICE_CALL /root/lanremote-relay/net-tune.sh
|
||||
echo " unit 里有吗: $(grep -c NETTUNE_SERVICE_CALL /etc/systemd/system/lanremote-nettune.service)"
|
||||
|
||||
echo
|
||||
echo "════ 3. 隧道为什么连接数是 0 ════"
|
||||
journalctl -u lanremote-tunnel --no-pager -n 25 2>/dev/null | tail -25 | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════ 4. 隧道 unit 长什么样(重启策略 / 协议)════"
|
||||
systemctl cat lanremote-tunnel 2>/dev/null | grep -vE '^#' | head -25 | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════ 5. cloudflared 进程 ════"
|
||||
ps -eo pid,etime,rss,cmd 2>/dev/null | grep cloudflared | grep -v grep | sed 's/^/ /'
|
||||
'''
|
||||
|
||||
|
||||
def main() -> int:
|
||||
out = run(REMOTE, timeout=300)
|
||||
text = out[1] if isinstance(out, tuple) else str(out)
|
||||
print(text)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
r'''看隧道为什么反复掉(公网 530 的真因)。
|
||||
|
||||
已知:
|
||||
nettune 死锁已修(SubState=exited,不再卡)
|
||||
但隧道每 3~10 分钟被重启一次(部分是我加的预案在救、部分是它自己掉)
|
||||
公网 530
|
||||
|
||||
要查的是 tunnel.log 里 cloudflared 到底在报什么。
|
||||
'''
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "_build"))
|
||||
from devssh import run # noqa: E402
|
||||
|
||||
REMOTE = r'''
|
||||
LOG=/root/lanremote-relay/tunnel.log
|
||||
H2LOG=/root/lanremote-relay/tunnel-h2.log
|
||||
|
||||
echo "════ 1. tunnel.log 里的错误行(最近 40 条)════"
|
||||
grep -iE 'error|fail|warn|timeout|retry|refused|EOF|unregister|connection' "$LOG" 2>/dev/null | tail -40 | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════ 2. tunnel.log 最后 25 行(原样)════"
|
||||
tail -25 "$LOG" 2>/dev/null | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════ 3. h2 那份的日志 ════"
|
||||
tail -15 "$H2LOG" 2>/dev/null | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════ 4. 两份日志多大(写爆了会拖慢小机器)════"
|
||||
ls -la "$LOG" "$H2LOG" 2>/dev/null | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════ 5. cloudflared 版本 + 配置 ════"
|
||||
/usr/local/bin/cloudflared --version 2>&1 | sed 's/^/ /'
|
||||
echo " --- config.yml ---"
|
||||
cat /root/.cloudflared/config.yml 2>/dev/null | sed 's/^/ /'
|
||||
|
||||
echo
|
||||
echo "════ 6. 现在两条隧道的连接数 ════"
|
||||
for p in 20241 20242; do
|
||||
n=$(curl -s --max-time 5 "http://127.0.0.1:$p/metrics" 2>/dev/null | grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}' | head -1)
|
||||
echo " $p -> ${n:-拿不到}"
|
||||
done
|
||||
|
||||
echo
|
||||
echo "════ 7. 公网现在通吗 ════"
|
||||
echo " $(curl -s -o /dev/null -w '%{http_code}' --max-time 15 https://relay.xxmxxs.top/v1/health)"
|
||||
'''
|
||||
|
||||
|
||||
def main() -> int:
|
||||
out = run(REMOTE, timeout=300)
|
||||
text = out[1] if isinstance(out, tuple) else str(out)
|
||||
print(text)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,162 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
r'''增强隧道稳定性 —— 「网站还是容易挂」的真因修法。
|
||||
|
||||
== 查到什么 ==
|
||||
|
||||
cloudflared 自己的 precheck 输出(tunnel.log):
|
||||
|
||||
| UDP Connectivity region1.v2.argotunnel.com FAIL QUIC connection failed |
|
||||
| UDP Connectivity region2.v2.argotunnel.com FAIL QUIC connection failed |
|
||||
| TCP Connectivity region1.v2.argotunnel.com FAIL HTTP/2 connection is blocked or unreachable |
|
||||
| TCP Connectivity region2.v2.argotunnel.com FAIL HTTP/2 connection is blocked or unreachable |
|
||||
| Cloudflare API api.cloudflare.com:443 PASS API is reachable |
|
||||
| ERROR: Allow outbound QUIC traffic on port 7844 or use HTTP2. |
|
||||
|
||||
也就是:**443 通,7844 不通**,而且是**间歇性**的
|
||||
(日志后面又出现 Registered tunnel connection,过一阵又掉)。
|
||||
|
||||
Cloudflare 隧道的边缘连接走 7844(QUIC 走 UDP 7844、HTTP/2 走 TCP 7844)。
|
||||
这条线路对 7844 是间歇性阻断的 —— 这不是设备能修的,
|
||||
但**可以让 cloudflared 自己去适应**。
|
||||
|
||||
== 现在的配置有两个问题 ==
|
||||
|
||||
1. **两条实例各写死一个协议**
|
||||
lanremote-tunnel --protocol quic (只走 UDP 7844)
|
||||
lanremote-tunnel-h2 --protocol http2 (只走 TCP 7844)
|
||||
如果那一刻 7844 的 UDP 和 TCP 都不通,两条一起死 —— 没有退路。
|
||||
实测就是这样:连接数掉到 1/0,公网 530。
|
||||
|
||||
2. **--retries 5**
|
||||
cloudflared 重试 5 次就**退出**,靠 systemd Restart=always 拉起来。
|
||||
每次退出/重启期间网站都是断的。而这个线路的抖动是分钟级的,
|
||||
5 次远远不够扛过去。
|
||||
|
||||
== 改法 ==
|
||||
|
||||
1. `--protocol auto` —— 让 cloudflared **自己**在 QUIC 和 HTTP/2 之间选,
|
||||
哪条通走哪条。两条实例都改成 auto,等于 10 条连接全都能自适应。
|
||||
(而不是现在这样"8 条赌 UDP、2 条赌 TCP")
|
||||
|
||||
2. `--retries` 提到很大(相当于"一直重试,别退出")——
|
||||
抖动期间连接会自己恢复,不会整条隧道退出让网站断掉。
|
||||
|
||||
3. 顺手加日志轮转:tunnel.log 已经涨到 2.98 MB,
|
||||
这台机器只有 460MB 内存 + 小硬盘,无限增长不合适。
|
||||
'''
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "_build"))
|
||||
from devssh import run # noqa: E402
|
||||
|
||||
|
||||
def patch_unit(name: str, proto: str) -> str:
|
||||
"""读设备上现有的 unit,改协议和重试次数。
|
||||
|
||||
用 sed 现场改而不是整份重写 —— 现有 unit 里还有
|
||||
metrics 端口、ha-connections、MemoryMax 这些实测调出来的参数,
|
||||
整份重写容易漏掉。
|
||||
"""
|
||||
cmds = [
|
||||
# 协议
|
||||
"sed -i 's/--protocol [a-z0-9]*/--protocol %s/' %s" % (proto, name),
|
||||
# 重试次数:改成很大(一直重试)
|
||||
"sed -i 's/--retries [0-9]*/--retries 1000000/' %s" % name,
|
||||
]
|
||||
return " && ".join(cmds)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
print("=" * 62)
|
||||
print(" 隧道稳定性:协议改 auto + 加大重试 + 日志轮转")
|
||||
print("=" * 62)
|
||||
|
||||
UNIT_DIR = "/etc/systemd/system"
|
||||
|
||||
print()
|
||||
print(" ── 1. 两条隧道都改成 --protocol auto ──")
|
||||
out = run(
|
||||
"cd %s && "
|
||||
"sed -i 's/--protocol [a-z0-9]*/--protocol auto/' "
|
||||
"lanremote-tunnel.service lanremote-tunnel-h2.service && "
|
||||
"echo ' tunnel:'; grep -o -- '--protocol [a-z0-9]*' "
|
||||
"lanremote-tunnel.service; "
|
||||
"echo ' h2:'; grep -o -- '--protocol [a-z0-9]*' "
|
||||
"lanremote-tunnel-h2.service; "
|
||||
# 重试次数
|
||||
"sed -i 's/--retries [0-9]*/--retries 1000000/' "
|
||||
"lanremote-tunnel.service lanremote-tunnel-h2.service && "
|
||||
"echo ' 重试:'; grep -o -- '--retries [0-9]*' "
|
||||
"lanremote-tunnel.service lanremote-tunnel-h2.service"
|
||||
% UNIT_DIR, timeout=120)
|
||||
for ln in out[1].strip().splitlines():
|
||||
print(" " + ln)
|
||||
|
||||
print()
|
||||
print(" ── 2. 日志轮转(tunnel.log 已经 2.98 MB)──")
|
||||
out = run(
|
||||
"cat > /etc/logrotate.d/lanremote <<'EOF'\n"
|
||||
"/root/lanremote-relay/*.log {\n"
|
||||
" size 5M\n"
|
||||
" rotate 2\n"
|
||||
" compress\n"
|
||||
" missingok\n"
|
||||
" notifempty\n"
|
||||
" copytruncate\n"
|
||||
"}\n"
|
||||
"EOF\n"
|
||||
"echo ' logrotate 配置已写'; "
|
||||
"logrotate --debug /etc/logrotate.d/lanremote 2>&1 | tail -3",
|
||||
timeout=120)
|
||||
for ln in out[1].strip().splitlines():
|
||||
print(" " + ln)
|
||||
|
||||
print()
|
||||
print(" ── 3. 重启两条隧道让新参数生效 ──")
|
||||
out = run(
|
||||
"systemctl daemon-reload && "
|
||||
"systemctl restart lanremote-tunnel lanremote-tunnel-h2 && "
|
||||
"echo ' 等 40 秒让连接建立…' && sleep 40 && "
|
||||
"echo \" tunnel: $(systemctl is-active lanremote-tunnel)\"; "
|
||||
"echo \" h2: $(systemctl is-active lanremote-tunnel-h2)\"",
|
||||
timeout=300)
|
||||
for ln in out[1].strip().splitlines():
|
||||
print(" " + ln)
|
||||
|
||||
print()
|
||||
print(" ── 4. 连接数 ──")
|
||||
out = run(
|
||||
"for p in 20241 20242; do "
|
||||
"n=$(curl -s --max-time 5 http://127.0.0.1:$p/metrics 2>/dev/null "
|
||||
"| grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}' "
|
||||
"| head -1); "
|
||||
"echo \" $p -> ${n:-拿不到}\"; done; "
|
||||
"echo ' --- 用的什么协议 ---'; "
|
||||
"grep -o 'protocol=[a-z0-9]*' /root/lanremote-relay/tunnel.log 2>/dev/null "
|
||||
"| tail -6 | sort | uniq -c | sed 's/^/ /'", timeout=120)
|
||||
for ln in out[1].strip().splitlines():
|
||||
print(" " + ln)
|
||||
|
||||
print()
|
||||
print(" ── 5. 公网(连测 5 次看稳不稳)──")
|
||||
out = run(
|
||||
"for i in 1 2 3 4 5; do "
|
||||
"c=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "
|
||||
"https://relay.xxmxxs.top/v1/health); "
|
||||
"echo \" 第 $i 次: $c\"; sleep 3; done", timeout=200)
|
||||
for ln in out[1].strip().splitlines():
|
||||
print(" " + ln)
|
||||
|
||||
print()
|
||||
print(" 说明:3844/7844 那条线路封不封是运营商的事,设备改不了。")
|
||||
print(" 但 --protocol auto 让 cloudflared 自己绕,")
|
||||
print(" --retries 拉大让它别退出 —— 抖动期间能自己恢复。")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -17,7 +17,7 @@ import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||||
VERSION = "2.1.1"
|
||||
VERSION = "2.1.2"
|
||||
NAME = f"ykxmz-{VERSION}"
|
||||
|
||||
AGENT_SRC = ROOT / "dist_exe" / "ykxmz"
|
||||
|
||||
Reference in New Issue
Block a user