transtation.git

transtation

~ Your own VLESS + REALITY proxy with optional Cloudflare WARP egress. Server in a container or native; native client with a fail-closed killswitch.
git clone https://github.com/debuman/transtation.git
commit b36a9530cd5014ca754c3fc8c50f17b00e1e5cbe
parent c1cd1d785f279e5c3ded3d9b5e19088b533b8197
Author: sqzer <110329244+sqzer-x@users.noreply.github.com>
Date: Thu, 6 Aug 2026 15:54:08 +0900

Measure the hot paths, then change only what the measurements justify

Baseline first, on a Korean client against a real server. There is no
super-linear algorithm anywhere in this project -- every loop runs over a
handful of users, ten dest candidates or eleven routing priorities. The costs
are serialised I/O, a fixed sleep, and one process per key.

What changed, with numbers:

- WARP registration (~4.0s) and dest selection (~1.05s) are independent, so
registration now starts first and is collected after the dest is chosen.
Cold start to healthy: 11.7s -> 6.5s.
- sni_probe made two round trips per candidate: `xray tls ping` for the
technical filter, then curl to time the handshake that ping had just
performed. It now times the ping. One fewer connection per candidate, to
third-party sites, on first boot.
- The state files were read with one `sed` per key. They are read once each
with the shell now: 50 `transtation status` calls, 2919ms -> 1743ms. This is
the path the healthcheck takes every five minutes for the life of the server.
- transtation-panic probed every priority in its range up to twenty times per
address family -- 440 `ip` invocations worst case -- because several rules can
share a priority. It lists the rules and deletes what is there: 134ms -> 76ms,
bounded by reality rather than by a guess.

What did NOT improve, stated because it is the number that matters: the time
from `docker run` to a verified working proxy is 13.9s before and 13.8s after.
Reordering made the container report healthy sooner, but the remainder is a
fixed warm-up inside xray before its first proxied connection succeeds, and no
amount of reordering removes it.

`transtation verify` was rewritten twice and put back. Racing to the earliest
possible request is slower, not faster: an attempt made before the probe client
is ready sits on a ~5s backoff, so the 2s settle beats every alternative for
the one call that matters, the one install.sh makes. The retries around it are
for slower hosts, not for speed, and the comment says so.

Diffstat:
Mclient/transtation-client | 17+++++++----------
Mhost/transtation-panic | 18+++++++++---------
Minstall.sh | 7++++---
Mserver/transtation | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
4 files changed, 90 insertion(+), 53 deletion(-)

diff --git a/client/transtation-client b/client/transtation-client
@@ -301,16 +301,13 @@ cmd_panic() {
 	nft delete table ip6 transtation 2>/dev/null || true
 	# sing-box's own ip rules live at priority 9000-9010 and are NOT bound to
 	# the interface, so they outlive a SIGKILLed container.
-	# Several rules can share one priority and `ip rule del priority N` removes
-	# exactly one, so one pass per priority leaves the rest behind. Verified on
-	# a live host, where two rules sat at 9003.
-	_p=9000
-	while [ "$_p" -le 9010 ]; do
-		_n=0
-		while [ "$_n" -lt 20 ] && ip -4 rule del priority "$_p" 2>/dev/null; do _n=$((_n + 1)); done
-		_n=0
-		while [ "$_n" -lt 20 ] && ip -6 rule del priority "$_p" 2>/dev/null; do _n=$((_n + 1)); done
-		_p=$((_p + 1))
+	# Delete exactly the rules that are there rather than probing every priority
+	# in the range: several rules can share a priority, and listing first is both
+	# bounded by reality and correct for duplicates.
+	for _f in -4 -6; do
+		ip $_f rule list 2>/dev/null | sed -n 's/^\(90[0-9][0-9]\):.*/\1/p' | while read -r _p; do
+			ip $_f rule del priority "$_p" 2>/dev/null || true
+		done
 	done
 	ip route flush table 2022 2>/dev/null || true
 	ip -6 route flush table 2022 2>/dev/null || true
diff --git a/host/transtation-panic b/host/transtation-panic
@@ -12,15 +12,15 @@ TUN_IFACE=${TUN_IFACE:-tt0}
 
 nft delete table inet transtation 2>/dev/null
 nft delete table ip6 transtation 2>/dev/null
-for p in $(seq 9000 9010); do
-	# Several rules can share one priority and `ip rule del priority N` removes
-	# exactly one, so a single pass leaves the rest behind -- verified on a live
-	# host, where two rules sat at 9003. Bounded so a misbehaving iproute2
-	# cannot spin here.
-	n=0
-	while [ "$n" -lt 20 ] && ip -4 rule del priority "$p" 2>/dev/null; do n=$((n + 1)); done
-	n=0
-	while [ "$n" -lt 20 ] && ip -6 rule del priority "$p" 2>/dev/null; do n=$((n + 1)); done
+# Delete exactly the rules that are there. The previous version probed every
+# priority in the range up to 20 times per address family -- 440 `ip`
+# invocations in the worst case -- because several rules can share a priority
+# and one delete removes one rule. Listing first is both bounded by reality and
+# correct for duplicates: a priority listed twice is deleted twice.
+for f in -4 -6; do
+	ip $f rule list 2>/dev/null | sed -n 's/^\(90[0-9][0-9]\):.*/\1/p' | while read -r p; do
+		ip $f rule del priority "$p" 2>/dev/null
+	done
 done
 ip route flush table 2022 2>/dev/null
 ip -6 route flush table 2022 2>/dev/null
diff --git a/install.sh b/install.sh
@@ -315,9 +315,10 @@ install_client() {
 			TUN_IFACE=${TUN_IFACE:-tt0}
 			nft delete table inet transtation 2>/dev/null
 			nft delete table ip6 transtation 2>/dev/null
-			for p in $(seq 9000 9010); do
-			  n=0; while [ "$n" -lt 20 ] && ip -4 rule del priority "$p" 2>/dev/null; do n=$((n+1)); done
-			  n=0; while [ "$n" -lt 20 ] && ip -6 rule del priority "$p" 2>/dev/null; do n=$((n+1)); done
+			for f in -4 -6; do
+			  ip $f rule list 2>/dev/null | sed -n 's/^\(90[0-9][0-9]\):.*/\1/p' | while read -r p; do
+			    ip $f rule del priority "$p" 2>/dev/null
+			  done
 			done
 			ip route flush table 2022 2>/dev/null
 			ip -6 route flush table 2022 2>/dev/null
diff --git a/server/transtation b/server/transtation
@@ -32,10 +32,11 @@ set_paths
 die() { printf 'transtation: %s\n' "$*" >&2; exit 1; }
 warn() { printf 'transtation: %s\n' "$*" >&2; }
 
-# Read KEY from a KEY=value file. Never `.`-source these: the values include
-# free text such as "best of KR-region candidates", and sourcing that runs `of`
-# as a command. Parsing also means a tampered state file cannot execute code.
-kv() { sed -n "s/^$2=//p" "$1" 2>/dev/null | head -1; }
+# State files are PARSED, never `.`-sourced: the values include free text such
+# as "best of KR-region candidates", and sourcing that runs `of` as a command.
+# Parsing also means a tampered state file cannot execute code. Each loader
+# reads its file once with the shell's own `read` rather than spawning a
+# process per key.
 
 # ---------------------------------------------------------------- identity
 
@@ -290,21 +291,31 @@ write_runtime() {
 
 load_runtime() {
 	[ -f "$RUNTIME" ] || die "server has not started yet -- run 'docker compose up -d' first"
-	HOST=$(kv "$RUNTIME" HOST)
-	PORT=$(kv "$RUNTIME" PORT)
-	SNI=$(kv "$RUNTIME" SNI)
-	DEST=$(kv "$RUNTIME" DEST)
-	WARP=$(kv "$RUNTIME" WARP)
-	WARP_READY=$(kv "$RUNTIME" WARP_READY)
-	SNI_REASON=$(kv "$RUNTIME" SNI_REASON)
+	HOST=""; PORT=""; SNI=""; DEST=""; WARP=""; WARP_READY=""; SNI_REASON=""
+	while IFS='=' read -r _k _v; do
+		case "$_k" in
+			HOST) HOST=$_v ;;
+			PORT) PORT=$_v ;;
+			SNI) SNI=$_v ;;
+			DEST) DEST=$_v ;;
+			WARP) WARP=$_v ;;
+			WARP_READY) WARP_READY=$_v ;;
+			SNI_REASON) SNI_REASON=$_v ;;
+		esac
+	done <"$RUNTIME"
 }
 
 load_state() {
 	[ -s "$STATE" ] || die "no identity yet -- start the server first"
-	SCHEMA=$(kv "$STATE" SCHEMA)
-	REALITY_PRIV=$(kv "$STATE" REALITY_PRIV)
-	REALITY_PUB=$(kv "$STATE" REALITY_PUB)
-	CREATED=$(kv "$STATE" CREATED)
+	SCHEMA=""; REALITY_PRIV=""; REALITY_PUB=""; CREATED=""
+	while IFS='=' read -r _k _v; do
+		case "$_k" in
+			SCHEMA) SCHEMA=$_v ;;
+			REALITY_PRIV) REALITY_PRIV=$_v ;;
+			REALITY_PUB) REALITY_PUB=$_v ;;
+			CREATED) CREATED=$_v ;;
+		esac
+	done <"$STATE"
 }
 
 apply() {
@@ -496,23 +507,25 @@ sni_score() {
 	printf '%s' "$_sc"
 }
 
-# One candidate: technical filter, then latency. Writes "score domain chain rtt"
-# to its own file so parallel probes cannot interleave.
+# One candidate. `xray tls ping` performs a full TLS handshake, so timing that
+# call gives the latency directly -- the earlier version made a second curl
+# round trip per candidate to measure what the first one already cost.
+# /proc/uptime is used rather than `date`, which in busybox has no %N.
 sni_probe() {
 	# "class:domain" region_match dir
 	_cls=${1%%:*} _c=${1#*:} _rm=$2 _dir=$3
+	read -r _t0 _ </proc/uptime
 	_p=$(timeout 12 xray tls ping "$_c" 2>&1) || return 0
+	read -r _t1 _ </proc/uptime
 	case "$_p" in *"Handshake succeeded"*) ;; *) return 0 ;; esac
 	# TLS 1.2 is a hard reject, not a penalty -- REALITY needs 1.3. This is not
 	# theoretical: abema.tv looked like an ideal Japanese video dest and serves
 	# only TLS 1.2.
 	case "$_p" in *"TLS Version:"*"1.3"*) ;; *) return 0 ;; esac
-	_chain=$(printf '%s' "$_p" | sed -n "s/^Certificate chain's total length: *\([0-9][0-9]*\).*/\1/p" | head -1)
+	_chain=$(printf '%s' "$_p" | sed -n "s/^Certificate chain's total length: *\\([0-9][0-9]*\\).*/\\1/p" | head -1)
 	[ -n "$_chain" ] && [ "$_chain" -le "$CHAIN_SAFE" ] || return 0
-	# busybox date has no %N, so time the TLS handshake with curl instead.
-	_t=$(curl -sS -o /dev/null --max-time 8 -w '%{time_appconnect}' "https://$_c/" 2>/dev/null) || return 0
-	_ms=$(printf '%s' "$_t" | awk '{ printf "%d", $1 * 1000 }')
-	[ -n "$_ms" ] && [ "$_ms" -gt 0 ] || return 0
+	_ms=$(awk -v a="$_t0" -v b="$_t1" 'BEGIN { printf "%d", (b - a) * 1000 }')
+	[ -n "$_ms" ] && [ "$_ms" -gt 0 ] || _ms=1
 	printf '%s %s %s %s %s %s\n' "$(sni_score "$_cls" "$_ms" "$_chain" "$_rm")" \
 		"$_c" "$_chain" "$_ms" "$_cls" "$_rm" >"$_dir/$_c"
 }
@@ -575,9 +588,14 @@ sni_write() {
 }
 
 sni_load() {
-	SNI=$(kv "$SNIFILE" SNI)
-	SNI_REASON=$(kv "$SNIFILE" SNI_REASON)
-	SNI_CHOSEN=$(kv "$SNIFILE" SNI_CHOSEN)
+	SNI=""; SNI_REASON=""; SNI_CHOSEN=""
+	while IFS='=' read -r _k _v; do
+		case "$_k" in
+			SNI) SNI=$_v ;;
+			SNI_REASON) SNI_REASON=$_v ;;
+			SNI_CHOSEN) SNI_CHOSEN=$_v ;;
+		esac
+	done <"$SNIFILE" 2>/dev/null
 	[ -n "$SNI" ] || die "$SNIFILE is empty or corrupt -- fix it with: transtation sni auto"
 }
 
@@ -635,8 +653,22 @@ cmd_verify() {
 	EOF
 	xray run -format json -c "$_d/c.json" >/dev/null 2>&1 &
 	_pid=$!
-	sleep 2
-	_out=$(curl -fsS --max-time 20 --socks5-hostname 127.0.0.1:10809 https://cloudflare.com/cdn-cgi/trace 2>/dev/null) || true
+	# The 2s settle is measured, not arbitrary. If the probe client is not ready
+	# its first outbound sits on a ~5s retry backoff, so racing to the earliest
+	# request is slower than waiting:
+	#   settle 2.0s, then request : 2.1s   <- what install.sh actually pays
+	#   settle 0.5s, 3s cap, retry: 4.1s on a cold boot (0.6s once warm)
+	# Repeat calls could be made faster, but the call that matters happens once,
+	# right after installation, and that one is fastest this way. The retries
+	# below are for hosts slower than the ones this was measured on, not speed.
+	_out=""
+	_i=0
+	while [ "$_i" -lt 6 ]; do
+		sleep 2
+		_out=$(curl -fsS --max-time 10 --socks5-hostname 127.0.0.1:10809 https://cloudflare.com/cdn-cgi/trace 2>/dev/null) && break
+		_out=""
+		_i=$((_i + 1))
+	done
 	kill "$_pid" 2>/dev/null || true
 	rm -rf "$_d"
 
@@ -948,6 +980,15 @@ cmd_run() {
     You pinned back to an older tag. Pull the newer one, or restore a backup."
 	migrate
 
+	# --- WARP registration depends on nothing else here and is the single
+	# slowest step (about 4s), so start it now and collect it after the dest has
+	# been chosen. First boot pays max(warp, dest) instead of the sum.
+	_warp_pid=""
+	if warp_wanted && [ ! -f "$PROFILE" ]; then
+		warp_register &
+		_warp_pid=$!
+	fi
+
 	# --- where are we? one request, used for both the address and the region ---
 	_trace=$(curl -fsS --max-time 8 https://cloudflare.com/cdn-cgi/trace 2>/dev/null) || _trace=""
 	[ -n "${HOST:-}" ] || HOST=$(printf '%s' "$_trace" | sed -n 's/^ip=//p')
@@ -982,10 +1023,8 @@ cmd_run() {
 	# destroying the volume.
 	[ -s "$USERS" ] || user_add "${USER_NAME:-main}"
 
-	# --- WARP: gated on the profile file, one attempt, never fatal ------
-	if warp_wanted && [ ! -f "$PROFILE" ]; then
-		warp_register || true
-	fi
+	# --- collect the WARP registration started above ---------------------
+	[ -z "$_warp_pid" ] || wait "$_warp_pid" || true
 
 	write_config
 	write_runtime