Files
obsidian-vault/personal/tech/xray-reverse-limits-private-network.md
T

7.7 KiB
Raw Blame History

title, created, type, namespace, tags, status, related
title created type namespace tags status related
Xray reverse — граница возможностей (forward proxy в приватные сети) 2026-09-23 tech personal
xray
reverse
vless
vpn
networking
pitfall
verified
personal/tech/xray-reverse-tunnel-kraken-truenas
personal/plans/lan-access-via-reverse-tunnel

Xray reverse — граница возможностей

Короткий вывод: Xray reverse намеренно не даёт использовать себя как «вход в чужую приватную сеть». Это защита от превращения сервера в открытый прокси — не баг, версией Xray не лечится, конфигом не обходится (кроме одного случая, см. ниже).

Проверено вживую 2026-09-23 на связке TrueNAS (портал) ↔ Кра́кен (бридж), Xray 26.4.25.

Симптом

Настроен рабочий reverse-канал (payload проходит, egress проверен). Подаём в него трафик, адресованный в приватную сеть публичной стороны:

портал: for safety reasons, user a81c3179-312b-4c5e-8a46-6bf3c30c2941
        is not allowed to use forward proxy

Соединение доходит до портала (received request for tcp:192.168.2.197:80), но портал отказывается его выпускать.

Причина (официальная документация)

Из доки Xray, outbound freedom:

⚠️ Default fallback safety policy (server-side / reverse-proxy scenarios):

  • Traffic from VLESS reverse proxy blocks all targets by default
  • Traffic from VLESS, VMess, Trojan, Shadowsocks, Hysteria, or WireGuard inbounds blocks private and reserved IP ranges by default
  • Other traffic is fully allowed by default

To allow clients access to internal services, explicitly configure allow rules and limit them to necessary network, ip, and port.

Источник: https://xtls.github.io/en/config/outbounds/freedom.html

Портал классифицирует запрос как forward proxy (клиент просит «сходи на 192.168.2.197») и режет его по политике.

Единственная рабочая конфигурация reverse

Use Case 2 из доки Xray — «Remote Return Home»:

клиент → PUBLIC SERVER (портал) → reverse-out → туннель
                                                     ↓
                               INTERNAL DEVICE (бридж)
                                                     ↓
                            freedom + finalRules[allow ip <локальная сеть>]
                                                     ↓
                                          <сеть «внутренней» стороны>

🔴 Ключевое ограничение: целевая сеть — локалка «внутренней» стороны (той, что держит reverse-соединение). Ходить reverse-каналом в сеть публичной стороны нельзя.

Пример конфига внутренней стороны (бридж) с разрешением в локалку:

{
  "protocol": "freedom",
  "tag": "home-lan",
  "settings": {
    "domainStrategy": "AsIs",
    "finalRules": [
      { "action": "allow", "network": "tcp,udp", "ip": ["192.168.1.0/24"] }
    ]
  }
}

И правило роутинга: { "inboundTag": ["reverse-in"], "outboundTag": "home-lan" }.

⚠️ finalRules применяется только если freedom — финальный outbound. Если у outbound задан sockopt.dialerProxy, freedom перестаёт быть финальным и finalRules не применяется (из доки).

Чем ЭТО обходится (а чем нет)

Способ Помогает?
finalRules: [{action:"allow", ip:[...]}] ✅ да — но только для локалки «внутренней» стороны
Смена версии Xray ❌ нет, это политика, не регрессия
allowForwardProxy в inbound ⚠️ относится к обычным proxy-inbound, не снимает reverse-политику
dokodemo-door / TPROXY / REDIRECT ❌ нет — меняет способ приёма трафика, не политику выпуска
Смена listen на 0.0.0.0 ❌ нет — влияет только на приём пакетов

⚠️ Не путать с issue #6612 / #6242 (регрессии версий, лечатся даунгрейдом/network_mode: host). Здесь другой класс: штатная политика безопасности, она есть во всех версиях.

Что делать, если нужен доступ в приватную сеть

  1. Определить, чья сеть «домашняя». Reverse пускает только в локалку стороны, держащей соединение. Если нужная сеть — на публичной стороне, reverse не подходит.
  2. Альтернативы для «полного IP-стека» (ICMP, UDP, broadcast/Samba-обзор):
    • WireGuard на узле с белым IP — даёт настоящий L3-VPN, всё проходит.
    • SOCKS-прокси на стороне клиента — только TCP, нужен SOCKS-aware клиент или routing на клиенте.
    • Прозрачный прокси на клиенте (TPROXY) — TCP; UDP требует отдельной работы.
  3. Reverse оставить для того, для чего он есть — egress через домашний канал (reverse-in → direct).

Сопутствующие питфоллы, найденные в той же сессии

  • dokodemo-door обязан слушать 0.0.0.0, не 127.0.0.1. При listen: 127.0.0.1 REDIRECT-трафик с внешнего адреса (клиент 192.168.1.57) не принимается — соединение отбивается мгновенно (HTTP 000 за ~0.005 с).
  • iptables -t nat PREROUTING НЕ действует на локально-исходящий трафик того же хоста. Тест curl-ом с самого узла, где стоит правило, всегда даст 000 и счётчик 0 — это ложный негатив. Проверять с постороннего хоста либо через ip netns (трафик станет транзитным).
  • redirect: "" в freedom невалидно — пустая строка ломает конфиг. Чтобы не менять адрес, использовать ":порт" (адрес не меняется) либо убрать поле целиком.
  • xray run -test читает stdin — под SSH без < /dev/null виснет.
  • sudo через SSH на Кра́кене требует < /dev/null — иначе Connection closed by remote host.

Связанные заметки