Open Source

Undetectable proxy,
one command

Deploy a VLESS+Reality proxy server that's invisible to censorship systems. Fully automated. Takes 2 minutes.

Setup

One command

You need a VPS (Debian/Ubuntu, root SSH key access) and a terminal. The script installs everything else automatically.

curl -sS https://raw.githubusercontent.com/uburuntu/meridian/main/setup.sh | bash

It asks for your server IP, configures the proxy, and outputs a QR code. Or pass the IP directly:

curl -sS https://raw.githubusercontent.com/uburuntu/meridian/main/setup.sh | bash -s -- YOUR_IP
with a domain (adds a decoy website + CDN fallback)
curl -sS https://raw.githubusercontent.com/uburuntu/meridian/main/setup.sh | bash -s -- YOUR_IP --domain example.com

What happens

Under the hood

1
Installs Ansible & qrencode if not already present
2
Downloads the playbook from GitHub (no git clone needed)
3
Hardens the server — firewall, SSH keys only, BBR congestion control
4
Deploys VLESS+Reality via Docker — looks like microsoft.com to any probe
5
Outputs a QR code and saves an HTML file you can send to anyone
Safe to re-run at any time. Fully idempotent — picks up where it left off.

Connect

Scan and go

The script generates an HTML file with a QR code and an "Open in App" deep link. Send it to whoever needs it — they tap once and connect.

Device clock must be accurate within 30 seconds. Enable automatic date/time.

Architecture

How it works

Standalone mode

Single server. VLESS+Reality on port 443 — traffic looks like a normal HTTPS connection to microsoft.com. Censors and probes see a legitimate TLS certificate.

With a domain: HAProxy routes by TLS SNI on port 443 without terminating encryption. Reality traffic goes to Xray, domain traffic goes to Caddy (decoy website + CDN fallback via Cloudflare).

Chain mode (IP whitelist bypass)

Two servers for when direct foreign connections are blocked. A domestic relay on a whitelisted IP accepts VLESS+TCP and forwards everything abroad via VLESS+Reality+XHTTP.

git clone https://github.com/uburuntu/meridian.git && cd meridian cp inventory-chain.yml.example inventory-chain.yml # Edit inventory-chain.yml with both server IPs ansible-playbook -i inventory-chain.yml playbook-chain.yml

Local sites are routed directly from the relay. The exit node also keeps a direct Reality+TCP fallback on port 8444.

Reference

Configuration & operations

Customization (group_vars/all.yml)
VariableDefaultDescription
reality_sniwww.microsoft.comSite that Reality impersonates
utls_fingerprintchromeTLS client fingerprint
client_limit_ip2Max simultaneous IPs per client
threexui_version2.6.0Pinned 3x-ui Docker image version
ssh_disable_passwordtrueDisable SSH password auth
bbr_enabledtrueTCP BBR congestion control

For optimal stealth, use RealiTLScanner to find an SNI target near your server's datacenter.

Cloudflare CDN setup (domain mode)

Follow this order to avoid TLS certificate issues:

1. Add domain in Cloudflare, create A record to server IP
2. Keep cloud icon grey ("DNS only") — don't proxy yet
3. Run the playbook — Caddy gets the TLS cert automatically
4. Switch to orange cloud (Proxied)
5. SSL/TLS → Full (Strict), Network → Enable WebSockets

Caddy obtains certs via HTTP-01 on port 80. If Cloudflare's "Always Use HTTPS" is active, it breaks the challenge. Disable it or add a page rule for /.well-known/acme-challenge/*.

Update & maintenance

Update Xray and 3x-ui:

ssh root@YOUR_SERVER cd /opt/3x-ui && docker compose pull && docker compose up -d

Or re-run the setup command — it's safe to repeat. Add more users via the 3x-ui panel (access through SSH tunnel).

Manual Ansible setup

For full control over inventory and variables:

git clone https://github.com/uburuntu/meridian.git && cd meridian pip3 install ansible ansible-galaxy collection install -r requirements.yml # Edit inventory.yml with your server IP ansible-playbook playbook.yml
Troubleshooting

Connection fails immediately: Check device clock is accurate within 30 seconds. Enable "Set Automatically" in date/time settings.

Connection stops after days: Server IP may have been blocked. Switch to CDN fallback, or get a new IP and re-run.

Slow speeds: Some hosting IP ranges are throttled. Try a different provider or datacenter (Finland, Netherlands, Sweden).

Do NOT run other protocols (OpenVPN, WireGuard) on the same server — it flags the IP.

Security notes

Credentials are saved locally in credentials/ (git-ignored, mode 0600). The panel binds to localhost — access via SSH tunnel only. SSH password auth is disabled. UFW allows only ports 22 and 443. Automatic security updates are enabled.

The 3x-ui Docker image is pinned to a tested version. All secrets use no_log: true in Ansible output.