Extending from a single Helsinki server to multiple exit nodes in different regions. Each server runs the same stack independently; clients switch between them via Hiddify auto-fallback.
| Tag | Location | Provider | IP | Key Protocols | Enabled |
|---|---|---|---|---|---|
| helsinki | Finland | Hetzner | <HEL_IP> |
VLESS Reality, Hysteria2, CDN-WS, XHTTP-CDN, gRPC-CDN, XrayHTTP, SS2022, DNS Tunnel, NaiveProxy, MTProto | Yes |
| oracle-madrid | Madrid | Oracle Cloud (Free) | <ORC_IP> |
VLESS Reality, Hysteria2, CDN-WS, XHTTP-CDN, gRPC-CDN, XrayHTTP, SS2022, DNS Tunnel, NaiveProxy, MTProto | Yes |
| gcp-middle-east | Middle East (Dammam) | Google Cloud ($300 credit) | <GCP_IP> |
VLESS Reality, Hysteria2, CDN-WS, XHTTP-CDN, gRPC-CDN, XrayHTTP, SS2022, MTProto | Yes |
| scaleway-london | London | Scaleway | <SCW_IP> |
VLESS Reality, Hysteria2, CDN-WS, XHTTP-CDN, gRPC-CDN, XrayHTTP, SS2022, DNS Tunnel, NaiveProxy, Cloak+SS2022, MTProto | Yes |
| Credential | Shared? | Why |
|---|---|---|
| UUID | YES | User identity — same user authenticates on all servers |
| Reality private key | NO | Generated per sing-box instance |
| Reality public key | NO | Per-server, clients need each server's key |
| Reality short-id | NO | Per-server |
| Hy2 cert SHA256 | NO | Self-signed cert per server |
| DNSTT pubkey | NO | Per dnstm install |
| Slipstream FP | NO | Per tunnel |
| WARP config | NO | Each server gets its own WARP identity |
Key principle: UUID is the only shared credential. Everything else is per-server. This means client configs need separate entries per server.
All servers use the same UUID. Per-server credentials are generated during deployment.
| Variable | Description | How to Get |
|---|---|---|
| Reality public key | Per-server Reality public key | Generated by reality-ezpz.sh |
| Reality short ID | Per-server Reality short ID | Generated by reality-ezpz.sh |
| Hy2 cert SHA256 | Per-server Hysteria2 cert hash | openssl x509 -in hy2.crt -noout -fingerprint -sha256 |
| WARP config | Per-server WireGuard identity | Generated by sing-box WARP setup |
| SS2022 server key | Per-server Shadowsocks 2022 key | Generated by deploy-ss2022.sh |
- VPS provisioned (Ubuntu 24.04, SSH key added) from any provider
- Same SSH key as Helsinki for convenience
-
Base setup — Follow server-setup.md steps 1-7 (SSH, Docker, UFW, fail2ban, unattended-upgrades)
-
Deploy reality-ezpz — Follow server-setup.md step 8
- Use same UUID as Helsinki
- SNI: diversify per server (google.com, dl.google.com, microsoft.com, etc.)
- WARP: ON
- Save generated keys
-
Deploy Hysteria2 — Follow server-setup.md step 9
- Generate new self-signed cert
- Inject into engine.conf + docker-compose.yml
- Same UUID as password
-
Deploy xray-core sidecar — Deploy XrayHTTP, XHTTP, SS2022 via HAProxy
- Use deploy scripts:
deploy-xhttp.sh,deploy-ss2022.sh
- Use deploy scripts:
-
Deploy advanced protocols (optional per server):
- Finalmask:
deploy-finalmask.sh - Salamander+Hop:
deploy-salamander-udphop.sh - ShadowTLS:
deploy-shadowtls.sh(servers with direct access) - NaiveProxy:
deploy-naiveproxy.sh(needs domain + Let's Encrypt) - Cloak:
deploy-cloak.sh(wraps SS2022) - DNS tunnel:
deploy-dnstunnel-expand.sh(needs NS delegation)
- Finalmask:
-
Automated backups — Follow server-setup.md step 13
-
DNS records — Add to Cloudflare:
- CDN record (Proxied):
cdn<N>.<DOMAIN> → <SERVER_IP>for XHTTP-CDN - NaiveProxy A record (DNS only):
web<N>.<DOMAIN> → <SERVER_IP> - DNS tunnel NS delegation (if applicable)
- CDN record (Proxied):
-
Update smart-sub worker — Add server config to worker.js, redeploy to CF Pages
# On target server
docker compose ps
ss -tlnp | grep 443
ss -ulnp | grep 8443
# From outside
curl -I https://<SERVER_IP>:443 -k
nc -zuv <SERVER_IP> 8443Users import a single subscription URL that includes all servers and protocols:
https://sub.example.com/sub/<UUID>
Backup (Vercel Edge): https://sub.example.net/sub/<UUID>
This returns ~190 configs across all 4 servers and 15+ protocol types. Hiddify auto-tests latency and falls back between them.
- XHTTP-CDN → CDN-fronted + no WS headers + anti-detection
- XHTTP-CDN + Clean CF IPs → When default CF IPs throttled
- Finalmask XDNS/XICMP → UDP-based, looks like DNS/game traffic
- XrayHTTP → Direct TCP with fake HTTP to whitelisted domains
- VLESS Reality → Direct TLS to Google-mimicking
- Hysteria2 → UDP/QUIC, fast
- Hy2 Salamander+Hop → Obfuscated QUIC + port cycling
- ShadowTLS v3 → Real TLS handshake + SS2022 inner tunnel
- IPv6 Reality/Hy2 → When ISP blocks IPv4 only
- CDN-WS → CDN-fronted but WS detectable
- SS2022, NaiveProxy, Cloak → Plan B diverse protocols
- DNS Tunnel → Emergency, always works, slow
- EDtunnel (CF Pages) → Zero server IP exposure
Only activate dns-tun-lb when you need DNS tunnel traffic distributed across multiple servers. For just VLESS Reality + Hysteria2 exit diversity, dns-tun-lb is not needed.
-
Install dnstm on France server, create
dnstt-sockstunnel -
On Helsinki, edit
/opt/dns-tun-lb/lb.yaml:backends: - id: "local-dnstt" address: "127.0.0.1:5311" - id: "france-dnstt" address: "<SERVER2_IP>:5311"
-
Run
/opt/dns-tun-lb/activate-lb.sh activate -
Add NS record: additional servers already have tns2/tns4 nameserver records
Caveat: Activating dns-tun-lb disables dnstm router, which breaks slipstream tunnels (t. and s2. subdomains). Only dnstt tunnels work through dns-tun-lb. Slipstream support is on the dns-tun-lb roadmap.
Current DNS tunnel deployment:
- Helsinki: Slipstream+SOCKS (t.), DNSTT+SOCKS, Slipstream+SSH — via tns nameserver
- Oracle Madrid: DNSTT+SOCKS (t2.) — via tns2 nameserver
- Scaleway London: DNSTT+SOCKS (s2.) — via tns4 nameserver
- Remove server's entries from client configs / subscription
- Delete DNS records for that server in Cloudflare
- If dns-tun-lb was active, remove the backend from lb.yaml and restart
- Destroy the VPS (provider dashboard)
- Update server inventory table above
- Each server backs up independently (own cron, own
/opt/vpn-backups/) - Download backups from each server separately:
scp root@<IP>:/opt/vpn-backups/*.tar.gz ~/vpn-backups/<location>/ - No cross-server state synchronization needed (stateless architecture)
- UUID rotation requires updating all servers simultaneously
- Monitor each server independently:
ssh root@<IP> 'docker compose ps && ss -tulnp'