VPNSmith
Free tool - Xray and sing-box

VLESS + REALITY config generator

Enter your server address and the site REALITY should borrow its TLS handshake from. The generator creates the X25519 key pair, UUID and short ID, then writes the matching server and client configs for Xray-core or sing-box, a vless:// link to import in v2rayN, v2rayNG, Hiddify or Shadowrocket, and the install commands. Keys never leave your browser.

Runs entirely in your browser: keys, UUID and configs are generated locally and never sent anywhere.

Your VPS public IP (or a domain pointing to it). Used in the client config and the share link.

443 is the norm: REALITY imitates HTTPS.

A third-party site with TLS 1.3 and HTTP/2, reachable from your clients. See the checklist below the tool.

uTLS fingerprint (client)

The TLS fingerprint the client imitates. chrome is the usual choice.

X25519 key pair

The private key goes on the server only. The public key goes to every client.

Hex, even length, up to 16 characters.

  • The keys are missing or invalid (32 bytes, base64url, 43 characters). Generate a pair or paste yours.

vless:// share link

vless://@203.0.113.10:443?encryption=none&flow=xtls-rprx-vision&security=reality&sni=www.example.com&fp=chrome&pbk=&sid=&type=tcp&headerType=none#my-reality

Import it in v2rayN, v2rayNG, Hiddify, Streisand or Shadowrocket, or scan the QR code.

config.json
{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "listen": "0.0.0.0",
      "port": 443,
      "protocol": "vless",
      "settings": {
        "clients": [
          {
            "id": "",
            "flow": "xtls-rprx-vision",
            "email": "my-reality"
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "tcp",
        "security": "reality",
        "realitySettings": {
          "show": false,
          "target": "www.example.com:443",
          "xver": 0,
          "serverNames": [
            "www.example.com"
          ],
          "privateKey": "",
          "shortIds": [
            ""
          ]
        }
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls",
          "quic"
        ],
        "routeOnly": true
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "tag": "direct"
    },
    {
      "protocol": "blackhole",
      "tag": "block"
    }
  ]
}
client-xray.json
{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "udp": true
      }
    },
    {
      "listen": "127.0.0.1",
      "port": 10809,
      "protocol": "http"
    }
  ],
  "outbounds": [
    {
      "protocol": "vless",
      "tag": "proxy",
      "settings": {
        "vnext": [
          {
            "address": "203.0.113.10",
            "port": 443,
            "users": [
              {
                "id": "",
                "flow": "xtls-rprx-vision",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "reality",
        "realitySettings": {
          "serverName": "www.example.com",
          "fingerprint": "chrome",
          "publicKey": "",
          "shortId": "",
          "spiderX": "/"
        }
      }
    },
    {
      "protocol": "freedom",
      "tag": "direct"
    }
  ]
}
install.sh
# Install Xray-core with the official script (systemd service included)
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install

# Optional: confirm the public key matches the private key
xray x25519 -i ""

# Check that the target answers in TLS 1.3 and HTTP/2
xray tls ping www.example.com

# Open the port
sudo ufw allow 443/tcp

# Paste the server config, test it, then start the service
sudo nano /usr/local/etc/xray/config.json
xray run -test -c /usr/local/etc/xray/config.json
sudo systemctl restart xray && sudo systemctl enable xray

# Follow the log while the first client connects
sudo journalctl -u xray -f

REALITY needs a server you control

A REALITY server is a VPS with a public IP and port 443 free, nothing more. Contabo's entry VPS includes a public IPv4, root access and a large traffic allowance, and you can pick the datacenter closest to your users.

Affiliate link: we may earn a commission, at no extra cost to you. The generator stays free and does not depend on it.

See the Contabo VPS

What each value does, and why they must match

REALITY replaces the TLS certificate you would normally need. Your server answers on port 443 like the real site you chose as target: a censor that connects without the right credentials gets the genuine site's handshake and pages, forwarded by your server. Only a client that knows the server's public key and a valid short ID completes the proxy handshake.

That is why four values have to agree on both sides. The private key stays on the server and the public key goes to every client. The target host must appear both as the destination (target, or dest in older guides; handshake.server in sing-box) and in the accepted server names, and the client sends it as SNI. The short ID the client sends must be one of the server's list. The UUID identifies the user, and xtls-rprx-vision must be set on both ends or the connection is refused.

The configs below keep to the documented fields only: no deprecated sing-box sniff options in the inbound, no extra transports. Add routing rules or more users once the basic tunnel works.

Choosing the target site: a checklist

The target matters more than any other field, and no tool can pick it for you. These are the properties to check before you settle on one.

CheckWhy it mattersHow to verify
TLS 1.3 and HTTP/2REALITY needs a TLS 1.3 handshake to mirrorxray tls ping <host>, or curl -I --tlsv1.3 --http2
Not blocked where your clients areA blocked target makes your server look like a blocked siteOpen it from the client's network without a proxy
Plausible from your server's networkA small VPS serving a giant's homepage stands out; a host on the same provider or region blends in betterCompare the target's IP location with your VPS datacenter
No redirect to another domainThe SNI must match the certificate the target really servescurl -sI https://<host> and check for a Location header
Not your own domainThe point is to look like somebody else's real trafficPick a third-party site you do not control

Circumventing network restrictions is restricted or unlawful in some jurisdictions. Check what applies where you and your users are.

Frequently asked questions

Is it safe to generate REALITY keys in a web page?
Here the key pair is generated by your browser's WebCrypto implementation (X25519) and nothing is sent to a server: you can disconnect from the network after the page loads and the tool keeps working. If you prefer, run xray x25519 or sing-box generate reality-keypair on the server and paste the private key: the Derive button computes the matching public key locally.
Where do I find the public key if I only have the private key?
Paste the private key and press Derive public key. It gives the same result as xray x25519 -i "<private key>", which prints the private key and, under the label Password (PublicKey), the public key that clients need.
Is the config compatible with v2rayN, v2rayNG, Hiddify and Shadowrocket?
Yes, import the vless:// link or scan the QR code. The link carries security=reality, the public key (pbk), the short ID (sid), the SNI, the uTLS fingerprint (fp) and flow=xtls-rprx-vision, which those clients read. If a client rejects it, update it: REALITY and Vision need a recent core.
Should I use dest or target in Xray?
Both are accepted by current Xray-core, where target is the name used in its own error messages. Most tutorials still write dest. The generator writes target on the server; if you run an old core that refuses it, rename the field to dest.
Do I need a domain name or a certificate?
No. REALITY borrows the handshake of the target site, so the server needs neither a domain nor a certificate: a VPS with a public IP and TCP port 443 open is enough. That is one of the main reasons it replaced VLESS over WebSocket with TLS for new setups.
Why does the client connect but no site loads?
Usually one of three mismatches: the short ID is not in the server list, the public key is not the pair of the server's private key, or flow is set on one side only. Check the server log with journalctl, and if you set maxTimeDiff (max_time_difference in sing-box), check the clock of both machines: drift then looks like a key error.