Reality hides a VPN behind an ordinary website. If that website belongs to someone else, such as microsoft.com or dl.google.com, the server is easy to spot, which is why such servers are being blocked en masse in 2026. Self-steal solves the problem – the server imitates your own website with a real certificate.
TIP
This article in brief
- Result – VLESS Reality that looks like your website to everyone;
- Time – about 20 minutes;
- You need – a VPS with Ubuntu or Debian and your own domain;
- Works with – Xray without a panel, 3X-UI, Marzban and Remnawave.
Why servers get blocked
| When | What happened |
|---|---|
| November 2025 | Mass drops of VLESS Reality on port 443 with home internet providers |
| 17 February 2026 | A major wave of blocking of VLESS Reality over TCP across the country |
| May 2026 | Tests of new methods in Siberia, the Far East and Moscow |
| August – September 2026 | Blocking of IP addresses and subnets of popular VPS hosting providers |
Reality itself has not been cracked. The providers' filters (TSPU) look for indirect signs, and the main one is imitating someone else's site:
- the site name (SNI) is sent in plain text;
- microsoft.com on the IP address of a small hosting provider looks unnatural;
- anyone who connects to the server will see the real Microsoft site on someone else's IP address.
What the Xray developers say
Since 2026, Xray prints a warning if apple.com, icloud.com or microsoft.com is chosen as the target, and since July 2026 also for sites in the .ru, .ir and .cn zones. The official Reality documentation advises choosing a site from the same network as the server. The easiest way to meet this condition is to host the site on the server itself.
How self-steal works
| Who connects | What they see |
|---|---|
| Your client with the key | A VPN connection |
| Provider, scanner, browser | Your website with a real certificate |
The domain, the certificate and the IP address all match, so the server looks like thousands of ordinary websites. Xray accepts connections on port 443, and the site runs in nginx on the internal address 127.0.0.1:8443.
WARNING
Self-steal is not a full guarantee. In August and September 2026, such servers were also caught in subnet blocks. The scheme works best together with a neutral domain, a small number of users and the firefox fingerprint.
What you need
- a VPS with Ubuntu 22.04, 24.04 or Debian 12 – DE-PROMO is enough for personal use, and DE-RZ9-1 suits a 1 Gbit/s channel;
- a domain or subdomain pointing to this server;
- free ports 80 and 443.
TIP
Choose a neutral domain name, like one for a blog or a portfolio, without the words vpn, proxy, xray, reality or node. For a server in Germany, an international zone (.com, .net, .org) or .de is better – Xray prints a warning about the .ru zone.
Step 1. DNS record
Create an A record with the server's IP address at your registrar. If the domain is connected to Cloudflare, turn the proxy off (grey cloud) – Reality does not work through a CDN.
dig +short example.comThe command should print the server's IP address.
Step 2. Website and certificate
Install nginx and certbot, then put a simple page on the site – a blog, a business card, anything except an empty placeholder:
apt update && apt install -y nginx certbot
nano /var/www/html/index.htmlIssue a certificate, replacing the domain and email with your own:
certbot certonly --webroot -w /var/www/html -d example.com -m you@example.com --agree-tos --no-eff-email --deploy-hook "systemctl reload nginx"Certbot will renew the certificate and reload nginx by itself.
Step 3. nginx configuration
Open the /etc/nginx/sites-available/default file and replace its contents, putting in your own domain:
server {
listen 80;
listen [::]:80;
server_name example.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 127.0.0.1:8443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}nginx -t && systemctl reload nginxWhat this configuration does
- Port 80 – certificate renewal and redirecting visitors to HTTPS.
- 127.0.0.1:8443 – the site itself. It is reachable only from inside the server, and port 443 stays free for Xray.
- The warning
listen ... http2 is deprecatedin newer nginx versions can be ignored. Do not replace the line withhttp2 on;– nginx in Ubuntu 22.04, 24.04 and Debian 12 does not know this directive and will not start.
Step 4. Installing Xray and keys
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
xray uuid
xray x25519
openssl rand -hex 8Save four values:
| Value | Where to get it | Where it is needed |
|---|---|---|
| UUID | xray uuid | Server and client |
| Private key | xray x25519, the PrivateKey line | Server only |
| Public key | xray x25519, the Password (PublicKey) or Public key line | Client only |
| Short ID | openssl rand -hex 8 | Server and client |
Step 5. Configuring Xray
WARNING
If the /usr/local/etc/xray/config.json file already contains your connections, do not wipe it, or you will lose your users. Change only the realitySettings block according to the table below.
For a new installation, open the file with nano /usr/local/etc/xray/config.json and paste the configuration, replacing the upper-case values.
Xray configuration for a new installation
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"listen": "0.0.0.0",
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "UUID",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"target": "127.0.0.1:8443",
"xver": 0,
"serverNames": ["example.com"],
"privateKey": "PRIVATE_KEY",
"shortIds": ["SHORT_ID"]
}
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"]
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}Three fields matter most in this configuration:
| Field | Value | Why |
|---|---|---|
target | 127.0.0.1:8443 | Outsiders are sent to your site. The field used to be called dest |
xver | 0 | Otherwise nginx gets an extra PROXY protocol header, and the site will not open |
serverNames | Your domain | Must match the domain in the certificate |
Check the configuration and restart Xray:
xray run -test -config /usr/local/etc/xray/config.json
systemctl restart xrayStep 6. Firewall
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enableIf SSH runs on another port, use it instead of 22.
Step 7. Check
Open https://example.com in a browser. If your site appears without any certificate warnings, Xray is correctly passing outside connections to nginx.
Step 8. Connecting a client
vless://UUID@example.com:443?encryption=none&flow=xtls-rprx-vision&security=reality&sni=example.com&fp=firefox&pbk=PUBLIC_KEY&sid=SHORT_ID&type=tcp#My-serverPut in your own values and import the link into the app, as shown in the import instructions. We explain why the link uses fp=firefox in the article about 3X-UI.
Self-steal in panels
First complete steps 1–3 on the server where Xray runs. Then change the connection in the panel.
Open the VLESS Reality connection and set:
- Target –
127.0.0.1:8443; - SNI – your domain;
- Xver –
0.
There is no need to regenerate the keys.
- In Core Settings, in the
realitySettingsblock, settargetto127.0.0.1:8443,serverNamesto your domain andxverto0. - In Host Settings, enter this domain in the SNI field.
- In Config Profiles, open the node's profile and make the same three changes in
realitySettings. - If SNI is overridden in Hosts, enter the new domain there.
You can read more about the panel in the article “Installing Remnawave on a VPS”.
INFO
If Xray runs in Docker without network_mode: host, the address 127.0.0.1 points inside the container, and nginx will be unreachable. The Remnawave node runs in host mode, so this does not affect it.
Moving from someone else's site
- Make a copy of the settings with
cp /usr/local/etc/xray/config.json /usr/local/etc/xray/config.json.bak. - Complete steps 1–3.
- Change
target,serverNamesandxveraccording to the table in step 5. If the configuration has bothdestandtarget, keep only one of them. - Check the configuration and restart Xray.
The UUID, keys and Short ID stay the same. Users only need to refresh their subscription or link, where the sni value will change.
WARNING
If Reality was installed through the AmneziaVPN app, the app writes the server settings itself, and manual changes may be lost. For self-steal it is more reliable to install Xray separately.
If something does not work
| Symptom | What to check |
|---|---|
| The site does not open | The A record, the nginx -t output, whether nginx listens on port 8443 (ss -tlnp | grep 8443) |
| Xray does not start | The log journalctl -u xray -n 50, the JSON syntax, whether port 443 is already in use |
| The site opens, but the VPN does not | Whether UUID, sni, pbk and sid match the server, whether the client is up to date |
| The certificate does not renew | Whether port 80 is open, the result of certbot renew --dry-run |
| It does not work with one provider | A different fingerprint in the client, connecting from another network, whether the IP is blocked |
Tips
- Fewer users – a less noticeable traffic profile.
- A real page – looks more natural than an empty placeholder.
- Fresh versions – Xray updates with the same installation command, and keep your clients up to date too.
- A backup connection – for example, VLESS + TLS + XHTTP in case the main one stops working.
Our resources
Telegram channel: https://t.me/f3cloud_news
F3 Cloud: https://f3cloud.com