mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-10-15 12:14:37 +00:00
docs: 补充内部机制说明与虚拟 frps 复现脚本
与本次 leader 修复无关,是工作区里此前遗留未提交的两个文件,误被 git add -A 卷进上一个提交,此处独立成提交。docs/how-it-works.md 记录了 DB 是唯一真源、 集群只复制环状态不复制配置、forward owner 归属等实测结论;配 scripts/probe-with-virtual-frps.sh 可在隔离环境复现全部结论,不触碰生产。
This commit is contained in:
137
scripts/probe-with-virtual-frps.sh
Executable file
137
scripts/probe-with-virtual-frps.sh
Executable file
@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env bash
|
||||
# 用隔离的虚拟 frps 探测 webui4frpc 行为。
|
||||
#
|
||||
# 全部端口与现网隔离(现网:7000/4434/7500/18082),不修改任何生产配置。
|
||||
# 用法:scripts/probe-with-virtual-frps.sh
|
||||
set -euo pipefail
|
||||
|
||||
LAB="${LAB:-/tmp/frplab}"
|
||||
FRP_VER="${FRP_VER:-0.61.1}"
|
||||
FRP_TGZ="frp_${FRP_VER}_linux_amd64"
|
||||
UI_ADDR="${UI_ADDR:-127.0.0.1:17500}"
|
||||
UI_USER="${UI_USER:-labadmin}"
|
||||
UI_PASS="${UI_PASS:-labpass123}"
|
||||
LAB_TOKEN="${LAB_TOKEN:-lab-token-$(date +%Y%m%d)}"
|
||||
|
||||
# 现网 frpc 二进制(唯一允许从生产读取的东西,只读)
|
||||
SRC_FRPC="${SRC_FRPC:-/opt/webui4frpc/data/bin/frpc-${FRP_VER}/frpc}"
|
||||
BACKEND_PORT=17090
|
||||
TCP_PORT=17091
|
||||
UI_FORWARD_PORT=17092
|
||||
|
||||
cleanup() {
|
||||
echo "==> 清理"
|
||||
pkill -f "webui4frpc -addr ${UI_ADDR}" 2>/dev/null || true
|
||||
pkill -f "frplab/.*frpc" 2>/dev/null || true
|
||||
[[ -n "${FRPS_PID:-}" ]] && kill "${FRPS_PID}" 2>/dev/null || true
|
||||
[[ -n "${BACKEND_PID:-}" ]] && kill "${BACKEND_PID}" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
mkdir -p "${LAB}"/{frps,probe,logs,ui/data}
|
||||
|
||||
# ---------- 1. frps(虚拟服务端) ----------
|
||||
if [[ ! -x "${LAB}/frpsd" ]]; then
|
||||
echo "==> 下载 frps ${FRP_VER}"
|
||||
curl -sL -o "${LAB}/frps-bin" \
|
||||
"https://github.com/fatedier/frp/releases/download/v${FRP_VER}/${FRP_TGZ}.tar.gz"
|
||||
tar xzf "${LAB}/frps-bin" -C "${LAB}"
|
||||
cp "${LAB}/${FRP_TGZ}/frps" "${LAB}/frpsd"
|
||||
chmod +x "${LAB}/frpsd"
|
||||
fi
|
||||
|
||||
cat > "${LAB}/frps/frps.toml" <<EOF
|
||||
bindPort = 17000
|
||||
vhostHTTPPort = 17080
|
||||
vhostHTTPsPort = 17443
|
||||
auth.token = "${LAB_TOKEN}"
|
||||
log.to = "${LAB}/logs/frps.log"
|
||||
log.level = "debug"
|
||||
EOF
|
||||
|
||||
echo "==> 启动虚拟 frps (17000/17080/17443)"
|
||||
"${LAB}/frpsd" -c "${LAB}/frps/frps.toml" > "${LAB}/logs/frps-stdout.log" 2>&1 &
|
||||
FRPS_PID=$!
|
||||
sleep 3
|
||||
ss -ltn | grep -E ':17000|:17443' || { echo "frps 未监听"; exit 1; }
|
||||
|
||||
# ---------- 2. 后端服务 ----------
|
||||
echo "==> 启动后端 http://127.0.0.1:${BACKEND_PORT}"
|
||||
( cd "${LAB}" && python3 -m http.server "${BACKEND_PORT}" --bind 127.0.0.1 > logs/backend.log 2>&1 & )
|
||||
BACKEND_PID=$!
|
||||
sleep 1
|
||||
|
||||
# ---------- 3. 裸 frpc 验证 frp 协议本身 ----------
|
||||
cat > "${LAB}/probe/frpc-probe.json" <<EOF
|
||||
{
|
||||
"serverAddr": "127.0.0.1",
|
||||
"serverPort": 17000,
|
||||
"loginFailExit": false,
|
||||
"auth": {"method": "token", "token": "${LAB_TOKEN}"},
|
||||
"proxies": [
|
||||
{"name":"lab-tcp","type":"tcp","localIP":"127.0.0.1","localPort":${BACKEND_PORT},"remotePort":${TCP_PORT}}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
cp "${SRC_FRPC}" "${LAB}/frpc" && chmod +x "${LAB}/frpc"
|
||||
echo "==> 裸 frpc 连接(验证 frp 协议通路)"
|
||||
"${LAB}/frpc" -c "${LAB}/probe/frpc-probe.json" > "${LAB}/logs/frpc.log" 2>&1 &
|
||||
sleep 4
|
||||
grep -q 'login to server success' "${LAB}/logs/frpc.log" \
|
||||
&& echo " frpc 登录成功" || { echo " frpc 登录失败"; tail -5 "${LAB}/logs/frpc.log"; }
|
||||
printf " tcp ${TCP_PORT} -> "; curl -s -o /dev/null -w "%{http_code}\n" "http://127.0.0.1:${TCP_PORT}/"
|
||||
pkill -f 'frplab/frpc' 2>/dev/null || true
|
||||
|
||||
# ---------- 4. webui4frpc 接管 ----------
|
||||
echo "==> 启动 webui4frpc ${UI_ADDR}(独立 workdir)"
|
||||
mkdir -p "${LAB}/ui/data/bin/frpc-${FRP_VER}"
|
||||
cp "${SRC_FRPC}" "${LAB}/ui/data/bin/frpc-${FRP_VER}/frpc"
|
||||
chmod +x "${LAB}/ui/data/bin/frpc-${FRP_VER}/frpc"
|
||||
( setsid /opt/webui4frpc/webui4frpc -addr "${UI_ADDR}" \
|
||||
-user "${UI_USER}" -password "${UI_PASS}" \
|
||||
-workdir "${LAB}/ui/data" > "${LAB}/logs/ui.log" 2>&1 < /dev/null & )
|
||||
sleep 5
|
||||
ss -ltn | grep -q "${UI_ADDR##*:}" || { echo "webui4frpc 未监听"; exit 1; }
|
||||
|
||||
AUTH="${UI_USER}:${UI_PASS}"
|
||||
|
||||
echo "==> 注入画布(注意:loopback 会被自动改写为 LAN 地址)"
|
||||
curl -s -u "${AUTH}" -X PUT "http://${UI_ADDR}/api/manager/canvas" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"remotes\":[{\"name\":\"lab-frps\",\"ip\":\"127.0.0.1\",\"port\":17000,\"token\":\"${LAB_TOKEN}\",\"enabled\":true}],
|
||||
\"locals\":[{\"name\":\"lab-backend\",\"ip\":\"127.0.0.1\",\"port\":${BACKEND_PORT}}],
|
||||
\"links\":[{\"local\":\"lab-backend\",\"remote\":\"lab-frps\",\"remotePort\":${UI_FORWARD_PORT}}]}" \
|
||||
| python3 -m json.tool
|
||||
|
||||
echo "==> binaryPath 必须先写入 settings,否则 worker 静默不启动"
|
||||
python3 - "${LAB}/ui/data/manager.db" "${LAB}/ui/data/bin/frpc-${FRP_VER}/frpc" <<'PY'
|
||||
import json, sqlite3, sys
|
||||
db, binary = sys.argv[1], sys.argv[2]
|
||||
c = sqlite3.connect(db)
|
||||
raw = c.execute("select value from settings where key='settings'").fetchone()[0]
|
||||
d = json.loads(raw); d["binaryPath"] = binary
|
||||
c.execute("update settings set value=? where key='settings'", (json.dumps(d),))
|
||||
c.commit()
|
||||
print(" binaryPath 已写入:", binary)
|
||||
PY
|
||||
|
||||
echo "==> 启动 forward(非 localOnly 需 owner claim,观察 status)"
|
||||
curl -s -u "${AUTH}" -X POST "http://${UI_ADDR}/api/manager/forwards/start" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"local\":\"lab-backend\",\"remote\":\"lab-frps\",\"remotePort\":${UI_FORWARD_PORT}}"
|
||||
echo
|
||||
sleep 5
|
||||
|
||||
echo "==> 观察结果"
|
||||
curl -s -u "${AUTH}" "http://${UI_ADDR}/api/manager/status" | python3 -c "
|
||||
import json,sys
|
||||
d=json.load(sys.stdin)
|
||||
print(' forwards:', [(f['local'], f['active']) for f in d.get('forwards',[])])
|
||||
print(' profiles:', [(p['name'], p['process']['state'], p.get('connState')) for p in d.get('profiles',[])])
|
||||
"
|
||||
echo " binaryPath: $(curl -s -u "${AUTH}" "http://${UI_ADDR}/api/manager/binary/status")"
|
||||
echo " configs/: $(ls "${LAB}/ui/data/configs/" 2>/dev/null | tr '\n' ' ')"
|
||||
echo " workers: $(pgrep -af "${LAB}/ui/data" | wc -l) 个"
|
||||
echo
|
||||
echo "日志: ${LAB}/logs/"
|
||||
echo "复现结论见 docs/how-it-works.md"
|
||||
Reference in New Issue
Block a user