#!/usr/bin/env bash # test_all_configs.sh — Sequential test of 4 xray configurations on port 443 # For each config: swap remote inbound, test locally, restore, next. # # Configs: # A: VLESS + TCP + Reality + Vision (baseline) # B: VLESS + XHTTP + Reality (split uploads, anti-freeze) # C: VLESS + gRPC + Reality (H2 enterprise traffic) # D: VLESS + TCP + Reality + Vision + Fragment+Noise (TLS handshake obfuscation) set -euo pipefail XRAY_BIN="/usr/local/x-ui/bin/xray-linux-amd64" SOCKS_PORT=11082 REMOTE_IP="83.99.190.32" RESULTS_FILE="/home/alvis/ai-xray/config_test_results.md" VENV="/home/alvis/ai-xray/venv" # Shared keys PUBLIC_KEY="58Iqd6LuWXgvjAgo92-7KURhTp0Vj79yGF81l_iuvTw" PRIVATE_KEY="KJfhenZvJV1kXwv4kDC8NPBtMUY0RR8lFrxsxfXfFmY" DEST="www.delfi.lv:443" SERVER_NAMES='["www.delfi.lv","www.lmt.lv","www.inbox.lv","e-klase.lv"]' # Config A UUID_A="64522a14-54aa-4b3c-8071-8c8b17aa1f08" SID_A="48b4c16249ad44ff" # Config B (XHTTP) UUID_B="6e422ab5-070a-43f6-8241-38cd56d23d24" SID_B="6036d37d12c443c4" XHTTP_PATH="/xt-6036d37d" # Config C (gRPC) UUID_C="d0dd1e83-43d8-4bf8-a2b0-005362076b7b" SID_C="52dfa6856de91d0f" GRPC_SVC="grpc-52dfa685" # Config D (Fragment) — uses Config A server-side UUID_D="fdc4fbc1-d3c0-43e9-917f-4026ba6d4f7c" SID_D="90abc7d195f7341d" RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m' header() { echo ""; echo -e "${BOLD}${CYAN}══════════════════════════════════════════${NC}"; echo -e "${BOLD}${CYAN} $1${NC}"; echo -e "${BOLD}${CYAN}══════════════════════════════════════════${NC}"; } pass() { echo -e " ${GREEN}✓${NC} $1"; } fail() { echo -e " ${RED}✗${NC} $1"; } info() { echo -e " ${YELLOW}→${NC} $1"; } XRAY_PID="" cleanup_xray() { if [[ -n "$XRAY_PID" ]]; then kill "$XRAY_PID" 2>/dev/null || true wait "$XRAY_PID" 2>/dev/null || true XRAY_PID="" fi } trap 'cleanup_xray; rm -f /tmp/xray-test-cfg.json' EXIT # ── Remote inbound management ───────────────────────────────────────────── remote_update_inbound() { # $1 = inbound JSON string (the streamSettings portion as Python dict repr) local stream_json="$1" local uuid="$2" local flow="$3" local sid="$4" source "$VENV/bin/activate" python3 << PYEOF import requests, json import urllib3; urllib3.disable_warnings() s = requests.Session(); s.verify = False BASE = "https://share.alogins.net:16627/gBdsRLtVZdgZ63wmVR" s.post(f"{BASE}/login", data={"username": "xrayadmin", "password": "Admin2026!"}) stream = $stream_json client = {"id": "$uuid", "flow": "$flow", "email": "test-client", "limitIp": 0, "totalGB": 0, "expiryTime": 0, "enable": True, "tgId": "", "subId": "", "comment": ""} payload = { "id": 1, "tag": "inbound-443", "enable": True, "port": 443, "listen": "", "protocol": "vless", "settings": json.dumps({"clients": [client], "decryption": "none", "fallbacks": []}), "streamSettings": json.dumps(stream), "sniffing": json.dumps({"enabled": False}), "remark": "inbound-443", "expiryTime": 0 } r = s.post(f"{BASE}/panel/api/inbounds/update/1", json=payload) print(r.json().get("success"), r.json().get("msg","")) PYEOF } restore_baseline() { info "Restoring baseline (TCP+Vision) on remote..." remote_update_inbound '{ "network": "tcp", "security": "reality", "realitySettings": { "show": False, "dest": "www.delfi.lv:443", "serverNames": ["www.delfi.lv","www.lmt.lv","www.inbox.lv","e-klase.lv"], "privateKey": "'"$PRIVATE_KEY"'", "shortIds": ["'"$SID_A"'", ""] }, "tcpSettings": {"header": {"type": "none"}} }' "$UUID_A" "xtls-rprx-vision" "$SID_A" } # ── Local standalone test config writers ────────────────────────────────── write_cfg_A() { cat > /tmp/xray-test-cfg.json << EOF { "log": {"loglevel": "error"}, "inbounds": [{"listen":"127.0.0.1","port":$SOCKS_PORT,"protocol":"socks","settings":{"auth":"noauth","udp":true}}], "outbounds": [ {"tag":"proxy","protocol":"vless", "settings":{"vnext":[{"address":"share.alogins.net","port":443,"users":[{"id":"$UUID_A","flow":"xtls-rprx-vision","encryption":"none"}]}]}, "streamSettings":{ "network":"tcp","security":"reality", "realitySettings":{"fingerprint":"chrome","serverName":"www.delfi.lv","publicKey":"$PUBLIC_KEY","shortId":"$SID_A","spiderX":"/"}, "tcpSettings":{"header":{"type":"none"}} } }, {"tag":"direct","protocol":"freedom"} ] } EOF } write_cfg_B() { cat > /tmp/xray-test-cfg.json << EOF { "log": {"loglevel": "error"}, "inbounds": [{"listen":"127.0.0.1","port":$SOCKS_PORT,"protocol":"socks","settings":{"auth":"noauth","udp":true}}], "outbounds": [ {"tag":"proxy","protocol":"vless", "settings":{"vnext":[{"address":"share.alogins.net","port":443,"users":[{"id":"$UUID_B","flow":"","encryption":"none"}]}]}, "streamSettings":{ "network":"xhttp","security":"reality", "realitySettings":{"fingerprint":"chrome","serverName":"www.delfi.lv","publicKey":"$PUBLIC_KEY","shortId":"$SID_B","spiderX":"/"}, "xhttpSettings":{"path":"$XHTTP_PATH","host":"","mode":"auto", "extra":{"xPaddingBytes":"100-1000","xmux":{"maxConcurrency":"16-32","maxConnections":0,"cMaxReuseTimes":"64-128","cMaxLifetimeMs":0,"hMaxRequestTimes":"600-900","hMaxReusableSecs":"1800-3000"}}} } }, {"tag":"direct","protocol":"freedom"} ] } EOF } write_cfg_C() { cat > /tmp/xray-test-cfg.json << EOF { "log": {"loglevel": "error"}, "inbounds": [{"listen":"127.0.0.1","port":$SOCKS_PORT,"protocol":"socks","settings":{"auth":"noauth","udp":true}}], "outbounds": [ {"tag":"proxy","protocol":"vless", "settings":{"vnext":[{"address":"share.alogins.net","port":443,"users":[{"id":"$UUID_C","flow":"","encryption":"none"}]}]}, "streamSettings":{ "network":"grpc","security":"reality", "realitySettings":{"fingerprint":"chrome","serverName":"www.delfi.lv","publicKey":"$PUBLIC_KEY","shortId":"$SID_C","spiderX":"/"}, "grpcSettings":{"serviceName":"$GRPC_SVC","multiMode":true,"idle_timeout":60,"health_check_timeout":20,"initial_windows_size":65536} } }, {"tag":"direct","protocol":"freedom"} ] } EOF } write_cfg_D() { cat > /tmp/xray-test-cfg.json << EOF { "log": {"loglevel": "error"}, "inbounds": [{"listen":"127.0.0.1","port":$SOCKS_PORT,"protocol":"socks","settings":{"auth":"noauth","udp":true}}], "outbounds": [ {"tag":"proxy","protocol":"vless", "settings":{"vnext":[{"address":"share.alogins.net","port":443,"users":[{"id":"$UUID_D","flow":"xtls-rprx-vision","encryption":"none"}]}]}, "streamSettings":{ "network":"tcp","security":"reality", "realitySettings":{"fingerprint":"chrome","serverName":"www.delfi.lv","publicKey":"$PUBLIC_KEY","shortId":"$SID_D","spiderX":"/"}, "tcpSettings":{"header":{"type":"none"}}, "sockopt":{"dialerProxy":"frag-chain1"} } }, {"tag":"frag-chain1","protocol":"freedom", "settings":{"fragment":{"packets":"tlshello","length":"100-200","interval":"10-20"}}, "streamSettings":{"sockopt":{"dialerProxy":"frag-chain2"}} }, {"tag":"frag-chain2","protocol":"freedom", "settings":{ "fragment":{"packets":"1-3","length":"1-5","interval":"1-2"}, "noises":[ {"type":"rand","packet":"50-150","delay":"10-16"}, {"type":"base64","packet":"7nQBAAABAAAAAAAABnQtcmluZwZtc2VkZ2UDbmV0AAABAAE=","delay":"10-16"} ] } }, {"tag":"direct","protocol":"freedom"} ] } EOF } # ── Core test runner ────────────────────────────────────────────────────── run_test() { local label="$1" local write_fn="$2" # function name to write the config local update_fn="$3" # function name to update remote (or empty) header "$label" # Update remote if needed if [[ -n "$update_fn" ]]; then info "Updating remote inbound..." $update_fn sleep 3 # give xray time to pick up the change fi # Write local test config $write_fn # Validate if ! "$XRAY_BIN" -test -c /tmp/xray-test-cfg.json &>/dev/null; then fail "Config validation FAILED" echo "$label|INVALID|—|—|—|—|—|—" >> /tmp/results.tsv return fi pass "Config valid" # Start test xray cleanup_xray "$XRAY_BIN" -c /tmp/xray-test-cfg.json >/tmp/xray-test.log 2>&1 & XRAY_PID=$! sleep 2 if ! kill -0 "$XRAY_PID" 2>/dev/null; then fail "Xray failed to start: $(tail -3 /tmp/xray-test.log)" echo "$label|FAIL-START|—|—|—|—|—|—" >> /tmp/results.tsv return fi pass "Xray started (PID $XRAY_PID)" # Connectivity info "Checking connectivity..." local exit_ip exit_ip=$(curl -s --socks5-hostname 127.0.0.1:$SOCKS_PORT --max-time 15 https://api.ipify.org 2>/dev/null || echo "FAIL") if [[ "$exit_ip" != "$REMOTE_IP" ]]; then fail "Exit IP '$exit_ip' (expected $REMOTE_IP)" cleanup_xray echo "$label|FAIL-CONNECT|—|—|—|—|—|—" >> /tmp/results.tsv return fi pass "Exit IP: $exit_ip" # Latency — 10 samples info "Measuring latency (10 samples)..." local latencies=() for i in $(seq 1 10); do local ms ms=$(curl -s -o /dev/null -w "%{time_total}" --socks5-hostname 127.0.0.1:$SOCKS_PORT \ --max-time 10 https://www.google.com 2>/dev/null | awk '{printf "%d", $1*1000}') if [[ -n "$ms" && "$ms" -gt 0 ]]; then latencies+=("$ms") printf " [%2d/10] %s ms\n" "$i" "$ms" else printf " [%2d/10] TIMEOUT\n" "$i" fi done local n=${#latencies[@]} avg_ms=0 min_ms=0 max_ms=0 p95_ms=0 if [[ $n -gt 0 ]]; then local sorted=($(printf '%s\n' "${latencies[@]}" | sort -n)) min_ms=${sorted[0]}; max_ms=${sorted[-1]} local sum=0; for v in "${latencies[@]}"; do sum=$((sum+v)); done avg_ms=$((sum/n)) local p95_idx=$(( n * 95 / 100 )); [[ $p95_idx -ge $n ]] && p95_idx=$((n-1)) p95_ms=${sorted[$p95_idx]} fi pass "Latency ($n/10): min=${min_ms}ms avg=${avg_ms}ms p95=${p95_ms}ms max=${max_ms}ms" # Throughput info "Testing throughput..." local dl_mbps=0 ul_mbps=0 # Download 10MB local dl_out dl_out=$(curl -s -o /dev/null -w "%{size_download} %{time_total}" \ --socks5-hostname 127.0.0.1:$SOCKS_PORT --max-time 30 \ "https://speed.cloudflare.com/__down?bytes=10485760" 2>/dev/null || echo "0 0") local dl_bytes dl_time dl_bytes=$(echo "$dl_out" | awk '{print $1}') dl_time=$(echo "$dl_out" | awk '{print $2}') if [[ "${dl_bytes:-0}" -gt 1000000 ]] 2>/dev/null; then dl_mbps=$(echo "scale=2; $dl_bytes * 8 / $dl_time / 1000000" | bc) pass "Download: ${dl_mbps} Mbps (${dl_bytes} bytes in ${dl_time}s)" else fail "Download failed (bytes=${dl_bytes:-0})" fi # Upload 5MB local ul_out ul_out=$(dd if=/dev/urandom bs=1M count=5 2>/dev/null | curl -s -o /dev/null -w "%{size_upload} %{time_total}" \ --socks5-hostname 127.0.0.1:$SOCKS_PORT --max-time 30 \ -X POST --data-binary @- https://httpbin.org/post 2>/dev/null || echo "0 0") local ul_bytes ul_time ul_bytes=$(echo "$ul_out" | awk '{print $1}') ul_time=$(echo "$ul_out" | awk '{print $2}') if [[ "${ul_bytes:-0}" -gt 100000 ]] 2>/dev/null; then ul_mbps=$(echo "scale=2; $ul_bytes * 8 / $ul_time / 1000000" | bc) pass "Upload: ${ul_mbps} Mbps (${ul_bytes} bytes in ${ul_time}s)" else fail "Upload failed" ul_mbps=0 fi echo "$label|OK|$avg_ms|$min_ms|$p95_ms|$max_ms|$dl_mbps|$ul_mbps" >> /tmp/results.tsv cleanup_xray } # ── Remote update functions for each config ─────────────────────────────── update_remote_B() { source "$VENV/bin/activate" python3 << PYEOF import requests, json import urllib3; urllib3.disable_warnings() s = requests.Session(); s.verify = False BASE = "https://share.alogins.net:16627/gBdsRLtVZdgZ63wmVR" s.post(f"{BASE}/login", data={"username": "xrayadmin", "password": "Admin2026!"}) stream = { "network": "xhttp", "security": "reality", "realitySettings": { "show": False, "dest": "$DEST", "serverNames": ["www.delfi.lv","www.lmt.lv","www.inbox.lv","e-klase.lv"], "privateKey": "$PRIVATE_KEY", "shortIds": ["$SID_B", ""] }, "xhttpSettings": { "path": "$XHTTP_PATH", "host": "", "mode": "auto", "extra": {"xPaddingBytes": "100-1000", "xmux": {"maxConcurrency": "16-32", "maxConnections": 0, "cMaxReuseTimes": "64-128", "cMaxLifetimeMs": 0, "hMaxRequestTimes": "600-900", "hMaxReusableSecs": "1800-3000"}} } } client = {"id": "$UUID_B", "flow": "", "email": "test-b", "limitIp": 0, "totalGB": 0, "expiryTime": 0, "enable": True, "tgId": "", "subId": "", "comment": ""} payload = {"id": 1, "tag": "inbound-443", "enable": True, "port": 443, "listen": "", "protocol": "vless", "settings": json.dumps({"clients": [client], "decryption": "none", "fallbacks": []}), "streamSettings": json.dumps(stream), "sniffing": json.dumps({"enabled": False}), "remark": "inbound-443", "expiryTime": 0} r = s.post(f"{BASE}/panel/api/inbounds/update/1", json=payload) print(" Remote updated (XHTTP):", r.json().get("success"), r.json().get("msg","")) PYEOF } update_remote_C() { source "$VENV/bin/activate" python3 << PYEOF import requests, json import urllib3; urllib3.disable_warnings() s = requests.Session(); s.verify = False BASE = "https://share.alogins.net:16627/gBdsRLtVZdgZ63wmVR" s.post(f"{BASE}/login", data={"username": "xrayadmin", "password": "Admin2026!"}) stream = { "network": "grpc", "security": "reality", "realitySettings": { "show": False, "dest": "$DEST", "serverNames": ["www.delfi.lv","www.lmt.lv","www.inbox.lv","e-klase.lv"], "privateKey": "$PRIVATE_KEY", "shortIds": ["$SID_C", ""] }, "grpcSettings": {"serviceName": "$GRPC_SVC", "multiMode": True, "idle_timeout": 60, "health_check_timeout": 20, "initial_windows_size": 65536} } client = {"id": "$UUID_C", "flow": "", "email": "test-c", "limitIp": 0, "totalGB": 0, "expiryTime": 0, "enable": True, "tgId": "", "subId": "", "comment": ""} payload = {"id": 1, "tag": "inbound-443", "enable": True, "port": 443, "listen": "", "protocol": "vless", "settings": json.dumps({"clients": [client], "decryption": "none", "fallbacks": []}), "streamSettings": json.dumps(stream), "sniffing": json.dumps({"enabled": False}), "remark": "inbound-443", "expiryTime": 0} r = s.post(f"{BASE}/panel/api/inbounds/update/1", json=payload) print(" Remote updated (gRPC):", r.json().get("success"), r.json().get("msg","")) PYEOF } update_remote_D() { # Config D uses same server as A but adds UUID_D as client source "$VENV/bin/activate" python3 << PYEOF import requests, json import urllib3; urllib3.disable_warnings() s = requests.Session(); s.verify = False BASE = "https://share.alogins.net:16627/gBdsRLtVZdgZ63wmVR" s.post(f"{BASE}/login", data={"username": "xrayadmin", "password": "Admin2026!"}) stream = { "network": "tcp", "security": "reality", "realitySettings": { "show": False, "dest": "$DEST", "serverNames": ["www.delfi.lv","www.lmt.lv","www.inbox.lv","e-klase.lv"], "privateKey": "$PRIVATE_KEY", "shortIds": ["$SID_D", ""] }, "tcpSettings": {"header": {"type": "none"}} } client = {"id": "$UUID_D", "flow": "xtls-rprx-vision", "email": "test-d", "limitIp": 0, "totalGB": 0, "expiryTime": 0, "enable": True, "tgId": "", "subId": "", "comment": ""} payload = {"id": 1, "tag": "inbound-443", "enable": True, "port": 443, "listen": "", "protocol": "vless", "settings": json.dumps({"clients": [client], "decryption": "none", "fallbacks": []}), "streamSettings": json.dumps(stream), "sniffing": json.dumps({"enabled": False}), "remark": "inbound-443", "expiryTime": 0} r = s.post(f"{BASE}/panel/api/inbounds/update/1", json=payload) print(" Remote updated (TCP+Fragment):", r.json().get("success"), r.json().get("msg","")) PYEOF } restore_A() { source "$VENV/bin/activate" python3 << PYEOF import requests, json import urllib3; urllib3.disable_warnings() s = requests.Session(); s.verify = False BASE = "https://share.alogins.net:16627/gBdsRLtVZdgZ63wmVR" s.post(f"{BASE}/login", data={"username": "xrayadmin", "password": "Admin2026!"}) stream = { "network": "tcp", "security": "reality", "realitySettings": { "show": False, "dest": "$DEST", "serverNames": ["www.delfi.lv","www.lmt.lv","www.inbox.lv","e-klase.lv"], "privateKey": "$PRIVATE_KEY", "shortIds": ["$SID_A", ""] }, "tcpSettings": {"header": {"type": "none"}} } client = {"id": "$UUID_A", "flow": "xtls-rprx-vision", "email": "local-outbound", "limitIp": 0, "totalGB": 0, "expiryTime": 0, "enable": True, "tgId": "", "subId": "", "comment": ""} payload = {"id": 1, "tag": "inbound-443", "enable": True, "port": 443, "listen": "", "protocol": "vless", "settings": json.dumps({"clients": [client], "decryption": "none", "fallbacks": []}), "streamSettings": json.dumps(stream), "sniffing": json.dumps({"enabled": False}), "remark": "inbound-443", "expiryTime": 0} r = s.post(f"{BASE}/panel/api/inbounds/update/1", json=payload) print(" Restored baseline (TCP+Vision):", r.json().get("success")) PYEOF } # ── Run all tests ───────────────────────────────────────────────────────── echo "Config|Status|Avg_ms|Min_ms|P95_ms|Max_ms|DL_Mbps|UL_Mbps" > /tmp/results.tsv # Ensure we start with baseline on remote info "Ensuring baseline is active on remote..." restore_A run_test "A: TCP+Reality+Vision (baseline)" write_cfg_A "" run_test "B: XHTTP+Reality" write_cfg_B update_remote_B restore_A; sleep 2 run_test "C: gRPC+Reality" write_cfg_C update_remote_C restore_A; sleep 2 run_test "D: TCP+Reality+Vision+Fragment+Noise" write_cfg_D update_remote_D # Restore baseline permanently header "Restoring baseline on remote" restore_A pass "Baseline restored" # ── Summary ─────────────────────────────────────────────────────────────── header "RESULTS SUMMARY" printf "\n%-42s %-12s %-9s %-9s %-9s %-9s\n" "Configuration" "Status" "Avg ms" "DL Mbps" "UL Mbps" "P95 ms" printf "%-42s %-12s %-9s %-9s %-9s %-9s\n" "──────────────────────────────────────────" "──────────" "───────" "───────" "───────" "───────" while IFS='|' read -r name status avg min p95 max dl ul; do [[ "$name" == "Config" ]] && continue if [[ "$status" == "OK" ]]; then printf "${GREEN}%-42s${NC} %-12s %-9s %-9s %-9s %-9s\n" "$name" "$status" "${avg}ms" "$dl" "$ul" "${p95}ms" else printf "${RED}%-42s${NC} %-12s\n" "$name" "$status" fi done < /tmp/results.tsv # ── Write markdown ──────────────────────────────────────────────────────── { cat << MDEOF # Xray Configuration Comparison — Port 443 **Date**: $(date '+%Y-%m-%d %H:%M:%S') **Local xray**: 25.10.15 | **Remote xray**: 26.2.6 **Remote**: share.alogins.net (83.99.190.32), LXD container "xray" ## Results | Configuration | Status | Avg Latency | P95 Latency | Download | Upload | |---------------|--------|-------------|-------------|----------|--------| MDEOF while IFS='|' read -r name status avg min p95 max dl ul; do [[ "$name" == "Config" ]] && continue if [[ "$status" == "OK" ]]; then echo "| $name | ✓ OK | ${avg}ms | ${p95}ms | ${dl} Mbps | ${ul} Mbps |" else echo "| $name | ✗ $status | — | — | — | — |" fi done < /tmp/results.tsv cat << 'MDEOF' ## Configuration Descriptions | Config | Transport | Port | Flow | DPI Target | |--------|-----------|------|------|------------| | A | TCP + Reality | 443 | xtls-rprx-vision | Baseline — standard Russia anti-DPI | | B | XHTTP + Reality | 443 | none | Volume-based TCP freezing (split uploads, XMUX padding) | | C | gRPC + Reality | 443 | none | H2 pattern analysis (looks like enterprise API traffic) | | D | TCP + Reality + Fragment/Noise | 443 | xtls-rprx-vision | TLS ClientHello DPI signature (fragment chains + noise) | ## Methodology - Each config tested sequentially on the **same port 443** - Remote inbound swapped on-the-fly via 3x-ui API - 10 latency samples to google.com - 10 MB download from Cloudflare speed test - 5 MB upload to httpbin.org MDEOF } > "$RESULTS_FILE" echo "" echo -e "${BOLD}Results saved: $RESULTS_FILE${NC}"