Я уже написал тут много статей на тему установки и настройки прокси‑серверов XRay с недетектируемыми протоколами Shadowsocks-2022, VLESS (с XTLS), и т. п. И один из очень часто поднимаемых в комментариях вопросов звучит так: можно ли с использованием XRay‑прокси как‑то организовать проброс портов или получать доступ к внутренностям корпоративной сети? Можно, и сейчас я расскажу как.
XRay поддерживает механизм под названием «reverse proxy», что в купе с богатыми возможностями настройки правил маршрутизации позволяет сделать довольно много интересных схем. Механизм в документации упомянут как «...in the testing phase» и «may have some issues», но я попробовал, и все работает.
Итак, что же можно сделать с помощью реверс‑проксирования?
Можно получать доступ к каким‑либо сервисам на хосте за NAT'ом или строгим фаерволом, и даже более того — можно получать доступ к сервисам на других устройствах в локальной сети, к которой имеет доступ этот самый хост за NAT'ом или файерволом.
Можно маршрутизировать весь (или некоторый в зависимости от настроенных правил) трафик на хост за NAT'ом или фаерволом и выпускать его оттуда в Интернет.
Например, вы проживаете за границей, хотите оплачивать счета за ЖКХ вашей недвижимости оставшейся России, но сервис оплаты не пускает вас с забугорных IP и не пускает вас с IP‑адресов даже российских VPS‑хостеров. Тогда можно поставить у кого‑нибудь из друзей или родственников в РФ преднастроенный роутер или одноплатник типа Raspberry Pi, который подключится к вашему прокси‑серверу, а вы, в свою очередь, через прокси‑сервер сможете достучаться до этого роутера/р‑пишки и выйти через него во внешний интернет как обычный пользователь, находящийся в России — и всем ресурсам будет виден IP‑адрес российского домашнего интернет‑провайдера.Можно обманывать тупые DPI, фильтрующие подключения по «белым спискам» в одну сторону. Например, от вас к серверу X подключиться нельзя (потому что его IP‑адрес забанен), а с сервера X к вам — можно (когда у вас есть белый IP‑адрес, пусть даже не статический, а с DynDNS). Тогда сделаем так, чтобы сервер X подключался к вам, а вы выходили через него в свободный интернет.
Можно выборочно пробрасывать порты, например, все подключения на 80 порт прокси‑сервера будут переадресовываться на 80 (или любой другой) порт «изолированного» хоста или еще куда‑то дальше.
Можно даже теоретически попробовать соорудить псевдо‑VPN, чтобы подключенные клиенты прокси‑сервера могли коммуницировать друг с другом.
Итак, поехали. Суть механизма reverse‑proxy проста. Есть у нас прокси‑сервер на каком‑нибудь VPS, доступный для всего интернета. Нам через него надо попасть на какой‑нибудь хост, который не доступен из всего интернета — например, он находится за NAT'ом без своего белого IP.
![](https://habrastorage.org/getpro/habr/upload_files/dae/53a/3bd/dae53a3bd344c7963a999475a090df04.png)
Решение простое: нужно сделать так, чтобы не сервер пытался достучаться до хоста (это невозможно), а хост первым подключился к серверу, а потом по уже установленному подключению запросы будут бегать в противоположном направлении. Это и есть reverse proxy.
Далее нужно разобраться с терминологией, которая используется в документации и конфигах XRay, потому что там все немного не очевидно и можно запутаться. Нужно знать и понимать три слова:
«client» — это клиент (логично, да), которому надо получить доступ куда‑то или выйти в Интернет;
«portal» — это ваш прокси‑сервер на VPS, связующее звено между client'ом и bridge'м;
«bridge» — это другой xray‑клиент, изолированный за NAT'ом и фаерволом, к которому надо получить доступ.
![- -](https://habrastorage.org/getpro/habr/upload_files/d21/ce0/aa7/d21ce0aa7930b4f0b293301dcba012fc.png)
Слово «bridge» может запутать, но скорее всего такое название разработчики решили использовать, потому что bridge является точкой соприкосновения внешнего интернета и ресурсов внутри сети - то есть финальной точкой назначения до которой мы хотим достучаться, может быть не сам bridge, а какие-то хосты в его локалке.
А теперь давайте разбираться, как это все настроить. Конфигурация reverse proxy описана в документации XRay: https://xtls.github.io/en/config/reverse.html, но описание довольно куцее. Еще есть гит-репа с примерами настройки реверс-прокси: https://github.com/XTLS/Xray-examples/blob/main/ReverseProxy/README.ENG.md
В качестве транспортного протокола может использоваться любой, который поддерживается XRay'ем. Я буду использовать в примерах для простоты обычный Shadowsocks, но ровно то же самое можно сделать и с VLESS, и с VLESS с Reality, и с VLESS через вебсокеты и CDN, и вообще как угодно — см. мои предыдущие статьи.
Начнем с настройки сервера ("portal")
{
"reverse": {
"portals": [
{
"tag": "portal",
"domain": "reverse.hellohabr.com"
}
]
},
"inbounds": [
{
"port": 5555,
"tag": "incoming",
"protocol": "shadowsocks",
"settings": {
"method": "2022-blake3-aes-128-gcm",
"password": "...",
"network": "tcp,udp"
}
}],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": ["incoming"],
"outboundTag": "portal"
}]
}
}
И давайте разбираться, что все это значит. В inbound у нас все как обычно — описание параметров для входящих соединений, простой shadowsocks. А вот дальше начинается интересное.
В начале конфига в секции «reverse» и объявляем один объект в массиве «portals», назначая ему тег «portal» и виртуальный домен «reverse.hellohabr.com». Этот домен именно виртуальный — он может не существовать, а правильнее сказать, он не должен быть каким‑то из реально существующих доменов. Он используется только для того, чтобы XRay понял, что конкретно вот этот входящий запрос (с таким доменом) — не что‑то, что нужно обработать как обычно и выпустить в интернет, а специальный запрос на установление соединения от bridge'а для того чтобы поднять reverse proxy.
Самое важное тут в routing — rules. Правило маршрутизации говорит о том, что все запросы, которые приходят от клиентов, нужно переадресовывать на reverse‑proxy (тег «portal»).
Естественно, если у нас другие пожелания, можно это правило маршрутизации немножко усложнить — например, переадресовывать на portal только запросы к определенным IP‑адресам (диапазонам IP‑адресов) или хостнеймам, а все остальное отправлять сразу в интернет (outbound «freedom»), или не пускать никуда (outbound «block»). Про правила маршрутизации можно почитать в документации XRay, плюс я еще немного касался этой темы в своем недавнем FAQ.
Дальше настраиваем «изолированного клиента» ("bridge")
{
"reverse": {
"bridges": [
{
"tag": "bridge",
"domain": "reverse.hellohabr.com"
}]
},
"outbounds": [
{
"protocol": "shadowsocks",
"settings": {
"servers": [{
"address": "....",
"port": 5555,
"method": "2022-blake3-aes-128-gcm",
"password": "...",
}]
},
"tag": "outgoing"
},
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": ["bridge"],
"domain": ["full:reverse.hellohabr.com"],
"outboundTag": "outgoing"
},
{
"type": "field",
"inboundTag": ["bridge"],
"outboundTag": "direct"
}]
}
}
В outbounds у нас тоже все просто — настройки подключения к серверу на VPS, который мы настроили в предыдущем шаге. Тоже есть секция «reverse», но на этот раз там объявлен объект «bridge» с тегом «bridge», и тем же виртуальным служебным хостнеймом, что мы задали для portal'а на предыдущем шаге — они должны совпадать.
А вот в routing‑rules у нас все чуть‑чуть сложнее. Первое правило определяет, как именно мы должны подключаться к нашему прокси на VPS (порталу) — мы говорим, что все подключения от bridge с виртуальным служебным адресом должны уходить на прокси через outbound, который мы описали чуть выше в этом же конфиге.
А второе правило определяет, что мы должны сделать с запросами, которые пришли к нам с прокси‑сервера (с портала). В данном случае мы сразу выпускаем их всех наружу. То есть если пунктом назначения в запросе будет IP‑адрес какого‑либо хоста в локальной сети, к которому подключен bridge, подключение будет установлено к этому хосту в локальной сети. Если пунктом назначения в запросе будет какой‑нибудь ресурс в публичности интернете — бридж установит соединение с ним и т. д. Также как и в прошлом пункте, эти правила можно кастомизировать под себя — например, выпускать на outbound «direct» только запросы к определенным IP‑адресам или хостнеймам, а все остальное отправлять в block, если мы не хотим, чтобы через нас лазили в интернет, а могли достучаться только до туда, до куда мы разрешили.
Готово!
В принципе, на этом настройка закончена. Когда вы запустите Xray на bridge, благодаря объявленному объекту «bridge» в конфиге, он инициирует и будет поддерживать специальное служебное подключение к прокси‑серверу.
Прокси‑сервер на вашем VPS, благодаря объекту «bridge» в конфиге, поймет, что это подключение — не обычно, а специальное служебное для reverse‑проксирования, и обработает его как надо.
Когда вы своим обычным клиентом (например, с мобильного телефона или десктопа) подключитесь к прокси‑серверу и попробуете подключиться через него к какому‑нибудь ресурсу, прокси (portal) следуя правилам, переадресует этот запрос на подключение на bridge, а bridge, в свою очередь, следуя своим правилам, выпустит этот вопрос в свою локальную сеть или в интернет.
Как я уже сказал ранее, вы можете настроить правила так, как надо вам — например, на вашем прокси на VPS отправлять на bridge только запросы к определенным IP‑адресам или доменам, а все остальное выпускать сразу в интернет и блокировать. Можно настроить несколько разных inbound's или несколько разных пользовательских ID в рамках одного inbound'а, и применять разные правила для разных пользователей. На самом bridge (хосте за NAT'ом) тоже можно применять разные правила — например, пропускать только запросы на определенные IP, а все остальное блокировать.
Про правила маршрутизации можно почитать в документации XRay, плюс я еще немного касался этой темы в своем недавнем FAQ.
Из того, что еще может оказаться полезным: в настройках outbound'а с протоколом «freedom» можно указывать конкретный сетевой интерфейс или IP‑адрес для исходящих подключений, и даже routing mark в Linux, чтобы разруливать доступ к локалке так, как нужно вам, см. документацию Xray для подробностей.
А если нужен проброс портов?
На базе описанных выше конфигов можно строить разные схемы — например, пробрасывать порты.
Допустим, нам нужно, чтобы все подключения к 80 порту portal'а переадресовывались на 80 порт bridge'а.
Добавим на portal'е специальный inbound и правило для него:
"inbounds":
[
....,
{
"tag": "web_server_forward",
"port": 80,
"protocol": "dokodemo-door",
"settings": {
"address": "127.0.0.1",
"port": 80,
"network": "tcp"
}
}
]
....
"routing": {
"rules": [
....,
{
"type": "field",
"inboundTag": ["web_server_forward"],
"outboundTag": "portal"
}
]
}
а и добавим соответствующие директивы на bridge:
"outbounds":
[
...,
{
"tag": "web_server_local",
"protocol": "freedom",
"settings": {
"redirect": "127.0.0.1:80"
}
}
]
...
"routing": {
"rules": [
...,
{
"type": "field",
"inboundTag": ["bridge"],
"outboundTag": "web_server_local"
}
]
}
После этого все запросы, пришедшие на 80 порт portal'а, будут переадресованы на 80 порт bridge'а через reverse‑прокси подключение.
Если ничего не работает
Если вы пытаетесь получить доступ к локальной сети через reverse proxy, но ничего не работает, и даже на сервере в логах не видно запросов, проверьте настройки клиента. Во многих клиентах по умолчанию запросы на «geoip:private» (то есть как минимум локальные IP‑адреса классов A, B и C) отправляются в block.
Так же не забываем, что есть основания предполагать, что в случае чего РКН будет блокировать вообще все неопознанные протоколы (и судя по всему, они уже это делали). Поэтому вместо Shadowsocks лучше использовать VLESS с TLS, см. предыдущие статьи.
Еще, из того, с чем столкнулся я: после настройки на bridge XRay запускался, но почему‑то не поднимал подключение к portal'у, и в логах была тишина. На portal же, при попытке сходить куда‑то через bridge, в логах были сообщение
v2ray.com/core/app/reverse: failed to process reverse connection > v2ray.com/core/app/reverse: empty worker list
означавшее, что portal‑то и не против сходить куда‑нибудь через bridge, вот только ни одного подходящего bridge'а к нему не подключилось. Я так и не понял, в чем было дело, в какой‑то момент я просто снес конфиг и переписал его заново более внимательно и все заработало.
При правильной настройке при попытке подключиться, на стороне portal в логах будет что‑то типа такого:
xray[1856216]: 11.11.11.11:10457 accepted 22.22.22.22:443 [incoming -> portal]
xray[1856216]: proxy/shadowsocks_2022: tunnelling request to tcp:reverse.hellohabr.com:0
xray[1856216]: app/dispatcher: taking detour [portal] for [tcp:reverse.hellohabr.com:0]
xray[1856216]: common/mux: dispatching request to udp:reverse.internal.v2fly.org:0
xray[1856216]: [33.33.33.33]:63786 accepted reverse.hellohabr.com:0 [incoming -> portal]
а на bridge:
xray[648852]: [Info] app/dispatcher: taking detour [outgoing] for [tcp:reverse.hellohabr.com:0]
xray[648852]: [Info] proxy/shadowsocks_2022: tunneling request to tcp:reverse.hellohabr.com:0 via 11.11.11.11:5555
xray[648852]: [Info] transport/internet/tcp: dialing TCP to tcp:[11.11.11.11]:5555
xray[648852]: [Info] common/mux: received request for udp:reverse.internal.v2fly.org:0
Псевдо-VPN?
Сообразительный читатель наверное догадается, что в теории таким образом можно даже сделать какое‑то подобие VPN. Если на каждом клиенте настроить и outbound до прокси и bridge, а на прокси для каждого клиента создать portal и соответствующие правила (например, выдумав набор виртуальных IP‑адресов и routing rules для них, типа подключения к 10.0.0.1 отправляй на этот портал, а к 10.0.0.2 на другой), то можно соорудить схему, когда клиенты смогут подключаться через прокси друг к другу. Скажу честно — я не пробовал. Может заработает, а может и нет. Если кто‑то попробует и получится — расскажите. Если не получится — тоже расскажите. Из явных минусов: конфиг будет страшный, и отлаживать все это дело будет непросто. Плюс на мобильных клиентах (да и в простых десктопных) bridge‑функционал просто так не настроить.
Поэтому в случае необходимости подобного, я бы предложил все‑таки использовать классические VPN‑протоколы, например, AmneziaWG, или OpenVPN завернутый в Cloak, или что‑то из TLS VPN, о которых я расскажу в следующей статье.
На этом всё.
Удачи, и да прибудет с вами сила.
Если вы хотите сказать спасибо автору — сделайте пожертвование в один из благотворительных фондов: "Подари жизнь", "Дом с маяком", "Антон тут рядом".