> The full list of articles is in [llms.txt](https://docs.f3cloud.com/llms.txt). Every page has a Markdown version: add .md to its address. This page as Markdown: [https://docs.f3cloud.com/en/vpn-guide/reality-self-steal.md](https://docs.f3cloud.com/en/vpn-guide/reality-self-steal.md).

# Self-steal for VLESS Reality – camouflage as your own website

Why VLESS Reality servers that imitate third-party sites are being blocked and how to switch to self-steal. Your own domain, nginx on 127.0.0.1:8443, Xray with Reality, and setup in 3X-UI, Marzban and Remnawave.

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.

<details>

<summary>What the Xray developers say</summary>

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.

</details>

### 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.

```bash
dig +short example.com
```

The 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:

```bash
apt update && apt install -y nginx certbot
nano /var/www/html/index.html
```

Issue a certificate, replacing the domain and email with your own:

```bash
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:

```nginx
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;
    }
}
```

```bash
nginx -t && systemctl reload nginx
```

<details>

<summary>What this configuration does</summary>

* **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 deprecated` in newer nginx versions can be ignored. Do not replace the line with `http2 on;` – nginx in Ubuntu 22.04, 24.04 and Debian 12 does not know this directive and will not start.

</details>

### Step 4. Installing Xray and keys

```bash
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
xray uuid
xray x25519
openssl rand -hex 8
```

Save 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.

<details>

<summary>Xray configuration for a new installation</summary>

```json
{
  "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"
    }
  ]
}
```

</details>

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:

```bash
xray run -test -config /usr/local/etc/xray/config.json
systemctl restart xray
```

### Step 6. Firewall

```bash
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable
```

If 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

```text
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-server
```

Put in your own values and import the link into the app, as shown in the [import instructions](https://docs.f3cloud.com/en/vpn-guide/marzban-installation.md#step-4.-connect-to-the-vpn). We explain why the link uses `fp=firefox` in the article [about 3X-UI](https://docs.f3cloud.com/en/vpn-guide/3x-ui-panel-guide.md#vless-reality).

### Self-steal in panels

First complete steps 1–3 on the server where Xray runs. Then change the connection in the panel.

#### 3X-UI

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.
#### Marzban

1. In **Core Settings**, in the `realitySettings` block, set `target` to `127.0.0.1:8443`, `serverNames` to your domain and `xver` to `0`.
2. In **Host Settings**, enter this domain in the SNI field.
#### Remnawave

1. In **Config Profiles**, open the node's profile and make the same three changes in `realitySettings`.
2. 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”](https://docs.f3cloud.com/en/vpn-guide/remnawave-installation.md).

> **Note.**
>
> 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

1. Make a copy of the settings with `cp /usr/local/etc/xray/config.json /usr/local/etc/xray/config.json.bak`.
2. Complete steps 1–3.
3. Change `target`, `serverNames` and `xver` according to the table in step 5. If the configuration has both `dest` and `target`, keep only one of them.
4. 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](https://docs.f3cloud.com/en/vpn-guide/setup-vless-xhttp.md) in case the main one stops working.

***

### Our resources

**Telegram channel:** [https://t.me/f3cloud_news](https://t.me/f3cloud_news)\
**F3 Cloud:** [https://f3cloud.com](https://f3cloud.com/en)
