## Concept - **Server A** (_e.g., RU_):\ Entry point, accepts Telegram proxy user traffic via **HAProxy** (port `443\tcp`)\ and sends it through the local **Xray** client (port `10443\tcp`) to Server **B**.\ Public port for HAProxy clients — `443\tcp` - **Server B** (_e.g., NL_):\ Exit point, runs the **Xray server** (to terminate the tunnel entry point) and **telemt**.\ The server must have unrestricted access to Telegram Data Centers.\ Public port for VLESS/REALITY (incoming) — `443\tcp`\ Internal telemt port (where decrypted Xray traffic ends up) — `8443\tcp` The tunnel works over the `VLESS-XTLS-Reality` (or `VLESS/xhttp/reality`) protocol. The original client IP address is preserved thanks to the PROXYv2 protocol, which HAProxy prepends before passing to Xray, and which transparently reaches telemt. --- ## Step 1. Setup Xray Tunnel (A <-> B) You must install **Xray-core** (version 1.8.4 or newer recommended) on both servers. Official installation script (run on both servers): ```bash bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install ``` ### Key and Parameter Generation (Run Once) For configuration, you need a unique UUID and Xray Reality keys. Run on any server with Xray installed: 1. **Client UUID:** ```bash xray uuid # Save the output (e.g.: 12345678-abcd-1234-abcd-1234567890ab) — this is ``` 2. **X25519 Keypair (Private & Public) for Reality:** ```bash xray x25519 # Save the Private key () and Public key () ``` 3. **Short ID (Reality identifier):** ```bash openssl rand -hex 16 # Save the output (e.g.: 0123456789abcdef0123456789abcdef) — this is ``` 4. **Random Path (for xhttp):** ```bash openssl rand -hex 8 # Save the output (e.g., abc123def456) to replace in configs ``` --- ### Configuration for Server B (_EU_): Create or edit the file `/usr/local/etc/xray/config.json`. This Xray instance will listen on the public `443` port and proxy valid Reality traffic, while routing "disguised" traffic (e.g., direct web browser scans) to `yahoo.com`. ```bash nano /usr/local/etc/xray/config.json ``` File content: ```json { "log": { "loglevel": "error", "access": "none" }, "inbounds": [ { "tag": "vless-in", "port": 443, "protocol": "vless", "settings": { "clients": [ { "id": "" } ], "decryption": "none" }, "streamSettings": { "network": "xhttp", "security": "reality", "realitySettings": { "dest": "yahoo.com:443", "serverNames": [ "yahoo.com" ], "privateKey": "", "shortIds": [ "" ] }, "xhttpSettings": { "path": "/", "mode": "auto" } } } ], "outbounds": [ { "tag": "tunnel-to-telemt", "protocol": "freedom", "settings": { "destination": "127.0.0.1:8443" } } ], "routing": { "domainStrategy": "AsIs", "rules": [ { "type": "field", "inboundTag": [ "vless-in" ], "outboundTag": "tunnel-to-telemt" } ] } } ``` Open the firewall port (if enabled): ```bash sudo ufw allow 443/tcp ``` Restart and setup Xray to run at boot: ```bash sudo systemctl restart xray sudo systemctl enable xray ``` --- ### Configuration for Server A (_RU_): Similarly, edit `/usr/local/etc/xray/config.json`. Here Xray acts as a local client: it listens on `10443\tcp` (for traffic from HAProxy), encapsulates it via Reality to Server B, and instructs Server B to deliver it to its *local* `127.0.0.1:8443` port (where telemt will listen). ```bash nano /usr/local/etc/xray/config.json ``` File content: ```json { "log": { "loglevel": "error", "access": "none" }, "inbounds": [ { "port": 10443, "listen": "127.0.0.1", "protocol": "dokodemo-door", "settings": { "address": "127.0.0.1", "port": 8443, "network": "tcp" } } ], "outbounds": [ { "tag": "vless-out", "protocol": "vless", "settings": { "vnext": [ { "address": "", "port": 443, "users": [ { "id": "", "encryption": "none" } ] } ] }, "streamSettings": { "network": "xhttp", "security": "reality", "realitySettings": { "serverName": "yahoo.com", "publicKey": "", "shortId": "", "spiderX": "/", "fingerprint": "chrome" }, "xhttpSettings": { "path": "/" } } } ] } ``` *Replace `` with the public IP address of Server B.* Restart and setup Xray to run at boot: ```bash sudo systemctl restart xray sudo systemctl enable xray ``` --- ## Step 2. Setup HAProxy on Server A (_RU_) HAProxy will run on the public port `443` of Server A, receive incoming connections from Telegram users, attach a `PROXYv2` header (to forward the true user IP) and send the stream to the local Xray client. Docker installation is like the [AmneziaWG instructions](./VPS_DOUBLE_HOP.en.md). > [!WARNING] > If you don't run as `root` or have issues with binding to port `443` (`cannot bind socket`), allow unprivileged usage: > ```bash > echo "net.ipv4.ip_unprivileged_port_start = 0" | sudo tee -a /etc/sysctl.conf && sudo sysctl -p > ``` #### Create HAProxy Directory: ```bash mkdir -p /opt/docker-compose/haproxy && cd $_ ``` #### Create `docker-compose.yaml` ```yaml services: haproxy: image: haproxy:latest container_name: haproxy restart: unless-stopped # user: "root" network_mode: "host" volumes: - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro logging: driver: "json-file" options: max-size: "1m" max-file: "1" ``` #### Create HAProxy Config `haproxy.cfg` ```haproxy global log stdout format raw local0 maxconn 10000 defaults log global mode tcp option tcplog option clitcpka option srvtcpka timeout connect 5s timeout client 2h timeout server 2h timeout check 5s frontend tcp_in_443 bind *:443 maxconn 8000 option tcp-smart-accept default_backend telemt_nodes backend telemt_nodes option tcp-smart-connect server telemt_core 127.0.0.1:10443 check inter 5s rise 2 fall 3 maxconn 250000 send-proxy-v2 ``` >[!WARNING] >**The configuration file must end with an empty newline, otherwise HAProxy fails to start!** #### Start the HAProxy Container Allow port `443\tcp` in your firewall and launch Docker compose: ```bash sudo ufw allow 443/tcp docker compose up -d ``` --- ## Step 3. Install telemt on Server B (_EU_) telemt installation is heavily covered in the [Quick Start Guide](../QUICK_START_GUIDE.en.md). By contrast to standard setups, telemt must listen strictly _locally_ (since Xray occupies the public `443` interface) and must expect `PROXYv2` packets. Edit the configuration file (`config.toml`) on Server B accordingly: ```toml [server] port = 8443 listen_addr_ipv4 = "127.0.0.1" proxy_protocol = true [general.links] show = "*" public_host = "" public_port = 443 ``` - Address `127.0.0.1` and `port = 8443` instructs the core proxy router to process connections unpacked locally via Xray-server. - `proxy_protocol = true` commands telemt to parse the injected PROXY header (from Server A's HAProxy) and log genuine end-user IPs. - Under `public_host`, place Server A's public IP address or FQDN to ensure working links are generated for Telegram users. Restart `telemt`. Your server is now robust against DPI scanners, passing traffic optimally.