Шейпинг исходящего трафика для TCP порта в Windows
Содержание
Шейпинг трафика для TCP-сервиса на Windows через WSL2
Инструкция описывает, как ограничить исходящую полосу пропускания для TCP-сервиса, работающего на Windows, по гео-принадлежности IP-адреса клиента (страны) - напрямую внутри WSL2.
Описание
Внутри WSL2 (полноценное Linux-окружение на базе настоящего Linux-ядра) напрямую ставятся nftables + tc/HTB и HAProxy (TCP-прокси до реального Windows-приложения).
Схема:
Клиенты → [ WSL2: HAProxy + nftables/tc ] → Windows-приложение (реальный IP хоста : внутренний порт)
Скрипт при каждом запуске сам:
- ставит недостающие зависимости (
nftables iproute2 curl unzip gawk haproxy) через apt; - определяет сетевой интерфейс WSL2 и IP Windows-хоста автоматически (через
ip route) - руками ничего искать не нужно; - качает/обновляет базу MaxMind GeoLite2-Country и строит классификацию по странам;
- генерирует и проверяет конфиг HAProxy;
- поднимает HAProxy (через systemd, если он уже активен в этой WSL-сессии, либо напрямую - если ещё нет);
- устанавливает себя и systemd-юнит для автоматического переприменения правил после каждого перезапуска WSL2;
- включает
systemd=trueв/etc/wsl.conf, если его там ещё нет; - по возможности сам регистрирует задачу в Планировщике Windows, чтобы WSL2 поднималась при старте Windows без входа пользователя.
Требования
- Windows 10 (2004+, сборка 19041+), Windows 11, либо Windows Server 2022/2025 с редакцией Desktop Experience.
- Права администратора.
- На части конфигураций Windows Server 2022 одной команды
wsl --installнедостаточно - см. раздел ниже "Если свежие образы Ubuntu не отображаются в списке".
Установка WSL2
В PowerShell от администратора:
wsl --install -d Ubuntu-24.04
Команда сама включает нужные компоненты Windows, скачивает ядро WSL2 и разворачивает Ubuntu. Если попросит перезагрузку - перезагружаемся, затем запускаем Ubuntu из меню Пуск.
Первый вход: имя пользователя и пароль
При первом запуске установленного дистрибутива WSL попросит задать имя пользователя и пароль для Linux-окружения (это отдельные учётные данные, никак не связанные с учёткой Windows):
- Имя "admin" использовать нельзя - оно уже зарезервировано/автоматически подставляется самим WSL, система откажет с ошибкой, что оно занято. Используйте любое другое имя.
- Пароль - любой, он нужен только для
sudoвнутри этого Linux-окружения.
Скрипт geo-shaper-wsl.sh должен запускаться от root, поэтому сразу после создания пользователя и входа под ним выполните:
sudo su cd
(sudo su переключает в root, cd без аргументов переводит в домашнюю директорию root - туда же можно скачать и запускать скрипт)
Если свежие образы Ubuntu не отображаются в списке (Windows Server 2022)
На части установок Windows Server 2022 команда wsl --install -d Ubuntu-24.04 не находит такой дистрибутив, а wsl --list --online показывает только старые образы (например, обычную "Ubuntu", то есть 20.04) - свежих версий в списке ещё нет, пока WSL и компоненты Windows не обновлены полностью. Рабочая последовательность:
- Установить все доступные обновления Windows через Центр обновления Windows и дождаться их установки - это важный шаг, без него следующие пункты могут не сработать.
- Вручную включить нужные компоненты (PowerShell или CMD от администратора):
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
- Перезагрузить сервер.
- Обновить сам WSL:
wsl --update
- После этого в списке доступных дистрибутивов появляются актуальные образы:
wsl --list --online wsl --install -d Ubuntu-24.04
Загрузка и запуск geo-shaper-wsl.sh
Внутри Ubuntu (WSL2), от root (см. "Первый вход" выше):
curl -fsSL -o geo-shaper-wsl.sh https://wiki.myarena.ru/soft/geo-shaper-wsl.sh chmod +x geo-shaper-wsl.sh
Синтаксис запуска:
sudo ./geo-shaper-wsl.sh <порт_снаружи> <порт_приложения> <лимит1_bps> <страны1> [<лимит2_bps> <страны2> [<лимит3_bps> <страны3>]]
Обязательны только первые четыре параметра (порт снаружи, порт приложения, лимит1, страны1). Вторая и третья группа - опциональны.
Параметры
- порт_снаружи - порт, который видят клиенты и для которого применяется шейпинг.
- порт_приложения - реальный порт, на котором слушает Windows-приложение.
- лимит1_bps / лимит2_bps / лимит3_bps - лимит полосы в битах в секунду, например
700000000= 700 Мбит/с. - страны1 / страны2 / страны3 - список ISO-кодов стран через запятую в кавычках, например
"RU,UA,KZ,BY", для этих стран действует свой лимит. Пустая строка""в любой из групп превращает её в тариф "для всех остальных" - допускается только в одной группе одновременно.
Если ни одна группа не оставлена с пустым списком стран, трафик, не попавший ни в одну группу, идёт без каких-либо ограничений (не шейпится).
Интерфейс WSL2 и IP Windows-хоста определяются автоматически. Если авто-определение ошиблось (нестандартная сетевая конфигурация) - можно переопределить через переменные окружения:
IFACE_OVERRIDE=eth0 TARGET_HOST_OVERRIDE=192.168.1.5 sudo ./geo-shaper-wsl.sh ...
Примеры
Лимит только для одной группы стран, остальное без ограничений
sudo ./geo-shaper-wsl.sh 443 8443 600000000 "RU,UA,KZ,BY"
Трафик к RU/UA/KZ/BY ограничен 600 Мбит/с суммарно, весь остальной трафик на этом порту идёт как обычно, без шейпинга.
Единый лимит на весь трафик порта
sudo ./geo-shaper-wsl.sh 443 8443 100000000 ""
Пустой список стран у единственной группы - лимит 100 Мбит/с действует на весь трафик порта целиком.
Лимит для стран СНГ 700 Мбит/с, для остальных - 200 Мбит/с
Windows-приложение слушает 8443, клиенты подключаются на 443:
sudo ./geo-shaper-wsl.sh 443 8443 \ 700000000 "RU,BY,KZ,KG,TJ,TM,UZ,MD,AM,AZ,UA" \ 200000000 ""
Вторая группа оставлена с пустым списком стран, поэтому работает как тариф "для всех остальных" (200 Мбит/с).
Три группы (если нужно разделить "остальных" тоже на два тарифа)
sudo ./geo-shaper-wsl.sh 443 8443 \ 600000000 "RU,UA,KZ,BY" \ 400000000 "DE,US,FR" \ 100000000 ""
Для полностью автоматической работы без единого ручного шага:
- Самый первый запуск скрипта выполните из PowerShell/Windows Terminal, запущенного через "Запуск от имени администратора", открыв оттуда вкладку с вашим дистрибутивом WSL.
- Все последующие запуски при перезагрузке сервера пройдут автоматически с нужными правами сами по себе.
Автозапуск
Скрипт настраивает автозапуск сам, но при первом прогоне обычно требуется один ручной шаг.
Что делает сам скрипт
- Пишет
systemd=trueв/etc/wsl.conf, если его там ещё не было. - Устанавливает себя в
/usr/local/sbin/geo-shaper-wsl.shи регистрирует systemd-юнит geo-shaper-windows.service с уже вшитыми вашими параметрами - он переприменяет nftables/tc-правила при каждом старте WSL2 (эти правила живут только в памяти ядра и не переживают перезапуск сам по себе). - Включает автозапуск HAProxy через systemd.
- Пытается сам создать задачу в Планировщике Windows (
schtasks.exe, доступен из WSL2 через interop), чтобы сама WSL2 поднималась при старте Windows без входа пользователя.
Что может потребоваться вручную
Если это первый запуск на чистом дистрибутиве (systemd ещё не был активен) - нужно один раз перезапустить WSL2, чтобы включённый systemd=true вступил в силу:
wsl --shutdown
Затем снова открыть дистрибутив - HAProxy и правила шейпинга поднимутся автоматически через systemd, сам скрипт запускать повторно не нужно.
Если авто-регистрация задачи в Планировщике не удалась (например, WSL был открыт не из elevated-окна) - скрипт в конце выведет готовую команду, её нужно выполнить из elevated PowerShell (запущенного от администратора):
schtasks /create /tn "WSL-Boot" /tr "wsl.exe -d <имя_дистрибутива> --exec /bin/true" /sc onstart /ru SYSTEM /rl highest
Без этого шага WSL2 (а значит, и HAProxy с шейпингом) не поднимется сама при перезагрузке Windows - придётся один раз вручную открыть дистрибутив.
Проверка работы
nft list table inet geoshaper tc -s class show dev <интерфейс> systemctl status haproxy systemctl status geo-shaper-windows.service
Если systemd в этой сессии ещё не активен (см. выше), HAProxy будет поднят напрямую - тогда вместо systemctl status haproxy проверяем так:
pgrep -a haproxy
Изменение параметров в будущем
Скрипт идемпотентен - просто перезапустите его с новыми значениями (можно поменять и количество групп - 1, 2 или 3), он сам сбросит старую конфигурацию nftables/tc/HAProxy и применит новую, а заодно перезапишет systemd-юнит с новыми параметрами:
sudo ./geo-shaper-wsl.sh 443 8443 \ 800000000 "RU,BY,KZ,KG,TJ,TM,UZ,MD,AM,AZ,UA" \ 150000000 ""