Материал предназначен для администрирования собственных устройств, корпоративного доступа и диагностики сетей. В России и других странах соблюдайте местные законы, правила работодателя и требования провайдера. Не используйте раздельное туннелирование для обхода блокировок, запретов, фильтрации и иных ограничений.
Раздельное туннелирование на Windows решает вполне приземлённую задачу: часть трафика уходит в VPN, а часть остаётся на обычном подключении. Обычно такой режим нужен не ради красивой галочки в настройках, а когда корпоративные подсети должны идти через туннель, а обычный веб, видеосвязь, обновления или локальные сервисы лучше не тащить туда же.
На практике есть два рабочих подхода. Первый, через графический клиент VPN, быстрее и проще, но часто скрывает детали и ломается в неожиданных местах. Второй, через таблицу маршрутизации Windows, требует больше аккуратности, зато даёт предсказуемый результат и нормально документируется. Для WireGuard на Windows есть ещё удобный промежуточный вариант: использовать AllowedIPs как фильтр маршрутов.
Как работает раздельное туннелирование в Windows на самом деле
Сразу поправлю термин. Windows работает не с «postfix-маршрутами», а с маршрутами по префиксу. Система сначала ищет самое точное совпадение по адресу назначения, а уже потом смотрит на метрику. Поэтому маршрут для одного узла с маской /32 всегда важнее маршрута для подсети /24, а маршрут для подсети, в свою очередь, важнее дефолтного 0.0.0.0/0. Именно на этой логике и держится всё раздельное туннелирование.
Из-за этого split tunneling в Windows почти всегда сводится к одному вопросу: какие IP-префиксы должны идти в VPN, а какие должны обходить туннель. Дальше уже выбирается инструмент. Графический клиент пытается решить задачу за вас. Таблица маршрутизации решает задачу прямо и без догадок.
| Подход | Где удобен | Слабое место |
|---|---|---|
| Графический клиент VPN | Быстро включить режим по приложениям или по списку сетей | Логику маршрутизации трудно проверить, исключения по приложениям часто неполные |
| Ручные маршруты Windows | Повторяемая настройка, аудит, точный контроль | Нужно понимать шлюз, интерфейс и префиксы |
| WireGuard AllowedIPs | Чистая и понятная схема для туннеля на Windows | Маршрутизация идёт по IP, а не по доменам и не по программам |
Подход 1. Раздельное туннелирование через графический клиент VPN
Если клиент умеет исключать приложения или подсети, начать можно с него. Такой путь подходит для домашнего сценария, где нужно, например, оставить браузер в обычном интернете, а рабочий доступ в офис пустить через VPN. Удобство здесь очевидное: не надо руками трогать маршруты, интерфейсы и метрики.
Но у такого режима есть слабые места. Windows маршрутизирует трафик по IP, а не по названиям программ. Поэтому клиенту приходится добавлять дополнительную логику поверх системы. Из-за этого браузер может пойти мимо VPN, а его вспомогательный процесс, обновлятор, встроенный DNS-over-HTTPS или отдельный модуль видеозвонков уже нет. В результате пользователь видит «режим включён», а трафик живёт своей жизнью.
Поэтому графический клиент хорош для быстрых сценариев и тестов. Для рабочих станций, документации, техподдержки и предсказуемого поведения обычно надёжнее маршрутный подход.
Подход 2. Ручная настройка через таблицу маршрутизации Windows
Здесь Windows ведёт себя честно и прозрачно. Команда route показывает таблицу маршрутов, позволяет добавлять постоянные записи и указывать интерфейс вручную. А если нужен более удобный вид на ту же таблицу, подойдёт netstat -r.
Логика такая. VPN обычно подменяет дефолтный маршрут или добавляет собственные префиксы. Если нужно, чтобы конкретная подсеть или один узел шли в обход VPN, надо добавить более специфичный маршрут через обычный шлюз, то есть через ваш локальный роутер или корпоративный выход без туннеля.
Сначала смотрим, что уже есть
route print
netstat -r
В выводе нужны две вещи: индекс обычного сетевого интерфейса и IPv4-шлюз для прямого выхода. Чаще всего речь про Wi-Fi или Ethernet, а не про VPN-адаптер.
Примеры ручных маршрутов
Пусть локальный шлюз равен 192.168.1.1, а индекс обычного интерфейса равен 15. Тогда подсеть 203.0.113.0/24 можно пустить мимо VPN так:
route -p add 203.0.113.0 mask 255.255.255.0 192.168.1.1 if 15
Если нужен обход для одного конкретного узла, используйте хост-маршрут с маской 255.255.255.255:
route -p add 198.51.100.42 mask 255.255.255.255 192.168.1.1 if 15
Ключ -p делает маршрут постоянным, то есть запись переживёт перезагрузку. Удаление простое:
route delete 203.0.113.0
route delete 198.51.100.42
Важный нюанс. Раздельное туннелирование по домену Windows из коробки не умеет. Windows маршрутизирует по IP-адресам. Сегодня домен резолвится в один адрес, завтра в другой, а послезавтра уедет на узел CDN в другой подсети. Поэтому для сервисов за CDN ручные маршруты по IP быстро превращаются в хрупкую конструкцию. Для таких задач иногда удобнее клиент с исключением по приложению, а не по адресу.
Где ручной маршрут реально выигрывает
Ручной метод особенно хорош, когда префиксы стабильны. Классический пример, доступ к офисной сети 10.50.0.0/16 через VPN, а весь остальной интернет напрямую. Или доступ к одной внутренней системе с фиксированным адресом. В таких случаях вы точно знаете, что должно уйти в туннель, и можете проверить правило одной командой.
Ручной метод плох там, где набор адресов постоянно гуляет. Публичные SaaS-платформы, видеосервисы, облака за балансировщиками, CDN и сервисы с агрессивным anycast быстро ломают идею «добавлю пару IP и всё заработает». В таком сценарии лучше не обещать себе лишнюю точность.
WireGuard на Windows: AllowedIPs как фильтр маршрутов
Для WireGuard на Windows схема обычно получается чище. Клиент сам берёт AllowedIPs из конфигурации и превращает их в маршруты для интерфейса. На уровне логики AllowedIPs работают как таблица выбора пути для исходящих пакетов и как список допустимых адресов для входящих. В документации WireGuard для Windows отдельно указано, что сервис добавляет маршруты на основе AllowedIPs.
Проще говоря, если вам нужен split tunnel, не ставьте туда 0.0.0.0/0 и ::/0 без необходимости. Перечислите только те подсети и узлы, которые действительно должны идти через туннель.
Пример конфигурации WireGuard для split tunnel
[Interface]
PrivateKey = ...
Address = 10.14.0.2/32
DNS = 10.14.0.53
[Peer]
PublicKey = ...
Endpoint = vpn.example.com:51820
AllowedIPs = 10.20.0.0/16, 10.30.40.12/32, 192.168.200.0/24
PersistentKeepalive = 25
В такой конфигурации через туннель пойдут только три указанных префикса. Обычный веб, обновления Windows и остальной трафик останутся на прямом канале.
Если же в AllowedIPs указать 0.0.0.0/0, ::/0, получится уже full tunnel. Для Windows у WireGuard здесь есть ещё один нюанс: при наличии /0 клиент включает более жёсткие правила и отдельное поведение для DNS. Поэтому переход между full tunnel и split tunnel меняет не только маршрутную схему, но и то, как система ведёт себя при сбоях и утечках.
Ещё один неочевидный момент связан с DNS. Если в секции [Interface] указать внутренний DNS-сервер компании, например 10.14.0.53, Windows может начать резолвить имена через него. Для внутренней зоны такое поведение нормальное и даже полезное. Но если вы ожидали, что публичные домены останутся на обычном DNS провайдера, настройку надо проверять отдельно, а не надеяться на интуицию.
PowerShell-скрипт для добавления и удаления маршрутов
Если команду route add нужно гонять регулярно, удобнее завернуть её в PowerShell. Ниже скрипт, который работает с обычным интерфейсом, сам забирает его шлюз и умеет показывать, добавлять и удалять маршруты. Запускать лучше из повышенной консоли.
param(
[ValidateSet("Show","Add","Remove")]
[string]$Action = "Show",
[string]$InterfaceAlias = "Wi-Fi",
[string[]]$Prefixes = @(
"203.0.113.0/24",
"198.51.100.42/32"
)
)
$cfg = Get-NetIPConfiguration -InterfaceAlias $InterfaceAlias
if (-not $cfg) {
throw "Интерфейс не найден: $InterfaceAlias"
}
$ifIndex = $cfg.InterfaceIndex
$nextHop = $cfg.IPv4DefaultGateway.NextHop
if (-not $nextHop) {
throw "У интерфейса $InterfaceAlias нет IPv4-шлюза"
}
switch ($Action) {
"Show" {
Get-NetRoute -InterfaceIndex $ifIndex -AddressFamily IPv4 |
Sort-Object DestinationPrefix |
Format-Table DestinationPrefix, NextHop, RouteMetric, InterfaceIndex, PolicyStore
}
"Add" {
foreach ($prefix in $Prefixes) {
$exists = Get-NetRoute -DestinationPrefix $prefix -InterfaceIndex $ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue
if (-not $exists) {
New-NetRoute -DestinationPrefix $prefix -InterfaceIndex $ifIndex -NextHop $nextHop -PolicyStore PersistentStore | Out-Null
Write-Host "Добавлен маршрут $prefix через $nextHop, ifIndex $ifIndex"
} else {
Write-Host "Маршрут уже существует: $prefix"
}
}
}
"Remove" {
foreach ($prefix in $Prefixes) {
Get-NetRoute -DestinationPrefix $prefix -InterfaceIndex $ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue |
Remove-NetRoute -Confirm:$false
Write-Host "Удалён маршрут $prefix"
}
}
}
Смысл параметра InterfaceAlias простой: туда нужно подставить обычный сетевой интерфейс, через который должен идти трафик в обход VPN. Чаще всего это Wi-Fi или Ethernet, а не туннельный адаптер. Если подставить VPN-интерфейс, получится обратный результат.
Как проверить, что split tunnel действительно работает
Проверка нужна обязательно. Визуально всё может выглядеть правильно, а по факту один сервис уже идёт мимо туннеля, а второй ещё сидит внутри него.
1. Проверка таблицы маршрутов
route print
netstat -r
Ищите нужный префикс, нужный шлюз и нужный интерфейс. Если маршрут для конкретного узла или подсети есть, но идёт через VPN-адаптер, цель вы не достигли.
2. Проверка пути пакета через tracert
tracert -d 198.51.100.42
tracert -d 10.30.40.12
Ключ -d отключает обратный DNS и делает вывод чище. Если трафик должен обходить VPN, первым заметным прыжком обычно будет локальный шлюз. Если маршрут должен идти через туннель, картина будет другой. Полного идеала тут нет, потому что часть узлов не отвечает на ICMP, но для грубой проверки команда полезна.
3. Проверка активных соединений через netstat
netstat -ano
netstat -ano | findstr ESTABLISHED
Эта команда показывает активные соединения и PID процессов. Когда нужно понять, какой процесс реально открыл соединение и на какой адрес, netstat помогает быстро отделить догадки от фактов. Особенно полезно, если графический клиент обещал исключение по приложению, а вы хотите увидеть реальную картину.
4. Проверка DNS через nslookup
nslookup example.com
nslookup corp.internal 10.14.0.53
Первый запрос показывает, какой DNS-сервер Windows использует по умолчанию. Второй проверяет конкретный внутренний резолвер. Такой тест полезен для быстрой диагностики утечки DNS, но тут важно не переоценивать возможности команды. nslookup проверяет именно системный резолв, а не поведение всех приложений. Браузер с DNS-over-HTTPS, клиент мессенджера или корпоративный агент могут резолвить имена вообще по своим правилам.
Из-за этого нормальная проверка выглядит так: сначала смотрите системный DNS через nslookup, потом путь трафика через tracert, а затем подтверждаете реальным соединением через netstat. Только связка этих трёх шагов даёт внятную картину.
Частые ошибки, из-за которых настройка выглядит правильной, но работает криво
- Маршрут добавили не через тот интерфейс. Вместо Wi-Fi указали VPN-адаптер.
- Исключение сделали по домену в голове, а Windows живёт по IP-адресам.
- У сервиса адреса меняются, а маршрут добавлен для вчерашнего IP.
- В WireGuard оставили
0.0.0.0/0, а потом удивились, что получился full tunnel. - Проверили только веб-сайт в браузере и не заметили, что DNS или фоновые процессы пошли другой дорогой.
- VPN-клиент включает kill switch или фильтры на уровне брандмауэра, поэтому один лишь маршрут уже не способен переиграть политику клиента.
Что выбрать в реальной жизни
Если задача домашняя и нужно быстро разделить трафик по программам, разумно начать с графического клиента. Если задача рабочая, нужна повторяемость, понятная схема и возможность быстро разбираться в сбоях, лучше идти в маршруты или сразу в WireGuard с аккуратно заполненным AllowedIPs.
WireGuard на Windows особенно удобен там, где вы точно знаете список внутренних подсетей. Тогда конфигурация получается короткой, а логика прозрачно читается даже через месяц. Ручные маршруты Windows хороши как универсальный инструмент, когда клиент ничего удобного не умеет или когда нужно тонко обойти отдельные сети мимо уже поднятого туннеля.
Практический вывод по настройке split tunneling на Windows
Самый надёжный путь на Windows выглядит так. Сначала решаете, делите ли трафик по приложениям или по IP-префиксам. Если по префиксам, сразу идите в маршрутную логику. Для WireGuard перечисляйте только нужные подсети в AllowedIPs. Для универсального сценария используйте route -p add или PowerShell с постоянными маршрутами. После настройки всегда проверяйте результат не одной командой, а связкой route print, tracert, netstat и nslookup. Иначе легко получить красивую конфигурацию, которая на деле разделяет трафик совсем не там, где вы планировали.
FAQ по раздельному туннелированию на Windows
Можно ли настроить split tunnel в Windows по домену, а не по IP?
Штатная маршрутизация Windows работает по IP-префиксам. По домену задачу решают либо VPN-клиенты со своей логикой, либо дополнительные корпоративные инструменты, но не таблица маршрутов сама по себе.
Что лучше для WireGuard, AllowedIPs или ручные route add?
Если трафик должен делиться в рамках самого туннеля WireGuard, обычно удобнее AllowedIPs. Если нужно поверх уже работающего VPN тонко перекинуть часть сетей в обход, ручные маршруты Windows дают больше контроля.
Почему сайт всё равно идёт через VPN, хотя маршрут добавлен?
Частая причина, у сервиса изменился IP, адрес сидит за CDN или клиент VPN жёстко фильтрует трафик на уровне брандмауэра. Ещё одна причина, маршрут добавили через неправильный интерфейс.
nslookup достаточно, чтобы проверить утечки DNS?
Нет. nslookup показывает только системный резолв. Для нормальной проверки надо смотреть и сам DNS, и путь пакета, и реальные соединения приложений.
Нужны ли права администратора для route add и PowerShell-маршрутов?
Да, в типовом сценарии нужны. Без повышенной консоли добавление и удаление маршрутов обычно не сработает.