Как мы дали 10+ офисам единый российский IP, обошли корпоративные блокировки и сделали так, чтобы трафик был неотличим от обычного HTTPS.
У нас несколько офисов с роутерами Keenetic. Задача — дать всем устройствам единый выходной IP-адрес в России. Без этого не работает целый класс сервисов.
При этом настройка на стороне офиса должна быть минимальной — просто VPN-подключение на Keenetic. Никаких клиентских программ, никаких ручных конфигов на каждом компьютере.
Стандартные решения нас не устраивали по конкретным причинам:
WireGuard (UDP 51820)
OpenVPN
Готовые VPN-сервисы
Мы построили двухуровневую систему. Каждый уровень решает свою задачу и является независимым слоем.
Уровень 1 — Transport. Keenetic подключается к серверу-шлюзу по протоколу Cisco AnyConnect на порту 443. Это стандартный HTTPS-порт — заблокировать его невозможно без отключения всего интернета.
Уровень 2 — Proxying. На шлюзе весь трафик от роутеров перехватывается через механизм TPROXY ядра Linux и прозрачно уходит через xray в VLESS-туннель на выходной узел в России. VLESS маскируется под обычный TLS-трафик Chrome.
Когда устройство в офисе открывает любой сайт, вот полный путь пакета:
| Шаг 1 | Запрос с устройства (телефон, ноутбук) поступает на Keenetic роутер. |
| Шаг 2 | Keenetic отправляет трафик через OpenConnect туннель на сервер-шлюз. |
| Шаг 3 | На шлюзе iptables перехватывает пакет через механизм TPROXY и помечает его fwmark 0x1 — без изменения содержимого. |
| Шаг 4 | xray получает помеченные пакеты через TPROXY listener (порт 12345) и прозрачно проксирует через VLESS на выходной узел. |
| Шаг 5 | Выходной узел делает реальный запрос в интернет — его IP видят все сайты. |
| Шаг 6 | Ответ идёт обратно по той же цепочке. |
| ocserv | Открытая реализация Cisco AnyConnect сервера. Принимает подключения от Keenetic на порту 443 TCP+UDP. Keenetic имеет встроенную поддержку этого протокола — никаких доп. прошивок. |
| xray (TPROXY) | Работает в двух режимах одновременно: TPROXY listener на порту 12345 (прозрачно принимает трафик от клиентов) и VLESS outbound (отправляет трафик на выходной узел). |
| iptables (OCVPN) | Кастомная цепочка. Перехватывает весь трафик от OpenConnect клиентов (интерфейсы vpns+) и перенаправляет в xray через механизм TPROXY ядра Linux. |
| ip routing (fwmark) | Специальные правила маршрутизации: fwmark 0x1 → table 100 → local route on lo. Позволяют ядру доставлять помеченные TPROXY пакеты в сокет xray. Без этих правил TPROXY физически не работает. |
| tproxy-routing.service | Systemd-сервис, который восстанавливает ip rule/ip route после каждой перезагрузки сервера. Без него всё работает до первого reboot. |
Предварительные требования: чистый Debian 12, отдельный VPS с xray в режиме VLESS+TLS (выходной узел), root-доступ по SSH.
apt update && apt upgrade -y apt install -y curl wget iptables-persistent netfilter-persistent ocserv openssl
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
Создайте /usr/local/etc/xray/config.json. Два inbound: socks на 10808 для проверки + TPROXY на 12345 для реального трафика. VLESS outbound на выходной узел.
{
"inbounds": [
{
"tag": "socks-in", // для тестирования через curl
"port": 10808, "listen": "127.0.0.1",
"protocol": "socks"
},
{
"tag": "tproxy-in", // прозрачный прокси для офисного трафика
"port": 12345, "listen": "0.0.0.0",
"protocol": "dokodemo-door",
"settings": { "network": "tcp,udp", "followRedirect": true },
"streamSettings": { "sockopt": { "tproxy": "tproxy" } }
}
],
"outbounds": [
{
"tag": "vless-out",
"protocol": "vless",
"settings": { "vnext": [{
"address": "ВАШ_VLESS_ДОМЕН", "port": 443,
"users": [{ "id": "ВАШ_UUID", "encryption": "none" }]
}]},
"streamSettings": {
"network": "tcp", "security": "tls",
"tlsSettings": {
"serverName": "ВАШ_VLESS_ДОМЕН",
"fingerprint": "chrome" // маскировка под браузер
}
}
}
]
}
systemctl enable --now xray
Проверка VLESS (должен вернуть IP выходного узла, не IP шлюза):
curl -s --socks5 127.0.0.1:10808 https://api.ipify.org
# Самоподписанный сертификат mkdir -p /etc/ocserv/ssl && cd /etc/ocserv/ssl openssl req -x509 -newkey rsa:2048 -keyout server-key.pem -out server-cert.pem -days 3650 -nodes -subj "/CN=ВАШ_IP_СЕРВЕРА" # Создать пользователя ocpasswd -c /etc/ocserv/ocpasswd itfresh
auth = "plain[passwd=/etc/ocserv/ocpasswd]" tcp-port = 443 udp-port = 443 server-cert = /etc/ocserv/ssl/server-cert.pem server-key = /etc/ocserv/ssl/server-key.pem device = vpns ipv4-network = 192.168.8.0/24 dns = 8.8.8.8 route = default # Критично: исключить IP шлюза и VLESS-сервера из туннеля no-route = 155.212.159.202/255.255.255.255 no-route = 202.148.54.236/255.255.255.255 max-clients = 50 keepalive = 30 dpd = 60 systemctl enable --now ocserv
# Создать цепочку OCVPN iptables -t mangle -N OCVPN iptables -t mangle -A PREROUTING -i vpns+ -j OCVPN # Не трогать приватные адреса iptables -t mangle -A OCVPN -d 0.0.0.0/8 -j RETURN iptables -t mangle -A OCVPN -d 10.0.0.0/8 -j RETURN iptables -t mangle -A OCVPN -d 127.0.0.0/8 -j RETURN iptables -t mangle -A OCVPN -d 172.16.0.0/12 -j RETURN iptables -t mangle -A OCVPN -d 192.168.0.0/16 -j RETURN iptables -t mangle -A OCVPN -d ВАШ_VLESS_IP/32 -j RETURN # Направить в xray iptables -t mangle -A OCVPN -p tcp -j TPROXY --on-port 12345 --on-ip 0.0.0.0 --tproxy-mark 0x1 iptables -t mangle -A OCVPN -p udp -j TPROXY --on-port 12345 --on-ip 0.0.0.0 --tproxy-mark 0x1 # Борьба с фрагментацией MTU iptables -t mangle -A FORWARD -i vpns+ -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu netfilter-persistent save
Это правило позволяет ядру Linux доставить помеченные TPROXY пакеты в сокет xray. Без него клиенты подключаются, но интернет не работает.
ip rule add fwmark 0x1 table 100 ip route add local 0.0.0.0/0 dev lo table 100 # Проверка ip rule list | grep fwmark # 218: from all fwmark 0x1 lookup 100 ← должно быть так
Создайте systemd-сервис, который восстанавливает ip rule при каждой загрузке:
[Unit] Description=TPROXY IP routing rules for OpenConnect+VLESS After=network.target netfilter-persistent.service xray.service Requires=netfilter-persistent.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/bin/bash -c "ip rule add fwmark 0x1 table 100 2>/dev/null || true; ip route add local 0.0.0.0/0 dev lo table 100 2>/dev/null || true" ExecStop=/bin/bash -c "ip rule del fwmark 0x1 table 100 2>/dev/null || true; ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null || true" [Install] WantedBy=multi-user.target
systemctl daemon-reload systemctl enable --now tproxy-routing # Финальная проверка всех сервисов systemctl is-enabled ocserv xray tproxy-routing netfilter-persistent # → enabled enabled enabled enabled
Весь смысл архитектуры — в том, что на стороне офиса настройка занимает ровно 2 минуты:
| Интернет → VPN → Добавить | Тип подключения: Cisco AnyConnect |
| Сервер | 155.212.159.202 · Порт: 443 |
| Логин / Пароль | Указанные при создании пользователя через ocpasswd |
| Проверять сертификат | НЕТ — используется self-signed сертификат |
| Маршрутизация | «Использовать как шлюз по умолчанию» — ДА. Весь трафик офиса пойдёт через VPN. |
Живой трафик в логах xray выглядит так:
После перезагрузки клиенты подключаются, но интернет не работает
ip rule list | grep fwmark — если пусто, вот причина.systemctl start tproxy-routingtproxy-routing.service enabled.
Все клиенты разом отключились и не могут залогиниться
/etc/ocserv/ocpasswd изменился.journalctl -u ocserv | grep "failed authentication"ocpasswd -c /etc/ocserv/ocpasswd itfresh, затем systemctl restart ocserv.Петля маршрутизации: xray → VLESS → через VPN → xray → ...
ocserv.conf нет строки no-route для IP VLESS-сервера.no-route = ВАШ_VLESS_IP/255.255.255.255no-route = ВАШ_ШЛЮЗ_IP/255.255.255.255
Весь интернет-трафик из офисов выходит через российский IP 202.148.54.236. Соединение по порту 443/TCP неотличимо от обычного HTTPS. VLESS + TLS маскируется под Chrome браузер через fingerprint: chrome. При перезагрузке шлюза все четыре сервиса поднимаются автоматически.