# Support for VLESS Reverse

**URL:** https://f.docs.rw/t/topic/132
**Category:** Предложения
**Created:** 2026-06-10T22:15:44Z
**Posts:** 6

## Post 1 by @remnawave — 2026-06-10T22:15:44Z

## Summary

Xray v25.10.15 (PR #5101) introduces a VLESS simplified reverse proxy feature where a specific user entry in a VLESS inbound includes a `reverse` field:

```
{
  "tag": "r-inbound",
  "port": 8443,
  "protocol": "vless",
  "settings": {
    "users": [
      {
        "id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
        "flow": "xtls-rprx-vision",
        "reverse": {
          "tag": "r-outbound"
        }
      }
    ],
    "decryption": "mlkem768x25519plus.native.600s.aCF82eKiK6g0DIbv0_nsjbHC4RyKCc9NRjl-X9lyi0k"
  }
}
```

This allows a device behind NAT/firewall (no inbound ports open) to establish a reverse tunnel to a public server without any overlay network such as Tailscale.

References:

- [VLESS (XTLS Vision Seed) | Project X](https://xtls.github.io/en/config/inbounds/vless.html)
- [VLESS Reverse Proxy Examples | Project X](https://xtls.github.io/en/document/level-2/vless_reverse.html)

## Problem

Remnawave’s config processing pipeline makes this impossible for three reasons:

**Issue 1: `cleanInboundClients()` unconditionally wipes all VLESS `users`/`clients`**

In `src/common/helpers/xray-config/xray-config.validator.ts`:

```
public cleanInboundClients(injectFlow: boolean): void {
    for (const inbound of this.config.inbounds) {
        if (!this.hasManagedClients(inbound)) continue;
        this.ensureSettings(inbound);
        inbound.settings!.clients = []; // always wiped
    }
}
```

Any `reverse`-annotated user entry written in the config profile is destroyed before xray receives the config.

**Issue 2: `addUsersToInbound()` only injects `{ id, email }` — no `reverse` field**

```
case 'vless':
    inbound.settings.clients ??= [];
    for (const user of users) {
        inbound.settings.clients.push({
            id: user.vlessUuid,
            email: user.tId.toString(),
            // 'reverse' field is never injected
        });
    }
```

There is no mechanism in the user data model or squad system to carry a `reverse` field through to the injected config.

**Issue 3: `leaveInbounds()` excludes unregistered VLESS inbounds**

```
public leaveInbounds(tags: Set): void {
    this.config.inbounds = this.config.inbounds!.filter(
        (inbound) => tags.has(inbound.tag!) || !this.hasManagedClients(inbound),
    );
}
```

Since `vless` is a managed protocol, a reverse-only inbound not present in `activeInbounds` is stripped from the config. But if it _is_ added to `activeInbounds`, its `reverse`-annotated users get wiped by Issue 1.

## Use Case

A device sits behind a home router where the firewall cannot be modified (no open inbound ports). The VLESS simplified reverse proxy in Xray v26 is exactly designed for this NAT traversal scenario — the internal device initiates an outbound connection to the public server and establishes a persistent reverse tunnel. This feature cannot be used with Remnawave as the panel.

## Expected Behavior

One of the following would resolve this:

1. **Preferred:** Add a “reverse proxy user” concept to the squad/inbound system, where a special non-subscribing user entry carries a `reverse: { tag: "..." }` field that is injected as-is into the target VLESS inbound’s `users` array, bypassing `cleanInboundClients` for that entry.

2. **Alternative:** Introduce a flag on an inbound registration (e.g. `isReverseProxy: true`) that causes Remnawave to skip `cleanInboundClients` for that inbound and pass the raw `users` array from the config profile directly to xray unchanged.

## Environment

- Remnawave backend: v2.7.4
- Xray-core: v26.3.27
- xray-typed: v1.1.1

---

## Post 2 by @inoutDeev — 2026-06-11T02:54:47Z

Alternative suggested workaround has drawbacks in my pov also preferred one is somehow not very optimal

It can be done in similar way but with a better execution and customisation options:

1. User Edit/Create
2. Add a new toggle as `isReverse`
3. Condition check == If TRUE \> then \>  
4. A new field for Reverse Tag to be typed by Admin (or with a button to randomly generated?)  
5. A new Inbound selection dropdown (like internal squads) in user’s access scope to be used as reverse proxy inbound/outbound
4. Remnawave injects the related code at runtime to that inbounds related nodes

I think it can be done more easily than other options.

---

## Post 3 by @remnawave — 2026-06-11T03:01:56Z

There will never be any additional fields for “User.”

I don’t want to make the same mistake other panels made when they linked “flow” to a specific user. In my opinion, such an architecture will cause a huge number of problems in the future. I believe a more correct approach is the same as was implemented for “flow,” which was moved to the same level as “clients.”

It might look something like this, but I haven’t yet decided whether to make a PR to Xray repo: [Comparing XTLS:main...kastov:reverse · XTLS/Xray-core · GitHub](https://github.com/XTLS/Xray-core/compare/main...kastov:Xray-core:reverse)

---

## Post 4 by @inoutDeev — 2026-06-11T03:05:18Z

I haven’t seen that you took initiative to change related matters of it in the core itself.

If it got merged, so yeah otherwise what are the options?

---

## Post 5 by @remnawave — 2026-06-11T23:20:17Z

> <https://github.com/XTLS/Xray-core/pull/6311>
>
> ```json
> {
> "protocol": "vless",
> "settings": {
> "decryption": "none",
> … "flow": "xtls-rprx-vision",
> "clients": [
> {
> "id": "27848739-7e62-4138-9fd3-098a63964b6b",
> "email": "home@example.com"
> },
> {
> "id": "ac04551d-6ebf-4685-86e2-17c12491f7f4",
> "email": "roam@example.com"
> }
> ],
> "reverses": [
> {
> "tag": "reverse-out",
> "email": [
> "home@example.com",
> "roam@example.com"
> ]
> }
> ]
> }
> }
> ```

Unfortunately, the PR was rejected.

---

## Post 6 by @inoutDeev — 2026-06-13T04:54:09Z

> [@remnawave](#):
>
> [VLESS inbound: Add "reverses" to set reverse tag by client email by kastov · Pull Request #6311 · XTLS/Xray-core · GitHub](https://github.com/XTLS/Xray-core/pull/6311)

So, need to do it with a workaround unfortunately…
