阶段1+2:恢复 HTTP/2 加速 + 重做官网

阶段1 网络加速
- 发现隧道在跑 QUIC(ExecStart 丢了 --protocol http2),
  实测 QUIC 可用率 48% vs HTTP/2 80%+,是重大性能回退。
  恢复后公网延迟从 4141ms 降到 690ms(快 6 倍),可用率 92%。
- 优选 IP 结论:无效。hosts 覆盖确实生效了(日志里连的就是指定 IP),
  但落点仍是 lax —— 运营商把所有 Cloudflare anycast 都路由到美西。
  已清掉这段无效配置。
- BBR 不可用:设备是自定义内核 6.4.0-rc4-jsbsbxjxh66,
  没编 tcp_bbr 模块也没配置项。改用 cubic + 调优:
  TCP 缓冲 4MB、tcp_fastopen=3、tcp_slow_start_after_idle=0
  (长轮询场景关键)、tcp_tw_reuse=1。

阶段2 官网重做
- 拆出独立模块 relay/landing.py(relay.py 已两千多行,
  再塞 HTML 没法看)
- 信息结构参考成熟产品站:吸顶导航 / Hero / 九宫格功能 /
  三步上手 / 下载 / FAQ / 页脚
- 保持白色简洁:底白、浅灰面板、细边框、大量留白
- logo 用内联 SVG(ICO 放 img 里实测是破图)
- 管理入口从官网移除(管理不对外开放)

过程中被自己的测试抓到两个 bug:
- 模块叫 site.py 会和 Python 标准库重名,import site 拿到的是标准库
- _logo() 里把 % 格式化和字符串拼接混用,直接抛 TypeError
This commit is contained in:
xmz7891
2026-10-06 23:53:19 +08:00
parent 9b1edbf378
commit 566d9e384f
214 changed files with 2879 additions and 1384 deletions
+111
View File
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
r'''在设备上测 Cloudflare 隧道边缘 IP 的 TCP 握手延迟,挑优选 IP。
为什么要这么干:
cloudflared 连 region1.v2.argotunnel.com,这个域名由 GeoDNS 决定 ——
国内 4G 常被解析到美西(实测 lax13),单程 200ms+,
往返加丢包重传能到 4 秒(用户实测 4141ms)。
Cloudflare 是 anycast,同一批 IP 从不同网络过去落点不同。
做法:测各候选 IP 的 7844(隧道端口)握手延迟,
把最快的写进 /etc/hosts 覆盖 GeoDNS。
⚠ 关键教训:
7844 **只对 Cloudflare 的隧道专用段开放**,不是所有 anycast IP 都行。
专用段是 198.41.192.0/24 和 198.41.200.0/24(实测 198.41.192.107 通)。
我第一次拿 104.16.x.x 测,56 个全不通,就是选错段了。
'''
from __future__ import annotations
import socket
import sys
import time
PORT = 7844 # cloudflared 的 HTTP/2 隧道端口
# 已知能用的几个放前面:先确认能通,再放大范围扫
KNOWN = [
"198.41.192.107", "198.41.192.7", "198.41.192.167",
"198.41.200.13", "198.41.200.33", "198.41.200.53", "198.41.200.63",
]
def build_candidates() -> list[str]:
ips = list(KNOWN)
for third in range(1, 255, 3):
ips.append("198.41.192." + str(third))
for third in range(1, 255, 3):
ips.append("198.41.200." + str(third))
seen = set()
out = []
for ip in ips:
if ip not in seen:
seen.add(ip)
out.append(ip)
return out
def probe(ip: str, timeout: float = 2.5):
"""返回 TCP 握手耗时(毫秒),不通返回 None。"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
start = time.perf_counter()
try:
sock.connect((ip, PORT))
return (time.perf_counter() - start) * 1000
except OSError:
return None
finally:
sock.close()
def main() -> int:
candidates = build_candidates()
print(" 候选 %d 个(Cloudflare 隧道专用段)" % len(candidates))
print(" 测 %d 端口,每个 2 次取最快" % PORT)
print()
results = []
reachable = 0
for index, ip in enumerate(candidates, 1):
best = None
for _ in range(2):
ms = probe(ip)
if ms is not None and (best is None or ms < best):
best = ms
if best is not None:
reachable += 1
results.append((best, ip))
if index % 40 == 0:
print(" 已测 %d/%d,通了 %d 个" % (index, len(candidates), reachable))
print()
if not results:
print(" 一个都不通")
return 1
results.sort()
print(" 通了 %d 个,最快的 15 个:" % reachable)
for ms, ip in results[:15]:
print(" %7.1f ms %s" % (ms, ip))
print()
print(" 默认 GeoDNS 解析:")
for host in ("region1.v2.argotunnel.com", "region2.v2.argotunnel.com"):
try:
infos = socket.getaddrinfo(host, PORT)
v4 = sorted({i[4][0] for i in infos if i[0] == socket.AF_INET})
print(" %s: %s" % (host, v4 or "(只有 IPv6)"))
except OSError as exc:
print(" %s: 解析失败 %s" % (host, exc))
with open("/root/cf_best.txt", "w") as fh:
for ms, ip in results[:5]:
fh.write("%s %.0f\n" % (ip, ms))
print()
print(" 最快 5 个 -> /root/cf_best.txt")
return 0
if __name__ == "__main__":
sys.exit(main())