Загрузка...

Серверная часть: поднимаем собственный Xray/Sing-box за 15 минут

Знакомая картина: вы развернули современный клиент на базе ядра Xray или Sing-box (Happ, Nekoray, CLI-демон), включили заветный режим TUN, проверили браузер — всё летает, геолокация сменилась, заблокированные технические доки и репозитории открываются. Вы садитесь за привычные рабочие задачи, открываете терминал, и тут начинается инфраструктурный кошмар:

  • Локальные базы данных и микросервисы в docker-compose внезапно перестают отвечать на запросы из хостовой системы.
  • Команда docker pull зависает на первом же слое, упираясь в таймауты TLS-рукопожатий.
  • SSH-сессии к внутреннему серверу в подсети офиса или умного дома (192.168.10.x) бесследно дропаются.
  • Пакетные менеджеры, сборщики образов и консольный git ведут себя совершенно непредсказуемо.

Почему так происходит? Для операционной системы включение TUN — это не просто «поднятие прокси для браузера». Это фундаментальное перестроение системной таблицы маршрутизации ядра на сетевом уровне (L3 OSI).

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

1. Что на самом деле происходит в ядре Linux при включении TUN

Чтобы понять причину багов, взглянем на вывод утилиты ip route до и после включения TUN-режима. В штатном состоянии таблица маршрутов Linux предельно проста:

Bash

$ ip route show
default via 192.168.1.1 dev eth0 proto dhcp metric 100 
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.50 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 

Когда клиент (например, Xray TUN или встроенный драйвер в Sing-box) активирует режим туннелирования, в системе создается виртуальный интерфейс (tun0 или кастомный вроде happ-xray). Чтобы заставить абсолютно весь трафик идти через него, клиент выполняет один из двух маневров:

  1. Создает маршрут по умолчанию с наивысшим приоритетом: default dev happ-xray metric 1.
  2. Либо применяет классический трюк OpenVPN: разбивает маршрут 0.0.0.0/0 на две половинки: 0.0.0.0/1 и 128.0.0.0/1. По правилу Longest Prefix Match ядро всегда отдает приоритет более специфичной маске перед общим /0.

В этот момент сетевой стек переключается: любой сгенерированный локальным процессом пакет ядро пытается протолкнуть в сокет туннеля.

Корень проблемы: конфликт серых диапазонов

Клиенты вроде Xray и Sing-box работают в пользовательском пространстве (userspace). Они вычитывают raw-пакеты из виртуального интерфейса, разбирают заголовки TCP/UDP и по своим внутренним правилам (routing.rules) решают: выпустить пакет локально или завернуть в исходящий шифрованный туннель до внешнего VPS.

Если во внутренних правилах клиента нет строгих исключений для приватных сетей, пакет к 172.18.0.2 (ваш локальный контейнер с PostgreSQL или Redis) упаковывается в VLESS/Trojan и улетает на удаленный VPS в Нидерландах или Германии. Разумеется, удаленный сервер ничего не знает о вашей внутренней топологии и молча сбрасывает соединение.

2. Лечим изоляцию Docker-контейнеров

Демон Docker при создании сетей откусывает подсети из пространства 172.17.0.0/16 (дефолтный мост docker0) и динамически генерирует новые пулы 172.18.0.0/16, 172.19.0.0/16 под каждый запущенный docker-compose.yml.

Здесь кроется двойная опасность: если TUN-клиент случайно сам выбрал IP из диапазона 172.19.0.0/24, наступает жесткий конфликт на уровне ядра хоста — два интерфейса претендуют на один и тот же маршрут.

Шаг 1. Жесткая фиксация подсетей Docker

Первым делом заставим Docker брать адреса строго из заранее выделенного диапазона. Создаем или дополняем конфигурационный файл /etc/docker/daemon.json:

Bash
sudo nano /etc/docker/daemon.json

Вставляем блок конфигурации:

JSON

{
  "bip": "172.28.0.1/16",
  "default-address-pools": [
    {
      "base": "172.29.0.0/16",
      "size": 24
    }
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  }
}

Что здесь произошло: мы закрепили стандартный мост docker0 на адресе 172.28.0.1, а все сети из Compose-файлов загнали в диапазон 172.29.0.0/16 с 24-й маской (по 254 адреса на проект). Это исключает пересечение с адресами виртуальных туннелей (которые чаще всего занимают 172.19.x.x или 10.x.x.x).

Перезапускаем службу:

Bash

sudo systemctl restart docker

Шаг 2. Настройка Direct-роутинга для приватных IP в клиенте

Теперь убедимся, что ядро прокси никогда не шифрует пакеты, адресованные локальным серверам, роутерам и контейнерам. В конфигурацию ядра (блок routing в Xray или route в Sing-box) добавляем правило прямого выхода (direct):

JSON

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "outboundTag": "direct",
        "ip": [
          "geoip:private",
          "127.0.0.0/8",
          "10.0.0.0/8",
          "172.16.0.0/12",
          "192.168.0.0/16"
        ]
      }
    ]
  }
}

Важно: По стандарту RFC 1918 приватный класс B охватывает адреса от 172.16.0.0 до 172.31.255.255. Указание маски 172.16.0.0/12 одной строкой защищает любые bridge-сети Docker от попадания в прокси.

3. Проксирование самого Docker Daemon: решаем проблему docker pull

Частый сценарий: в браузере всё открывается, но попытка собрать проект или вытянуть базовый образ падает по таймауту:

Bash
$ docker pull golang:1.24-alpine
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded)

Причина: демон dockerd запускается системным менеджером systemd как изолированный процесс в собственном пространстве имен еще до старта пользовательских графических сессий. Если в системе активен TUN, резолв адресов реестров через локальные DNS-заглушки (например, systemd-resolved) внутри демона сбоит.

Самое надежное решение — явно указать демону локальный HTTP-прокси, который параллельно поднимает любой Xray-клиент (по умолчанию порт 10809).

  1. Создаем каталог переопределения юнита:
    Bash
    sudo mkdir -p /etc/systemd/system/docker.service.d
    sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf
    
  2. Прописываем переменные окружения:
    Ini, TOML
    [Service]
    Environment="HTTP_PROXY=http://127.0.0.1:10809"
    Environment="HTTPS_PROXY=http://127.0.0.1:10809"
    Environment="NO_PROXY=localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,.corp.local"
    
  3. Перезагружаем конфигурацию systemd и перезапускаем Docker:
    Bash
    sudo systemctl daemon-reload
    sudo systemctl restart docker
    
  4. Проверяем, подхватились ли параметры:
    Bash
    sudo systemctl show --property=Environment docker
    

Теперь скачивание манифестов и слоев через docker pull пойдет на полной скорости канала без подвисаний.

4. Git, SSH и корпоративные репозитории

Разработчики регулярно клонируют код с GitHub, GitLab или корпоративных серверов. При этом смешивать внешние и внутренние ресурсы в одну кучу нельзя.

Тонкая настройка Git по HTTPS

Не нужно прописывать глобальный http.proxy на всю систему — это сломает доступ к внутренним корпоративным серверам Git в локальной сети. Настройте проксирование точечно для нужных публичных хостингов:

Bash
# Заворачиваем только GitHub через локальный SOCKS5 (порт 10808)
git config --global http.https://github.com.proxy socks5h://127.0.0.1:10808
# Заворачиваем GitLab.com при необходимости
git config --global http.https://gitlab.com.proxy socks5h://127.0.0.1:10808

Обратите внимание на букву «h»: схема socks5h:// принципиально отличается от socks5://. Буква «h» заставляет клиент передавать доменное имя узла для резолва на стороне удаленного прокси-сервера. Если указать просто socks5://, резолв домена попытается выполниться локально, что может привести к ошибкам DNS.

Проброс Git по SSH через ProxyCommand

Если репозитории клонируются по SSH (git@github.com:...), настройки http.proxy игнорируются, так как трафик идет по 22-му порту.

Открываем клиентский файл конфигурации SSH:

Bash
nano ~/.ssh/config

И настраиваем автоматический проброс соединения через openbsd-netcat (пакет netcat-openbsd должен быть установлен в системе):

Фрагмент кода

# Подключение к GitHub через локальный SOCKS5
Host github.com
    User git
    Port 22
    ProxyCommand nc -X 5 -x 127.0.0.1:10808 %h %p
    ServerAliveInterval 30
    ServerAliveCountMax 5
# Корпоративный сервер пускаем напрямую
Host gitlab.mycompany.internal
    User git
    Port 22
    ProxyCommand none

Проверяем соединение:

Bash

$ ssh -T git@github.com
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

5. Удобный switch-скрипт для терминала (Bash/Zsh)

Что делать, если тяжелый системный TUN прямо сейчас не нужен, но требуется запустить curl, обновить пакеты через apt, скачать зависимости через pip, npm или composer?

Добавьте в конец файла ~/.bashrc или ~/.zshrc удобную обвязку из функций:

Bash
# --- Proxy Switcher Helpers ---
proxy_on() {
    local PROXY_HOST="127.0.0.1"
    local SOCKS_PORT="10808"
    local HTTP_PORT="10809"
    export http_proxy="http://${PROXY_HOST}:${HTTP_PORT}"
    export https_proxy="http://${PROXY_HOST}:${HTTP_PORT}"
    export ftp_proxy="http://${PROXY_HOST}:${HTTP_PORT}"
    export all_proxy="socks5h://${PROXY_HOST}:${SOCKS_PORT}"
    export no_proxy="localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.local"
    echo "[-] Terminal Proxy Activated"
    echo "[-] Checking outbound IP..."
    curl -s --connect-timeout 5 https://ipinfo.io/json | grep -E '"ip"|"country"|"org"'
}
proxy_off() {
    unset http_proxy https_proxy ftp_proxy all_proxy no_proxy
    echo "[x] Terminal Proxy Deactivated"
}

Применяем изменения в текущей сессии:

Bash
source ~/.bashrc  # или source ~/.zshrc

Теперь достаточно набрать в терминале proxy_on — консоль подхватит переменные и выведет внешний IP прокси. Команда proxy_off возвращает прямое соединение.

Требования к серверу: стабильность под нагрузкой

Рабочая станция разработчика генерирует принципиально иной паттерн трафика по сравнению со смартфоном: тысячи одновременных короткоживущих TCP-соединений при параллельной установке зависимостей, непрерывные потоки сборщиков артефактов и тяжелый обмен данными с удаленными стендами.

Если бэкенд развернут на перегруженном хостинге с шумными соседями, вы будете регулярно сталкиваться с дропами пакетов на этапе TLS-handshake.

Где хостить рабочий узел:

Для задач разработки критичны не столько терабайты диска, сколько низкий джиттер (стабильность пинга), честный гигабитный порт и отсутствие скрытого троттлинга по CPU. Отличную сетевую связность и гарантированные ресурсы предоставляет скоростной VPS от UFO Hosting — быстрое развертывание чистых ОС, поддержка актуальных ядер Linux и широкие каналы без ограничений отлично подходят для личного или командного шлюза разработчика.

Итоговый чеклист проверки рабочей станции

  1. Диапазоны сетей Docker зафиксированы в /etc/docker/daemon.json и не пересекаются с адресом TUN-адаптера.
  2. В клиенте (Xray / Sing-box) маска 172.16.0.0/12 добавлена в список правил со статусом direct.
  3. Для службы Docker настроен drop-in файл с параметрами локального HTTP-прокси.
  4. В файле ~/.ssh/config прописан ProxyCommand для хоста github.com с использованием socks5h://.
  5. Проверена доступность локальных баз данных и localhost при активном туннеле.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *