#!/usr/bin/env bash # w4f demo cluster: 4-node ring (a=leader, b/c/d join) + 1 isolated standalone (e). set -euo pipefail cd "$(dirname "$0")" FRP=${FRP:-/home/jianf/Program/frp/bin} NET=w4f-demo VER=0.70.1 docker network inspect $NET >/dev/null 2>&1 || docker network create $NET # clean + seed node-a cache with real frpc binary for d in node-a node-b node-c node-d node-e; do rm -rf data/$d 2>/dev/null || true; mkdir -p data/$d; done mkdir -p data/node-a/bin/frpc-$VER [ -x data/node-a/bin/frpc-$VER/frpc ] || cp $FRP/frpc data/node-a/bin/frpc-$VER/frpc chmod +x data/node-a/bin/frpc-$VER/frpc echo "== starting backend ==" docker run -d --name w4f-backend --user $(id -u):$(id -g) --network $NET --network-alias backend -p 18080:8080 -v $PWD/artifacts/backend:/app/backend:ro --restart unless-stopped --entrypoint /app/backend debian:bookworm-slim echo "== starting frps ==" docker run -d --name w4f-frps --user $(id -u):$(id -g) --network $NET --network-alias frps -p 7000:7000 -p 7080:7080 -p 18081:18081 -v $FRP/frps:/app/frps:ro -v $PWD/frps.toml:/app/frps.toml:ro --restart unless-stopped --entrypoint /app/frps debian:bookworm-slim -c /app/frps.toml echo "== starting mock frps2 (bindPort 7001) ==" docker run -d --name w4f-frps2 --user $(id -u):$(id -g) --network $NET --network-alias frps2 -p 7001:7001 -p 7081:7081 -v $FRP/frps:/app/frps:ro -v $PWD/frps2.toml:/app/frps.toml:ro --restart unless-stopped --entrypoint /app/frps debian:bookworm-slim -c /app/frps.toml echo "== starting mock frps3 (bindPort 7002) ==" docker run -d --name w4f-frps3 --user $(id -u):$(id -g) --network $NET --network-alias frps3 -p 7002:7002 -p 7082:7082 -v $FRP/frps:/app/frps:ro -v $PWD/frps3.toml:/app/frps.toml:ro --restart unless-stopped --entrypoint /app/frps debian:bookworm-slim -c /app/frps.toml echo "== starting node-a (seed, has frpc cache) ==" docker run -d --name w4f-node-a --user $(id -u):$(id -g) --network $NET --network-alias node-a -e W4F_HOST=node-a -p 7501:7500 -p 17401:7400 -v $PWD/artifacts/webui4frpc:/app/webui4frpc:ro -v $PWD/data/node-a:/data -v $FRP:/app/frp:ro --restart unless-stopped --entrypoint /app/webui4frpc debian:bookworm-slim -addr=0.0.0.0:7500 -user=admin -password=admin123 -workdir=/data -frpc=/app/frp/frpc # Wait for node-a to be ready and fetch its admission key. Nodes b/c/d join # via node-a, so they need node-a's nodeKey (-join-key) to pass the sponsor # verification in handleClusterJoin (403 on mismatch/empty). Node-e is isolated. echo "== fetching node-a join key ==" KEY="" for _ in $(seq 1 15); do KEY=$(curl -fsS -u admin:admin123 http://localhost:7501/api/manager/cluster/ring 2>/dev/null \ | python3 -c "import sys,json; print(json.load(sys.stdin).get('nodeKey',''))" 2>/dev/null || true) [ -n "$KEY" ] && break sleep 1 done if [ -z "$KEY" ]; then echo "FATAL: could not fetch node-a join key"; docker logs w4f-node-a 2>&1 | tail 20; exit 1; fi echo " node-a join key: $KEY" echo "== starting node-b (no frpc; joins via node-a) ==" docker run -d --name w4f-node-b --user $(id -u):$(id -g) --network $NET --network-alias node-b -e W4F_HOST=node-b -p 7502:7500 -v $PWD/artifacts/webui4frpc:/app/webui4frpc:ro -v $PWD/data/node-b:/data -v $FRP:/app/frp:ro --restart unless-stopped --entrypoint /app/webui4frpc debian:bookworm-slim -addr=0.0.0.0:7500 -user=admin -password=admin123 -workdir=/data -frpc=/app/frp/frpc -peer=node-a:7500 -join-key=$KEY echo "== starting node-c (no frpc; joins via node-a) ==" docker run -d --name w4f-node-c --user $(id -u):$(id -g) --network $NET --network-alias node-c -e W4F_HOST=node-c -p 7503:7500 -v $PWD/artifacts/webui4frpc:/app/webui4frpc:ro -v $PWD/data/node-c:/data -v $FRP:/app/frp:ro --restart unless-stopped --entrypoint /app/webui4frpc debian:bookworm-slim -addr=0.0.0.0:7500 -user=admin -password=admin123 -workdir=/data -frpc=/app/frp/frpc -peer=node-a:7500 -join-key=$KEY echo "== starting node-d (no frpc; joins via node-a) ==" docker run -d --name w4f-node-d --user $(id -u):$(id -g) --network $NET --network-alias node-d -e W4F_HOST=node-d -p 7504:7500 -v $PWD/artifacts/webui4frpc:/app/webui4frpc:ro -v $PWD/data/node-d:/data -v $FRP:/app/frp:ro --restart unless-stopped --entrypoint /app/webui4frpc debian:bookworm-slim -addr=0.0.0.0:7500 -user=admin -password=admin123 -workdir=/data -frpc=/app/frp/frpc -peer=node-a:7500 -join-key=$KEY echo "== starting node-e (isolated standalone, not in cluster) ==" docker run -d --name w4f-node-e --user $(id -u):$(id -g) --network $NET --network-alias node-e -e W4F_HOST=node-e -p 7505:7500 -v $PWD/artifacts/webui4frpc:/app/webui4frpc:ro -v $PWD/data/node-e:/data -v $FRP:/app/frp:ro --restart unless-stopped --entrypoint /app/webui4frpc debian:bookworm-slim -addr=0.0.0.0:7500 -user=admin -password=admin123 -workdir=/data -frpc=/app/frp/frpc echo "== cluster up ==" docker ps --filter "name=w4f-" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"