Open-source self-hosted VPN

Share secure internet with the people you care about

One command turns a fresh VPS into a hardened VPN server that blends in with ordinary HTTPS, with a built-in web panel for you and a one-tap connection page for each person.

Connection page — what each person receives
What each person receives — try the connection page · try the web panel

How it works

Two commands to a working VPN

You need a Debian or Ubuntu VPS (a $5/month one is enough) and a terminal on your computer. Meridian sets up the rest.

A full meridian setup, start to finish: 3½ minutes. Download the video
Step 1 — Install
curl -sSf https://getmeridian.org/install.sh | bash
then
Step 2 — Set up
meridian setup

The wizard asks a few plain questions, shows a review, then sets up your server. For one server with no questions, run meridian deploy IP — see the CLI reference.

Meridian deploy output in a terminal

What happens behind the scenes

  1. Installs the control service and web panel with a node agent that runs Xray — no Docker, no third-party panel

  2. Generates x25519 keypair — unique encryption keys for Reality authentication

  3. Hardens the server — UFW opens only your SSH port, 443 (TCP and UDP), and 80 for certificates; SSH key-only login, fail2ban, BBR congestion control

  4. Configures VLESS+Reality on TCP 443, where probes see a real website's certificate

  5. Adds XHTTP and Hysteria2 — XHTTP through nginx on the same port, Hysteria2 on UDP 443 with salamander obfuscation

  6. Outputs QR codes and a connection page once real traffic has passed through the new subscription

Safe to re-run. A second run keeps credentials and keys, and resumes or updates the deployment in place.

See it

What you and your people get

Every deployment includes a connection page for each person and a web panel for you. Both demos run in your browser on invented data: click around, nothing is real and nothing is sent anywhere.

Connection page

Each person opens their subscription link in a browser: they pick their platform and app, import with one tap or a QR code, check their traffic and expiry, and read notices and plain help in four languages.

Try the connection page

Web panel

Run meridian panel to open your management panel (owner console). Add people, share links and QR codes, set expiry dates, traffic limits, and device caps, keep private notes and tags, post a notice for everyone, and issue scoped API tokens.

Try the web panel

Command builder

Build your command

Pick options and copy the full command. Covers deploy, relays, checks, camouflage scans, diagnostics, and teardown.

Deploy Reality, XHTTP, and Hysteria2 on one server. Sets up the control service, web panel, nginx, the firewall, and TLS.

Server IP, a saved server name, or "local" to run on the server itself. Leave empty to be asked.
Default: the saved user, else root. Non-root users need passwordless sudo.
Default: the saved port, else 22.
Optional. Moves XHTTP to your domain and adds WSS; both can run through the Cloudflare CDN.
The site Reality imitates. Leave it on auto and deploy picks one that works from your server, or find one with the SNI scan tab.
Name for the first person who connects. Default: "default".
Label shown on connection pages.
An emoji or an image URL for the connection page.
Color theme of the connection page.
Command
meridian deploy

First time? Just run meridian setup — the wizard asks for everything it needs.

Technology

How it avoids detection

OpenVPN and WireGuard have recognizable traffic signatures. A VLESS+Reality connection is hard to tell apart from ordinary HTTPS to a real website.

Deep Packet Inspection (DPI)

DPI inspects traffic patterns to identify VPN and proxy protocols. OpenVPN and WireGuard have handshakes that are easy to recognize and block.

VLESS+Reality runs inside a standard TLS 1.3 connection on port 443, so DPI sees what looks like ordinary HTTPS to the camouflage site. Every server also offers XHTTP and Hysteria2, so a block on one method leaves the others working.

Active probing

Censors connect to suspicious servers and try to fingerprint them. If a server responds differently than the website it claims to be, it gets blocked.

Reality borrows the TLS identity of a real website: by default a site hosted near your server, or www.google.com. A probe without your key is passed through to that site and sees its genuine certificate. Only clients with your key enter the VPN tunnel.

TLS fingerprinting

Every TLS client sends a unique "Client Hello" fingerprint. Censors flag connections where the fingerprint doesn't match the claimed application.

Client apps use uTLS to send the same Client Hello as Chrome. Meridian also publishes a Firefox copy of each Reality and XHTTP entry, so if censors flag one fingerprint, the other keeps working.

Connect

Scan and go

After deploying, each person gets a connection page with QR codes and one-tap import. Send them the link — they tap once and connect.

Connection pages list these apps first and link others for each platform. See the demo.

Turn on automatic date and time on every device. Connections can fail when the device clock is wrong.

Architecture

Under the hood

Meridian architecture: nginx routes TCP 443 by SNI to Xray Reality, XHTTP, and the connection pages; Hysteria2 listens on UDP 443Internetnginx stream — SNI routerTCP 443Xray Hysteria2UDP 443 (salamander)Xray Realitynginx http :8443SNI = camouflageno SNI / server IPConnection pagesControl serviceXray XHTTPXray WSSdomain modenginx ACMETCP 80
Standalone mode (no domain)

nginx owns TCP port 443 and routes connections by TLS SNI with its stream module. Reality connections go to Xray. Everything else reaches nginx's http module, which serves the connection pages, subscriptions, and XHTTP over HTTPS with a short-lived Let's Encrypt certificate for the server's IP (issued by acme.sh). Hysteria2 listens on UDP 443 with salamander obfuscation.

Meridian's control service sits behind nginx on a secret path: it keeps your users, serves their subscriptions, and hosts the web panel over HTTPS, with no SSH tunnel needed. A small agent on each server dials out to it, so nodes open no extra ports.

Domain mode (CDN fallback)

With --domain, nginx gets a Let's Encrypt certificate for your domain and routes that SNI to the domain's paths. XHTTP moves to the domain and VLESS+WSS is added. With Cloudflare proxying the domain, both travel through the CDN and keep working if your server's IP is blocked. The control service and connection pages stay on the IP certificate.

Relay mode (domestic entry point)

A Realm TCP forwarder on a server inside your country passes connections to your exit abroad. Relays carry Reality only; XHTTP, WSS, and Hysteria2 still connect to the exit directly. Encryption runs end to end between the app and the exit, so the relay never sees plaintext.

Add one with meridian relay add RELAY_IP --exit EXIT. Subscriptions and connection pages pick up the relay entries automatically.

Ready to get started?

Install Meridian, deploy your VPN server, and share access with the people who need it. A deploy usually takes 3 to 10 minutes.