https://cmptrnb.github.io

Vercel XHTTP Relay

Translated by Google Translate from ๐Ÿ‡ฎ๐Ÿ‡ท Complete Persian Setup Guide.

Telegram Channel

๐Ÿ“ข Avaco Cloud Telegram Channel โ€” Join for more tutorials, updates, censorship bypass methods and new configs:

๐Ÿ‘‰ https://t.me/avaco_cloud

A minimal relay running on Vercel Edge Functions that forwards XHTTP traffic from your Xray/V2Ray client to your backend Xray server. The goal: use Vercel's global edge network and the *.vercel.app domain as a front to hide the real IP of your origin server.

Table of Contents

Who is this project for?

This project is only useful if you have an Xray server with XHTTP and want to mask its IP with Vercel.

โŒ It is not useful for you if:

โœ… It is useful for you if:

How it works (architecture)

+-----------+                       +-------------+           +---------------+
| Client    | TLS, SNI=vercel.com   | Vercel Edge | HTTP/2    | Xray server   |
| (v2rayN/  +---------------------->| (relay)     +---------->| XHTTP inbound |
| Hiddify)  |  XHTTP request        |             | forward   |               |
+-----------+                       +-------------+           +---------------+

The client connects to the Vercel domain with SNI=vercel.com. To the censor, it looks like normal Vercel traffic. The Vercel Edge Function forwards the request body to the Xray server without buffering. The response is streamed back in the same way.

Limitations and Warnings

๐Ÿ”ด Important Warning โ€” Fast Origin Transfer: In the Hobby plan, each byte of traffic is counted twice (once clientโ†”Vercel and once Vercelโ†”server). If the quota is reached, Vercel will pause your account, users will no longer be able to connect and you will have to wait 30 days or purchase Pro. Details in Vercel Limitations section.

โš ๏ธ XHTTP only: WebSocket, gRPC, TCP, mKCP, QUIC and Reality do not work on Vercel Edge (runtime limitation).

โš ๏ธ Vercel TOS: Using a proxy may violate the TOS. If traffic is high, your account may be suspended. Keep traffic balanced.

โš ๏ธ Educational: This repo is for personal training and testing, not production. No SLA or support.

๐Ÿ’ก Sustainable Usage Tips

To avoid disconnection in the middle of the month:

Prerequisites

Items to explain

Tools required by operating system

This guide is written for both Windows and Mac/Linux. At each step you will see the equivalent commands depending on your OS.

๐ŸชŸ Windows (Windows 10/11)

All of the following tools are free:

๐Ÿ’ก Recommendation: After installing Git for Windows, use Git Bash, as Unix commands (like curl, ssh, cat) work naturally inside it. It makes this guide easier.

๐ŸŽ Mac / ๐Ÿง Linux

Step 1 โ€” Buy โ€‹โ€‹a VPS

Recommendations

Minimum specifications

After purchase

Note the public IP and the SSH password from the dashboard.

Step 2 โ€” Set up your domain and DNS

If you donโ€™t have a domain:

Set up an A Record (on Cloudflare):

  1. Go to dash.cloudflare.com
  2. Click on your domain โ†’ DNS menu โ†’ Records
  3. Add record:

๐Ÿ”ด Proxy status must be DNS only. If you set it to Proxied, Cloudflare will get caught in the middle of the traffic and wonโ€™t work.

DNS Test

๐ŸŽ Mac / ๐Ÿง Linux:

dig @8.8.8.8 xray.yourdomain.com +short

๐ŸชŸ Windows (PowerShell):

Resolve-DnsName xray.yourdomain.com -Server 8.8.8.8 -Type A

Or with nslookup:

nslookup xray.yourdomain.com 8.8.8.8

๐ŸชŸ Windows (Git Bash):

nslookup xray.yourdomain.com 8.8.8.8

It should return your server IP. This may take 1-5 minutes.

Step 3 โ€” SSH to VPS

๐ŸŽ Mac / ๐Ÿง Linux / ๐ŸชŸ Windows (PowerShell or Git Bash)

ssh root@YOUR_VPS_IP

First type yes. Enter the password (it won't show as you type โ€” this is normal).

๐ŸชŸ Windows with PuTTY (if CLI is difficult)

  1. Open PuTTY
  2. Host Name (or IP address): YOUR_VPS_IP
  3. Port: 22
  4. Connection type: SSH
  5. Click Open
  6. Click Accept the first time
  7. login: root + Enter, enter password

๐Ÿ’ก After this step, all commands starting with # (or root@vps:~#) will be executed inside the SSH server โ€” it doesn't matter if you're connecting from Mac or Windows.

Check OS:

cat /etc/os-release

You should see Ubuntu 22.04 or 24.04.

Step 4 โ€” Install Xray

Update the system and install packages:

apt update && apt upgrade -y

apt install -y curl socat cron ufw

Install Xray with the official script:

bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install

After a few seconds:

info: Xray vXX.X.X is installed

Check version:

xray version

โš ๏ธ The version must be at least v1.8.16 (for XHTTP). Newer versions (like 26.x) are better.

Generate UUID:

xray uuid

Output like:

xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Save this UUID โ€” you will need it later in the server and client config.

Enable the service

systemctl enable xray

Firewall configuration:

ufw allow 22/tcp # SSH

ufw allow 80/tcp # for issuing cert

ufw allow 443/tcp # for future

ufw allow 2096/tcp # our Xray port

ufw --force enable

ufw status

โš ๏ธ Before ufw --force enable, make sure port 22 is allowed, otherwise SSH connection will be dropped.

Step 5 โ€” Get TLS Certificate

We will use acme.sh + Let's Encrypt (free, automatic).

Install acme.sh:

curl https://get.acme.sh | sh -s email=your@email.com

source ~/.bashrc

Set the default CA:

~/.acme.sh/acme.sh --set-default-ca --server letsencrypt

Make sure port 80 is free:

ss -tlnp | grep :80

If there is anything listening (like apache or nginx), stop it:

systemctl stop apache2 2>/dev/null

systemctl disable apache2 2>/dev/null

systemctl stop nginx 2>/dev/null

Issue a certificate:

~/.acme.sh/acme.sh --issue -d xray.yourdomain.com --standalone -k ec-256

Replace xray.yourdomain.com with your actual domain.

Successful output:

Cert success.
Your cert is in: /root/.acme.sh/xray.yourdomain.com_ecc/...

Install cert in Xray path:

mkdir -p /etc/xray

~/.acme.sh/acme.sh --install-cert -d xray.yourdomain.com --ecc --fullchain-file /etc/xray/cert.pem --key-file /etc/xray/key.pem --reloadcmd "systemctl restart xray"

chown -R nobody:nogroup /etc/xray

chmod 644 /etc/xray/cert.pem

chmod 640 /etc/xray/key.pem

ls -la /etc/xray/

You should see cert.pem and key.pem.

Step 6 โ€” Configure Xray with XHTTP

Prepare Logs:

mkdir -p /var/log/xray

touch /var/log/xray/access.log /var/log/xray/error.log

chown -R nobody:nogroup /var/log/xray

cp /usr/local/etc/xray/config.json /usr/local/etc/xray/config.json.bak 2>/dev/null || true

Write config:

๐Ÿ“ Before pasting, keep these values โ€‹โ€‹in mind:

cat > /usr/local/etc/xray/config.json << 'EOF'
{
  "log": {
    "loglevel": "warning",
    "access": "/var/log/xray/access.log",
    "error": "/var/log/xray/error.log"
  },
  "inbounds": [
    {
      "tag": "xhttp-in",
      "listen": "0.0.0.0",
      "port": 2096,
      "protocol": "vless",
      "settings": {
        "clients": [
          {
            "id": "YOUR-UUID-HERE",
            "flow": ""
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "xhttp",
        "security": "tls",
        "tlsSettings": {
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "certificates": [
            {
              "certificateFile": "/etc/xray/cert.pem",
              "keyFile": "/etc/xray/key.pem"
            }
          ]
        },
        "xhttpSettings": {
          "path": "/yourpath",
          "host": "xray.yourdomain.com",
          "mode": "auto"
        }
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "tag": "direct"
    },
    {
      "protocol": "blackhole",
      "tag": "blocked"
    }
  ]
}
EOF

โš ๏ธ After pasting, open the file with:

nano /usr/local/etc/xray/config.json

Open it and replace the three values โ€‹โ€‹YOUR-UUID-HERE, /yourpath, xray.yourdomain.com with the actual values.

Test the config syntax:

xray -test -config /usr/local/etc/xray/config.json

You should see: Configuration OK.

Start Xray:

systemctl restart xray

systemctl status xray --no-pager

ss -tlnp | grep 2096

Test locally:

curl -vk https://127.0.0.1:2096/yourpath

If you get an HTTP/2 404 โ†’ Great! (404 is normal because you didn't send a UUID, which means Xray is working.)

Step 7 โ€” Deploy to Vercel

Two ways: CLI (faster) or Dashboard (with GitHub).

Method A: Vercel CLI

Install Node.js and Vercel CLI

๐ŸŽ Mac:

# If you don't have Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

brew install node

sudo npm i -g vercel

vercel --version

๐Ÿง Linux (Ubuntu/Debian):

sudo apt update

sudo apt install -y nodejs npm

sudo npm i -g vercel

vercel --version

๐ŸชŸ Windows:

Install Node.js:

  1. Go to nodejs.org
  2. Download the LTS version (.msi file)
  3. Double-click, Next until Finish
  4. Make sure Add to PATH is checked

Install Vercel CLI (in PowerShell or Git Bash):

npm i -g vercel

vercel --version

If it gives a permission error, open PowerShell As Administrator and try again.

Login to Vercel

On any operating system:

vercel login

Select Continue with Email with the arrow, enter your email, click the confirmation link.

Initial Deploy

๐ŸŽ Mac / ๐Ÿง Linux / ๐ŸชŸ Git Bash:

git clone https://github.com/YOUR-USERNAME/vercel-xhttp-relay.git

cd vercel-xhttp-relay

vercel

๐ŸชŸ Windows PowerShell:

git clone https://github.com/YOUR-USERNAME/vercel-xhttp-relay.git

cd vercel-xhttp-relay

vercel

Questions:

Set Environment Variable

vercel env add TARGET_DOMAIN

Final Deploy

vercel --prod

You will get a URL like https://your-project.vercel.app.

Method B: Dashboard (with GitHub)

  1. Fork or clone this project's repo and push it to your GitHub.
  2. Import the repo at vercel.com/new.
  3. On the Settings page, Environment Variables section:
  4. TARGET_DOMAIN = https://xray.yourdomain.com:2096
  5. Deploy.

Disabling Deployment Protection

If you enabled Vercel Authentication during setup, you need to disable it or relay won't work:

  1. Vercel Dashboard โ†’ Project โ†’ Settings โ†’ Deployment Protection
  2. Set Vercel Authentication to Disabled
  3. Save

Test relay

๐ŸŽ Mac / ๐Ÿง Linux / ๐ŸชŸ Git Bash / ๐ŸชŸ PowerShell (Win 10+):

curl -I https://your-project.vercel.app/yourpath

๐ŸชŸ Windows PowerShell (native version):

Invoke-WebRequest -Uri "https://your-project.vercel.app/yourpath" -Method Head

๐Ÿ’ก On Windows 10+, curl.exe is installed and working.

Output Meaning

Step 8 โ€” Configure the client

Configuration values

VLESS share link

vless://YOUR-UUID@vercel.com:443?encryption=none&security=tls&sni=vercel.com&alpn=h2&fp=chrome&type=xhttp&path=%2Fyourpath&host=your-project.vercel.app&mode=auto#Vercel-Relay

Note: Replace / in path with %2F encode.

Recommended Clients

Configuration Tips

Test after connection

Go to browser:

https://ifconfig.me

It should show your VPS server IP, not Iran IP.

Vercel Limitations

โš ๏ธ These numbers are from the official Vercel documentation at the time of writing this README. They may have changed โ€” check vercel.com/pricing and vercel.com/docs/limits for the latest updates.

General Numbers

๐Ÿ”ด Very important point: Fast Origin Transfer

For proxy/relay use this is more critical than Fast Data Transfer!

Every byte of your traffic is counted twice.

If Fast Origin Transfer reaches its limit, your Hobby account will be paused and you will have to wait 30 days or upgrade

๐Ÿ“š Fast Origin Transfer documentation

Hobby usage estimates (conservative)

Considering both Fast Data and Fast Origin:

๐Ÿ’ก For everyday use (chat, browsing, music, 720p video) Hobby is more than enough. For 4K streaming or heavy downloads, either go Pro or create several Hobby projects and load balance between them.

Troubleshooting

502 Bad Gateway: Tunnel Failed

Vercel cannot reach the backend server. Check:

500 Misconfigured: TARGET_DOMAIN is not set

Env var not set or redeployed. Run:

vercel env ls

vercel --prod

401 Unauthorized with HTML login

Vercel Authentication is enabled. In Dashboard โ†’ Settings โ†’ Deployment Protection โ†’ Disabled.

Client connects but traffic is not passed

TLS handshake error on client

Change SNI from vercel.com to your-project.vercel.app

Set ALPN to h2 only

Client only works on Wi-Fi, not mobile data

Mobile ISP may bottleneck *.vercel.app. Connect a Custom Domain to Vercel (Settings โ†’ Domains).

Configuration OK but Xray crashes

See error log:

tail -50 /var/log/xray/error.log

Usually cert/key file access problem. Fix with:

chown -R nobody:nogroup /etc/xray /var/log/xray

FAQ

Can I do this with Cloudflare instead of Vercel?

Yes, but with different code (Cloudflare Workers). For WebSocket, Cloudflare Workers is better. For XHTTP, Vercel is more stable because of streaming WebStreams.

What if *.vercel.app is filtered in Iran?

Connect a personal domain to Vercel (Settings โ†’ Domains โ†’ Add). Then leave the host and address the same in the client.

How many users can connect at the same time?

There is no hard limit, but create a separate UUID for each user:

        "clients": [
          { "id": "uuid-1", "email": "user1@example.com" },
          { "id": "uuid-2", "email": "user2@example.com" }
        ]

Can I change port 2096?

Yes. Put the desired port in config.json, allow in ufw, and set the same port in TARGET_DOMAIN in Vercel.

How to see Vercel logs?

vercel logs --follow

Or in Dashboard โ†’ Project โ†’ Logs.

What should I do after changing Xray configuration?

xray -test -config /usr/local/etc/xray/config.json

systemctl restart xray

Certificate is automatically renewed?

Yes. acme.sh creates a cron job and automatically renews every 60 days. You can test manually:

~/.acme.sh/acme.sh --renew -d xray.yourdomain.com --force --ecc

License

MIT โ€” same as the original project.

Disclaimer

This project is for personal training and testing. Use at your own risk. Follow the laws of your country and Vercel's TOS.

๐Ÿ“ข Contact Us

If this guide was useful to you, or you have questions/suggestions, get in touch via the Telegram channel:

Join Telegram

https://t.me/avaco_cloud

More tutorials โ€ข Update configs โ€ข Ways to bypass censorship โ€ข Support

โญ If you found the project useful, leave a Star so it can be seen more.