Прошу помощи с настройкой реверс-прокси

Пользуюсь двумя серверами с 3X-UI – в РФ и за границей, уровень – чайник, без методички как без рук.

В прошлом году настроил реверс-прокси по вот этой статье, чтобы иностранный сервер сам устанавливал соединение с российским, а российский ходил через это соединение в интернет. Всё прекрасно работало, пока не вышло обновление ядра Xray (26.4.25), начиная с которого поддержка реверс-прокси через явно заданные объекты portal и bridge (как в статье) была убрана, сменившись на новый механизм VLESS reverse-proxy. Скорее всего, для 90% пользователей не составит никакого труда перенастроить свои legacy reverse proxy (как их сейчас называют разработчики Xray) на модный VLESS-вариант.

Проблема в том, что я не понимаю, что пишут в мануалах на вики-ресурсе Xray и в разных статьях на китайском, которые тут даже попадались. Ну, точнее, я могу по описанию понять какие-то тонкости настройки чего-то, о чём уже имею некое базовое представление. Но когда надо понять какую-то новую концепцию, нужна статья уровня почтенного Miracle с Хабра или пояснение от опытных гуру, а я никак не могу ни найти таких статей, ни добиться толку от доступных мне гуру в лице бесплатных ИИ )

Поэтому прошу здешних гуру доступно объяснить, как перенастроить legacy reverse-proxy на работу в режиме VLESS reverce-proxy. Или, может быть, всё-таки есть такая волшебная статья-методичка для чайников, тогда ткните в неё, пожалуйста, нос(ик)ом.

я не эксперт, но самое простое решение какое мне видится - это скачать релиз более старой версии и развернуть по гайду, что у тебя уже работал, зайди сюда и найди ту версию, что была. там есть как развернуть.

вот команда чтобы развернуть нужную версию: VERSION=v1.7.9 && bash <(curl -Ls “https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh”) $VERSION

Откатывать версию не безопасно, их не просто так обновляют! Ну по крайней мере старое и новое ядро одновременно в цепочке ВПС работает прям плохо, возможно будет когда-то и плохо между старой в серверной частью и новым в клиенте.

Я сейчас почитал, что то по теме реверс-прокси, есть ли прям преимущество? У всех впс белый ip. Или это сразу на случай бана по ip? Или ресурсы экономит?

Есть такая статья, тоже самое написано - устарело Обратный прокси | Project X

Устарело, потому что это старый механизм конфигурации. В доках есть инструкция, как поднять новый.

Обратный прокси может помочь, в случае если у тебя зарубежный VPS из сети хостера, который находится под 16 Кб блоком, и вы не хотите пробивать его с помощью zapret (или аналогичными программами) на стороне РФ VPS. Обычно 16 Кб блок работает только в одну сторону РФ → зарубеж, поэтому при подключении через реверс-прокси будет работать нормально. Я так пробивался к своему VPS у Hetzner.

я нашел баг в реверсивном прокси три недели назад BUG??? Reverse Proxy (Portal/Bridge) connection state desynchronization after restarts · XTLS/Xray-core · Discussion #5962 · GitHub

мысль была чтобы 99% всей логики оставить за бугром, тупо прокси-порты пробросить

Спасибо всем за мысли, отвечу на вопросы и изложу свои чайницкие соображения по пунктам:

  1. Насколько я понимаю, смысл реверс-прокси в первую очередь в проникновении за разные NAT-ы и прочие системы без внешнего белого IP. Но у меня цель не в этом, а именно в пробивании блока с противоположной стороны ) Legacy-вариант такую возможность давал, новый – пока непонятно.

  2. Мой иностранный хостер (racknerd) пока не блокируется из РФ, но я пытаюсь действовать на опережение – сейчас могут быстро вычислить и заблокировать как непосредственно выходной IP моего VPS (я принимаю меры для маскировки, но всем родственникам и знакомым по рукам не надавать), так и подсеть, активно используемую для VPN другими пользователями и сервисами.

  3. Сейчас я пока сижу на последних версиях 3X-UI и Xray, поддерживающих legacy reverce-proxy. Но понимаю, что эта тактика становится чем дальше, тем хуже, поэтому и пытаюсь сам разобраться в настройках, не дожидаясь статьи от почтенного Миракла или других сочувствующих чайникам гуру )

Спасибо, эту статью я видел, но тут мне как раз не хватает концептуального понимания – что делать, и вообще непонятно – будет ли эта схема работать так, как legacy. Поскольку авторы исходят из случая с домашней подсетью, мне с самого начала непонятно, мой случай – это “Ingress forwarding“, “Remote return home“ или что-то вообще другое, что они там описывают финальной фразой “Once you understand that, you can freely extend the model between “port mapping” and “remote roaming” according to your own needs.“

Этого самого understanding мне и не хватает, поэтому если кто-нибудь хотя бы скажет “свои настройки из bridge укажи там-то, а настройки из pottal там-то“, я уже буду бесконечно благодарен, ну и, может быть, есть и другие упершиеся в этот тупик, которым это тоже будет полезно. А уж понятное объяснение схемы в целом – это вообще мечта чайника )


:grin:

Как это работает: Схема скрытия зарубежного VPS

Ну давай разбираться вместе. У тебя есть забугорный VPS, на котором настроен VPN. Назовем его VPSEU. Ты хочешь, чтобы пользователи коннектились не напрямую к нему, а к другому VPS внутри РФ — назовем его VPSRU.

В такой связке раскрытие IP основного сервера (VPSEU) будет пофиг. Расходным материалом становится VPSRU: если его вдруг раскроют, мы его просто меняем.

Основные настройки всех инбаундов с пользователями и прочим лучше держать на VPSEU, чтобы легко и просто в случае чего поменять VPSRU с минимумом перенастроек. Логично?

Сценарий с маскировкой

Допустим, у тебя на VPSEU на порту 443 висит какой-нибудь REALITY. На 80 порту висит тот же сайт, что и на 443 REALITY — для полноты маскировки.

Тогда тебе нужно сделать Port Mapping — отобразить порты так, чтобы:

  • VPSRU:443VPSEU:443
  • VPSRU:80VPSEU:80

Это попадает под определение «Ingress forwarding»: удаленное отображение портов (remote port mapping), которое маппит публичный порт входа на удаленный внутренний веб-сервис.

Что мы делаем на VPSRU

На российском сервере (я хз, как это через панель, тут руками маленький конфиг):

{
  "inbounds": [
    {
      "listen": "::",
      "port": 8443,
      "protocol": "vless",
      "settings": {
        "clients": [
          {
            "id": "VPSEU-SERVER",
            "flow": "xtls-rprx-vision",
            "reverse": {
              "tag": "reverse-out"
            }
          }
        ]
      }
    },
    {
      "listen": "::",
      "port": "443,80",
      "protocol": "tunnel",
      "tag": "portal"
    }
  ],
  "routing": {
    "rules": [
      {
        "inboundTag": ["portal"],
        "outboundTag": "reverse-out"
      }
    ]
  },
  "outbounds": [
    {
      "protocol": "freedom"
    }
  ]
}

Что здесь имеем:
Порт 8443 — это порт, по которому VPSEU сервер будет коннектиться к нашему VPSRU серверу. Конкретные настройки (REALITY, просто TLS или вообще голый VLESS) на работу схемы не сказываются. Я бы сделал TLS с Vision и самоподписанным сертификатом, но смотри сам, как хочешь…

Есть волшебный инбаунд portal, который слушает на VPSRU порты 443 и 80 и «как есть» перенаправляет трафик через туннель, который открыл VPSEU в тот момент, когда подключился к нашему порту 8443.

Что имеем на VPSEU

{
  // Other forward-proxy-related configuration is omitted...
  "routing": {
    "rules": [
      {
        "ruleTag": "reverse-direct-rule",
        "inboundTag": ["reverse-in"],
        "outboundTag": "reverse-direct"
      }
    ]
  },
  "outbounds": [
    {
      "protocol": "freedom"
    },
    {
      "protocol": "freedom",
      "tag": "reverse-direct",
      "settings": {
        "redirect": "127.0.0.1:0",
        "finalRules": [
          {
            "action": "allow",
            "network": "tcp",
            "ip": "127.0.0.1",
            "port": "80,443"
          }
        ]
      }
    },
    {
      "protocol": "vless",
      "settings": {
        "address": "IP_OF_VPSRU",
        "port": 8443,
        "id": "VPSEU-SERVER",
        "flow": "xtls-rprx-vision",
        "reverse": {
          "tag": "reverse-in"
        }
      }
    }
  ]
}

Что это означает:
Правило reverse-direct-rule перенаправит всё, что прилетело с сервера VPSRU, на специальный аутбаунд reverse-direct. Этот аутбаунд перепишет адрес назначения на 127.0.0.1, но оставит порт назначения нетронутым. Финальное правило отрубит UDP и все порты, кроме 80 и 443.

Итого:
Все запросы, которые прилетают на порты 443 и 80 сервера VPSRU, оказываются на твоем забугорном VPSEU на локальном 127.0.0.1 на тех же портах. А там на 443 — твой REALITY, на 80 — тот же сайт для маскировки.

Вот описание проблемы и пошаговый алгоритм для проверки бага. Терминология заменена: VPSRU (вместо Portal) и VPSEU (вместо Bridge).


Проблема: Рассинхронизация состояний Reverse Proxy при перезагрузках

Модуль Reverse Proxy в Xray-core некорректно восстанавливает соединение, если один из серверов (VPSRU или VPSEU) перезагружается. Система входит в состояние «deadlock»: либо VPSRU удерживает устаревшие маппинги туннелей, либо VPSEU не может перерегистрироваться после перезагрузки VPSRU. Это приводит к «зависанию» соединений или ошибкам Empty reply from server. Проблема указывает на отсутствие механизмов самовосстановления (heartbeat или автоматической очистки пула туннелей).


Шаги для воспроизведения (Тест на стабильность туннеля)

Попробуй воспроизвести это у себя по следующим шагам:

  1. Исходное состояние: Запусти Xray сначала на VPSRU, затем на VPSEU.
  2. Проверка связи: Выполни запрос на VPSRU: curl 127.0.0.1:80.
  • Ожидаемый результат: Успех (получен ответ от веб-сервиса за VPSEU).
  1. Симуляция сбоя VPSEU: Убей процесс Xray на VPSEU. Снова запусти curl 127.0.0.1:80 на VPSRU.
  • Результат: Запрос висит (это нормально).
  1. Ошибка восстановления (Stale State): Снова запусти Xray на VPSEU.
  • Результат: Тот curl, который завис на шаге 3, продолжает висеть и не оживает.
  1. Призрачная сессия: Убей зависший curl и попробуй сделать новый запрос: curl 127.0.0.1:80.
  • Результат: Всё равно висит. (Баг: VPSRU не направляет новые запросы через переподключенный VPSEU).
  1. Рассинхронизация VPSRU: Останови curl. Перезапусти процесс Xray на VPSRU, при этом VPSEU пусть продолжает работать. Сделай curl 127.0.0.1:80 на VPSRU.
  • Результат: Ошибка curl: (52) Empty reply from server. (Баг: VPSEU не понимает, что сервер перезагрузился, и не пересоздает туннели).
  1. Полный сброс: Перезапусти Xray на VPSEU. Снова проверь curl на VPSRU.
  • Результат: Успех (связь восстановилась только после перезагрузки обоих узлов).

Что ожидается от системы

  • VPSRU должен инвалидировать или очищать старые туннели, когда тот же самый VPSEU (с тем же доменом) подключается заново.
  • VPSEU должен иметь механизм проверки связи (keep-alive/heartbeat), чтобы мгновенно перерегистрироваться, если VPSRU упал и поднялся.

Проверь, подтверждается ли у тебя такое поведение на последней версии ядра.

Это простейшая и максимально надежная альтернатива туннелям в Xray. Стандартный SSH умеет сам следить за состоянием сессии, а системные лимиты надежно вычищают «зависшие» порты.


Шаг 1: Подготовка ключей на VPSEU

Создаем пару ключей, чтобы VPSEU мог заходить на VPSRU без пароля.

ssh-keygen -t ed25519 -f ~/.ssh/id_tunnel -N ""

Шаг 2: Добавление ключа на VPSRU

Переносим публичный ключ на российский сервер.

ssh-copy-id -i ~/.ssh/id_tunnel.pub user@IP_OF_VPSRU

Если ssh-copy-id не срабатывает, просто скопируй содержимое id_tunnel.pub в файл /home/user/.ssh/authorized_keys на VPSRU.


Шаг 3: Настройка VPSRU (Разрешаем внешние порты)

Чтобы порты были доступны не только локально, но и из интернета, нужно разрешить GatewayPorts.

  1. Отредактируй конфиг: sudo nano /etc/ssh/sshd_config
  2. Установи параметр: GatewayPorts clientspecified (или yes).
  3. Перезапусти службу: sudo systemctl restart ssh

Шаг 4: Создание сервиса на VPSEU

Для автоматического подъема туннеля используем стандартный systemd. Мы добавим жесткие проверки (Keep-Alive), чтобы туннель не «зомбировался».

Создай файл: sudo nano /etc/systemd/system/vps-tunnel.service

[Unit]
Description=SSH Reverse Tunnel (80, 443)
After=network.target

[Service]
Type=simple
User=root
# Параметры:
# -N (не выполнять команды)
# -R [интерфейс_на_vpsru]:[порт_на_vpsru]:[хост_на_vpseu]:[порт_на_vpseu]
# ExitOnForwardFailure=yes (критично: если порт на RU занят, сервис упадет и рестартнется)
ExecStart=/usr/bin/ssh -i /root/.ssh/id_tunnel \
    -o "ServerAliveInterval 30" \
    -o "ServerAliveCountMax 3" \
    -o "ExitOnForwardFailure yes" \
    -o "StrictHostKeyChecking no" \
    -N \
    -R 0.0.0.0:80:127.0.0.1:80 \
    -R 0.0.0.0:443:127.0.0.1:443 \
    user@IP_OF_VPSRU

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target


Шаг 5: Контроль и проверка

Запускаем магию:

sudo systemctl daemon-reload
sudo systemctl enable vps-tunnel
sudo systemctl start vps-tunnel

Как проверить, что порты пробросились правильно:

  1. На VPSRU (проверка слушателя):
ss -tulpn | grep -E "80|443"

Должно быть написано LISTEN на адресе 0.0.0.0:80 (или *:80). Если там 127.0.0.1:80, значит GatewayPorts на VPSRU не применились.
2. На VPSEU (проверка статуса сервиса):

systemctl status vps-tunnel

Если видишь Active: active (running), значит туннель стабилен. Если постоянно restarting, смотри логи через journalctl -u vps-tunnel — скорее всего, порты 80/443 на российском сервере уже чем-то заняты (например, установленным там по ошибке nginx).

Спасибо, я долго пытался вникнуть и сам, и с помощью Gemini, и вообще не понял, для чего нужен аутбаунд reverse-direct на VPSEU – ведь запрос на создание канала (туннеля?) поступает от него по другому аутбаунду, который по порту 8443, без тэга. А на порты 443 и 80, которые использует аутбаунд reverse-direct, трафик должен приходить на VPSRU от пользователей, а не от VPSEU. В общем, пока у меня понимангия на прибавилось, а стало больше путаницы – я-то надеялся, что достаточно будет секций “reverse” с тэгом в инбаунде на VPSRU и в аутбаунде на VPSEU, и по этим тэгам уже маршрутизировать )

Ну ладно, пусть будет ещё одна пара VPSEU-аутбаунд (freedom) и VPSRU-инбаунд (tunnel), тогда, может быть, подскажете, на какие порты настроить эту пару в моём случае (где и 443, и 8443 уже задействованы), чтобы минимально поломать действующий конфиг? Поскольку сам я так и не уловил концепцию (

Вот содержательная часть конфига на VPSRU, клиент для реверс-прокси там входит в инбаунд inbound-443 (VLESS, xhttp, Reality), а обычные клиенты есть в обоих инбаундах – и inbound-443, и inbound-8443

{
…
  "inbounds": [
…
    {
      "listen": "0.0.0.0",
      "port": 443,
      "protocol": "vless",
…
      "tag": "inbound-443"
    },
    {
      "listen": "0.0.0.0",
      "port": 8443,
      "protocol": "vless",
…
      "tag": "inbound-8443"
    }
  ],
…
  "outbounds": [
…
  "reverse": {
    "portals": [
      {
        "domain": "reverse.ogorod",
        "tag": "portal"
      }
    ]
  },
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
…
      {
        "domain": [
          "full:reverse.ogorod"
        ],
        "inboundTag": [
          "inbound-443",
          "inbound-8443"
        ],
        "outboundTag": "portal",
        "type": "field"
      },
…
      {
        "domain": [
          "full:reverse.ogorod"
        ],
        "inboundTag": [],
        "outboundTag": "portal",
        "type": "field"
      },
…
      {
        "inboundTag": [
          "inbound-443",
          "inbound-8443"
        ],
        "outboundTag": "portal",
        "type": "field"
      }
    ]
  },
…
}

А вот на VPSEU:

{
…
  "outbounds": [
…
    {
…
      "tag": "Pumpkin",
…
    },
…
  ],
…
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
…
      {
        "outboundTag": "Pumpkin",
        "inboundTag": [
          "bridge"
        ],
        "domain": [
          "full:reverse.ogorod"
        ],
        "type": "field"
      },
…
    ],
…
  "reverse": {
    "bridges": [
      {
        "tag": "bridge",
        "domain": "reverse.ogorod"
      }
    ]
  },
…
}

Там ещё есть и дополнительная маршрутизация на VPSRU, и прямые инбаунды со своей маршрутизацией на VPSEU, но, насколько я понимаю, для того, чтобы разобраться с реверс-прокси, это всё лишнее.

в тех конфигах что я привел 8443 это аутбаунд по которому VPSEU соединяется с VPSRU. А reverse-direct это конечная точка назначения на которое попадает траффик с VPSRU по обратному туннелю.

у тебя старый формат и я не совсем понимаю что именно ты хочешь получить в результате. Если тебе нужно просто “зеркало” - клиент коннектится на 443 порт VPSRU а по факту оказывается на 443 порту VPSEU а там какой-нибудь REALITY то мой конфиг VPSRU уже достаточен… При этом VPSRU максимально “тупой и примитивный” - просто зеркало, он не занимается авторизацией или роутингом клиентов, он просто пропускает “как есть” поток до VPSEU.

Если же ты хочешь например обращения к RU-сайтам выполнять с VPSRU а остальное делегировать на VPSEU то есть VPSRU перестает быть глупым зеркалом то схема будет немного другая. Теперь обьясни нормально чего ты хочешь

Да, именно этого и хочу – сейчас клиенты обращаются к VPSRU, там происходит их авторизация и маршрутизация трафика на российские сайты, а остальной трафик маршрутизируется на VPSEU через реверс-прокси. При этом на VPSEU есть и свои клиенты, не зависящие от VPSRU, для них отдельная маршрутизация. Вот эту схему и хотелось бы сохранить с новым реверс-прокси, если это, конечно, возможно.

VPSRU

ОК, на VPSRU для VPSEU указываешь

   "reverse": {
              "tag": "reverse-out"
            }

удаляешь старый синтаксис:

"reverse": {
    "portals": [
      {
        "domain": "reverse.ogorod",
        "tag": "portal"
      }
    ]
  },

вместо вот этих правил

      {
        "domain": [
          "full:reverse.ogorod"
        ],
        "inboundTag": [
          "inbound-443",
          "inbound-8443"
        ],
        "outboundTag": "portal",
        "type": "field"
      },
…
      {
        "domain": [
          "full:reverse.ogorod"
        ],
        "inboundTag": [],
        "outboundTag": "portal",
        "type": "field"
      },
…
      {
        "inboundTag": [
          "inbound-443",
          "inbound-8443"
        ],
        "outboundTag": "portal",
        "type": "field"
      }

считай что у тебя есть outbound с именем “reverse-out” и заруливаешь в него все что тебе надо по любым правилам например

{
        "domain": [
          "full:youtube.com"
        ],
      
        "outboundTag": "reverse-out",
        "type": "field"
      },

VPSEU

удаляешь старый синтаксис

  "reverse": {
    "bridges": [
      {
        "tag": "bridge",
        "domain": "reverse.ogorod"
      }
    ]
  },

в аутбоунд который цепляется к VPSRU добавляешь

 "reverse": {
          "tag": "reverse-in"
        }

считай что у тебя есть inbound с именем “reverse-in” из него прилетает все от VPSRU

  "rules": [
…
      {
        "outboundTag": "Pumpkin",
        "inboundTag": [
          "reverse-in"
        ],
        "type": "field"
      },
…
    ],

Важное замечание!

Если ты будешь выходить на русские сайты с IP своего VPSRU тебя забанят. Всякие яндексы по дианазону IP поймут что хоть и РФ но адрес принадлежит подсети хостера. В данном случае я бы наоборот везде выходил бы с заграничного чтобы ничего не мешало бы коннектится с РФ

Я там выхожу не напрямую, а через WARP – он пока работает, и через него по крайней мере пускают к себе те сервисы, которые не пускают из-за границы.

С реверс-прокси теперь вроде всё понятно, осталось добраться до экспериментальной проверки, огромное спасибо )