В современном мире вопрос VPN или прокси давно не про удобство. Это инженерная дисциплина управления поверхностью атаки, минимизации сигнатур, защиты от корреляции идентификаторов и оценки юрисдикционных рисков. Любая схема должна строиться как маленькая система OPSEC: что мы скрываем, от кого, какими средствами и какой ценой. Магии здесь нет — только грамотное планирование и понимание ограничений.
Далее я разбираю рабочую цепочку туннелирования, со своей колокольни, где Xray, Gluetun, и Docker работают как единая система.
Цель — снизить детектируемость, усложнить корреляцию трафика и изолировать выходную точку. Иллюзий абсолютной анонимности здесь нет: задача — повысить стоимость анализа и атак, а не стать сверх 'Анонимным'.
Псевдо double‑VPN
Эта схема — не чистый double‑hop вроде Tor, но и не иллюзия. Входной‑VPS видит исходный IP клиента, VPN‑Выход видит интернет‑трафик, но не знает о начальном клиенте.Прямой корреляции между ними нет без кооперации минимум двух юрисдикций.
Важно корректно понимать модель контроля. Формально цепочка не принадлежит одному юридическому субъекту: VPS‑хостинг, VPN‑провайдер и оператор находятся в разных странах. Однако логический контроль остаётся у оператора: он управляет VPS, выбирает VPN‑провайдера и контролирует клиент. Это не trustless‑модель, а модель разделения зон видимости.
Такая схема ломает привычные DPI‑сигнатуры, снижает репутационные риски IP и усложняет корреляцию. Но компрометация клиента или сервера VPS по‑прежнему ломает весь OPSEC. Тайминговая корреляция, утечки логов или ошибки конфигурации мгновенно уничтожают невидимость.
0. Принципиальный момент
Использование root как повседневного пользователя системы — одна из самых частых и самых дорогих ошибок. Root должен рассматриваться как аварийный режим, а не рабочая среда.
Любая уязвимость в Docker, x‑ui, Xray или вспомогательных скриптах, запущенных под root, автоматически превращается в полную компрометацию хоста. OPSEC логика здесь простая: если сервис взломан, он не должен мгновенно становиться root.
Поэтому вся эксплуатация — Docker, x‑ui, конфиги, обновления — выносится в отдельного пользователя. Root остаётся только для bootstrap и экстренных действий.
1. Подготовка хоста: базовая гигиена VPS
Выбираем образ Debian 12 в Европе. Никаких предустановленных панелей, "VPN‑скриптов" и авто‑харденинга от хостера. Каждый лишний пакет — потенциальная точка утечки, каждый сервис — коридор для lateral movement.
Обновляем систему:
Устанавливаем Docker и docker‑compose:
Docker здесь — не про удобство, а про контроль сетевых пространств, предсказуемость маршрутов и жёсткую привязку сервисов к VPN‑OUT.
1.1 Создание операционного пользователя
Создаём отдельного пользователя, под которым будет жить вся инфраструктура:
Всю дальнейшую работу ведём только под ops. Root‑логин по SSH отключается полностью. Это резко снижает радиус поражения при компрометации контейнера или панели.
2. UFW: минимизация сетевой поверхности
Firewall — первый OPSEC‑барьер. Не является надёжной защитой, но минимизирует вероятность ошибок настройки.
Разрешаем только необходимое:
Firewall здесь — страховка от случайного лишних пакетов из глобальной сети.
3. Fail2ban
Fail2ban убирает фоновый мусор и сканеры:
Минимальные jails:
Gluetun выполняет ключевую роль:
А регулярное обновление списка серверов с помощью встроенного функционала, снижает вероятность использования "мертвых" exit‑нодов, что в итоге ускоряет процесс рестарта и смены выходных нод.
Glue кстати,частенько любит поделать мозги с подключением к vpn, причины он и сам не всегда понимает.
Конечный docker-compose.yml
предполагается размещение в /home/ops/, а не в /root
Здесь мы используем несколько сервисов и каждый нужен в своей мере:
Кстати для удобства можем сделать следующие alias в .bashrc:
И обновить терминал:
Дальше нам нужно создать пару папок и файл, потому-что docker почему-то упорно пытается создать директорию вместо файла:
Выполняем через sudo, docker-демон работает от имени root,архитектурная особенность у него такая.
или:
5. SSH
SSH — критическая точка. Пароли исключены.
Генерация клиентского ключа:
Настройка сервера SSH:
/etc/ssh/sshd_config
Подключение клиента(Не забудьте скачать приватный ключ):
только потом:
На Host системе:
Port forwarding к панели x-ui(54321 пример порта):
TLS для x-ui не нужен, канал уже зашифрован через SSH.
6. Xray + x‑ui (VLESS + XHTTP + REALITY)
С помощью
смотрим на каком порту запустился наш x-ui.
И поскольку мы уже перезашли на сервер с port-forward через ssh, открываем в браузере: http://127.0.0.1:54321- admin:admin
Если уж совсем печетесь,то можете сгенерировать certs и подставить их в соответствующие настройки панели.
В данной схеме Xray используется исключительно как входная‑точка.
Его роль — принять клиентский трафик, замаскировать его под легитимный HTTPS и передать дальше, не оставляя артефактов, по которым DPI или пассивный наблюдатель может уверенно классифицировать соединение как прокси или VPN.
Кратко о настройке Inbound:
Inbound настраивается максимально скучно и реалистично. Любая "креативность" здесь работает против OPSEC.
Важно про IP и x-ui при использовании Gluetun
Из-за включённого FIREWALL=on в Gluetun и режима
контейнер x-ui полностью наследует сетевое пространство VPN-контейнера и не видит внешний IP хоста.
x-ui в такой схеме:
— не знает публичного IP VPS
— видит только loopback и интерфейсы Gluetun
— не способен корректно автоподставить IP в inbound / client config
При создании inbound - поле IP / Address нужно оставить пустым.
В итоге при генерации конфигураций и QR-кодов в x-ui:
— x-ui будет генерировать конфиг с 127.0.0.1
— это ожидаемое и корректное поведение в данной архитектуре
Как с этим работать
В клиентском приложении или перед отправкой URI:
— вручную заменяем 127.0.0.1 на реальный публичный IP или домен VPS
Все остальные параметры (UUID, REALITY-keys, SNI, transport) остаются без изменений
Опции Inbound:
Отдельно и принципиально:
один IP — один inbound — один протокол.
Несколько inboundов, fallbackов, резервных портов и на всякий случай:
Ресурсы:
Gluetun - WIKI
https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers
Далее я разбираю рабочую цепочку туннелирования, со своей колокольни, где Xray, Gluetun, и Docker работают как единая система.
Цель — снизить детектируемость, усложнить корреляцию трафика и изолировать выходную точку. Иллюзий абсолютной анонимности здесь нет: задача — повысить стоимость анализа и атак, а не стать сверх 'Анонимным'.
Псевдо double‑VPN
Эта схема — не чистый double‑hop вроде Tor, но и не иллюзия. Входной‑VPS видит исходный IP клиента, VPN‑Выход видит интернет‑трафик, но не знает о начальном клиенте.Прямой корреляции между ними нет без кооперации минимум двух юрисдикций.
Важно корректно понимать модель контроля. Формально цепочка не принадлежит одному юридическому субъекту: VPS‑хостинг, VPN‑провайдер и оператор находятся в разных странах. Однако логический контроль остаётся у оператора: он управляет VPS, выбирает VPN‑провайдера и контролирует клиент. Это не trustless‑модель, а модель разделения зон видимости.
Такая схема ломает привычные DPI‑сигнатуры, снижает репутационные риски IP и усложняет корреляцию. Но компрометация клиента или сервера VPS по‑прежнему ломает весь OPSEC. Тайминговая корреляция, утечки логов или ошибки конфигурации мгновенно уничтожают невидимость.
0. Принципиальный момент
Использование root как повседневного пользователя системы — одна из самых частых и самых дорогих ошибок. Root должен рассматриваться как аварийный режим, а не рабочая среда.
Любая уязвимость в Docker, x‑ui, Xray или вспомогательных скриптах, запущенных под root, автоматически превращается в полную компрометацию хоста. OPSEC логика здесь простая: если сервис взломан, он не должен мгновенно становиться root.
Поэтому вся эксплуатация — Docker, x‑ui, конфиги, обновления — выносится в отдельного пользователя. Root остаётся только для bootstrap и экстренных действий.
1. Подготовка хоста: базовая гигиена VPS
Выбираем образ Debian 12 в Европе. Никаких предустановленных панелей, "VPN‑скриптов" и авто‑харденинга от хостера. Каждый лишний пакет — потенциальная точка утечки, каждый сервис — коридор для lateral movement.
Обновляем систему:
Bash:
apt update && apt full-upgrade -y
Bash:
apt install -y sudo ufw docker.io docker-compose && systemctl enable docker
1.1 Создание операционного пользователя
Создаём отдельного пользователя, под которым будет жить вся инфраструктура:
Bash:
adduser ops
usermod -aG sudo,docker ops
newgrp docker
2. UFW: минимизация сетевой поверхности
Firewall — первый OPSEC‑барьер. Не является надёжной защитой, но минимизирует вероятность ошибок настройки.
Разрешаем только необходимое:
Bash:
ufw default deny incoming
Bash:
ufw default allow outgoing
Bash:
ufw allow 22 && ufw allow 443 && ufw allow 53 && ufw enable
3. Fail2ban
Fail2ban убирает фоновый мусор и сканеры:
Bash:
apt install -y fail2ban
systemctl enable fail2ban
systemctl start fail2ban
- SSH
- x‑ui (если панель вообще слушает порт наружу)
Gluetun выполняет ключевую роль:
- Поднимает VPN‑туннель
- Реализует killswitch на уровне iptables
- Контролирует DNS
- Изолирует сетевое пространство контейнеров
Bash:
Switzerland,Iceland,Finland,Czechia,Romania,Bulgaria,Serbia,Hungary,Slovenia,Australia
Glue кстати,частенько любит поделать мозги с подключением к vpn, причины он и сам не всегда понимает.
Конечный docker-compose.yml
предполагается размещение в /home/ops/, а не в /root
Код:
version: "2"
services:
gluetun-update:
image: qmcgaw/gluetun
command: update -enduser -providers ivpn
restart: "no"
deunhealth:
image: qmcgaw/deunhealth
container_name: deunhealth
network_mode: "none"
environment:
- LOG_LEVEL=info
- HEALTH_SERVER_ADDRESS=127.0.0.1:9999
- TZ=America/Montreal
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
gluetun:
image: qmcgaw/gluetun
depends_on:
- gluetun-update
labels:
- deunhealth.restart.on.unhealthy=true
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
- VPN_SERVICE_PROVIDER=ivpn
- OPENVPN_USER=USERNAME
- OPENVPN_PASSWORD=PASSWORD
- SERVER_COUNTRIES=Switzerland,Iceland,Finland,Czechia,Romania,Bulgaria,Serbia,Hungary,Slovenia,Australia
- FIREWALL=on
- FIREWALL_ALLOW_PORTS=443,54321
- BLOCK_MALICIOUS=on
- DOT=on
- DNS_ADDRESS=9.9.9.9
- TZ=Europe/Amsterdam
ports:
- 443:443
- 54321:54321
xui:
image: alireza7/x-ui
network_mode: "service:gluetun"
depends_on:
- gluetun
volumes:
- /home/ops/db:/etc/x-ui/
- /home/ops/xray_config/config.json:/app/bin/config.json
Здесь мы используем несколько сервисов и каждый нужен в своей мере:
- gluetun-update - обновляет списки серверов перед запуском одноименного сервиса.
- deunhealth - перезапускает gluetun, в случае падения по какой-либо причине, без необходимости перезапускать все.
- xui - соответственно наш VLESS маршрутка до VPS.
Кстати для удобства можем сделать следующие alias в .bashrc:
Bash:
alias stop='docker-compose down && docker-compose rm -f'
alias start='docker-compose up -d'
alias restart='stop && start'
alias status='docker-compose logs -f'
Bash:
source .bashrc
Выполняем через sudo, docker-демон работает от имени root,архитектурная особенность у него такая.
Bash:
sudo mkdir db && sudo mkdir gluetun && mkdir xray_config && touch xray_config/config.json
- db - будет лежать sqlite.db от x-ui.
- gluetun - servers.json для vpn провайдеров, создается сам при необходимости..
- xray_config - json с конфигом соответственно.
Bash:
docker-compose up -d
Bash:
start | restart
SSH — критическая точка. Пароли исключены.
Генерация клиентского ключа:
Bash:
ssh-keygen -f ~/client_key
Bash:
install -m 700 -d /home/ops/.ssh
Bash:
cat ~/client_key.pub >> /home/ops/.ssh/authorized_keys
Bash:
chmod 600 /home/ops/.ssh/authorized_keys
Bash:
chown -R ops:ops /home/ops/.ssh
/etc/ssh/sshd_config
Bash:
nano /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password
Bash:
sftp root@ip
get /home/ops/client_key
Bash:
systemctl restart sshd
Bash:
ssh -i ~/client_key ops@vps_ip
Bash:
ssh -i ~/client_key -L 54321:127.0.0.1:54321 ops@vps_ip
6. Xray + x‑ui (VLESS + XHTTP + REALITY)
С помощью
Bash:
docker logs root_xui_1
И поскольку мы уже перезашли на сервер с port-forward через ssh, открываем в браузере: http://127.0.0.1:54321- admin:admin
- Идем в настройки панели , авторизация и меняем пользователя и пароль.
-
- Там же в соседней вкладке, можем поменять panel path: "/", например: "ZHNhZHNha3Nha2Rsc2phZmtsYXM7amdsJ2thZ2phZGtsO2pka2w7c2FqZGtsYXM7bG"
- Открываем настройки xray, отключаем логирование полностью.
Если уж совсем печетесь,то можете сгенерировать certs и подставить их в соответствующие настройки панели.
В данной схеме Xray используется исключительно как входная‑точка.
Его роль — принять клиентский трафик, замаскировать его под легитимный HTTPS и передать дальше, не оставляя артефактов, по которым DPI или пассивный наблюдатель может уверенно классифицировать соединение как прокси или VPN.
- Связка VLESS + XHTTP + REALITY на 443‑м порту в 2026 году — это фактически минимальный набор, который ещё позволяет жить под агрессивным DPI без выделяющихся сигнатур.
- Отсутствие TLS‑сертификата на сервере означает, что нечего отзывать, анализировать или связывать с конкретным IP. Сервер не хранит private key и не участвует в PKI‑цепочке, что резко снижает след на стороне хоста.
- REALITY использует реальный TLS‑handshake к существующему домену, а не симуляцию. Для DPI это выглядит как обычное HTTPS‑соединение к популярному ресурсу, без "кривых" параметров ClientHello.
- XHTTP убирает артефакты WebSocket: нет Upgrade, нет характерных заголовков, нет долгоживущих соединений с неестественным паттерном. Трафик выглядит как обычные HTTP‑запросы поверх TLS.
Кратко о настройке Inbound:
Inbound настраивается максимально скучно и реалистично. Любая "креативность" здесь работает против OPSEC.
Важно про IP и x-ui при использовании Gluetun
Из-за включённого FIREWALL=on в Gluetun и режима
Bash:
network_mode: "service:gluetun"
x-ui в такой схеме:
— не знает публичного IP VPS
— видит только loopback и интерфейсы Gluetun
— не способен корректно автоподставить IP в inbound / client config
При создании inbound - поле IP / Address нужно оставить пустым.
В итоге при генерации конфигураций и QR-кодов в x-ui:
— x-ui будет генерировать конфиг с 127.0.0.1
— это ожидаемое и корректное поведение в данной архитектуре
Как с этим работать
В клиентском приложении или перед отправкой URI:
— вручную заменяем 127.0.0.1 на реальный публичный IP или домен VPS
Все остальные параметры (UUID, REALITY-keys, SNI, transport) остаются без изменений
Опции Inbound:
- Protocol: VLESS
- Port: 443
- Transmission / Transport:XHTTP
- XHTTP — ключевой момент. Он убирает WebSocket-артефакты (Upgrade, Connection, неестественные long-lived streams), которые давно используются DPI для классификации прокси. Трафик выглядит как серия обычных HTTPS-запросов с реалистичными таймингами.
- Security:REALITY
- REALITY не "шифрует TLS", а встраивается в реальный TLS-контур. Сервер не хранит сертификат, не участвует в PKI и не оставляет криптографический след, который можно отозвать, зафиксировать или связать с IP.
- Authentication:ml-kem-768
- Используется только если клиент поддерживает. Если клиент не поддерживает:
- — authentication → clear
- — иначе Get new keys
- ml-kem-768 не влияет на DPI видимость, он влияет исключительно на криптографическую стойкость сессии при перехвате.
- Host:st.ozone.ru (пример)
- Host должен строго совпадать с реальным HTTP-поведением домена. Никаких выдуманных путей или псевдо API, нехарактерных для ресурса.
- Path:/api (пример)
- Используется только если:
- — путь реально существует или выглядит типовым для выбранного домена
- — нет аномальных ответов
- — нет нестандартных размеров payload
- Слишком экзотический path — быстрый триггер эвристик.
- SNI:st.ozone.ru
- Обязан быть:
- — массовым
- — стабильным
- — реально используемым CDN / сервисом
- — с TLS-параметрами, соответствующими реальному ClientHello
- Dest:st.ozone.ru
- Dest и SNI должны совпадать.
- Любое расхождение SNI / Dest / Host — один из самых простых и надёжных DPI-индикаторов прокси-туннеля.
- uTLS:qq
- Профиль китайского QQ-браузера долгое время оставался "белым" даже под агрессивным DPI.
- Он не выглядит как Chrome/Firefox, но при этом массово встречается в реальном трафике, что снижает приоритет анализа.
- Private / Public keys:
- — Get new cert
- Ключи REALITY должны быть уникальны для каждого inbound и тем более сервера.
- Повторное использование ключей между серверами создаёт коррелируемый криптографический отпечаток.
- MLDSA-65 (seed / verify):
- Опционально. Используется для пост-квантовой подписи, если клиент поддерживает.
- Как и ml-kem:
- — не влияет на DPI
- — не маскирует трафик
- — повышает стойкость при долгосрочном перехвате
- Если клиент не поддерживает — отключается без потери OPSEC.
- Sniffing:off
- Sniffing в нашем сценарии:
- — не нужен
- — увеличивает объём логики
- — повышает риск артефактов
- — не даёт выигрыша в маскировке
- Sniffing оправдан только в сложных routing-сценариях, не в минималистичном транзите.
Отдельно и принципиально:
один IP — один inbound — один протокол.
- — формируют профиль сервера
- — увеличивают корреляцию
- — дают DPI больше статистики
- — упрощают активное зондирование
Ресурсы:
Gluetun - WIKI
https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers
Вложения
Последнее редактирование: