Добавление маршрутов на Linux через .sh скрипт
NetRoute Pro генерирует простой Bash-скрипт с командами ip route add. Применяется одной командой. Для персистентности — один дополнительный шаг в зависимости от дистрибутива.
Синтаксис команды
Синтаксис (idempotent — используйте в скриптах):
ip route replace <CIDR> via <GATEWAY> dev <VPN_IF>
Пример:
ip route replace 1.1.1.0/24 via 10.0.0.1 dev wg0
Выполнять от root или через sudo. NetRoute Pro генерирует команды в .sh-скрипте — запустите bash routes.sh. replace создаёт маршрут если его нет и обновляет если есть, поэтому повторный запуск безопасен; add упал бы с RTNETLINK answers: File exists на дубликате и (вместе с set -e) прервал бы скрипт.
Что понадобится
- Пакет
iproute2— есть во всех современных дистрибутивах (Ubuntu, Debian, Fedora, Arch и др.) - Права root или
sudo - Настроенный и активный VPN-интерфейс
- Расширение NetRoute Pro в Chrome
Шаг 1. Сгенерируйте .sh в NetRoute Pro
- Откройте нужный сайт в Chrome
- Запустите расширение NetRoute Pro
- Выберите платформу Linux
- Укажите IP VPN-шлюза (например
10.8.0.1) - Задайте маску агрегации (рекомендуется
/24) - Нажмите Analyze Website
- Скачайте
routes.sh
Шаг 2. Примените скрипт
chmod +x routes.sh
sudo bash routes.sh
Маршруты добавлены. Работают до перезагрузки системы.
Шаг 3. Сделайте маршруты постоянными
Три варианта — выберите тот, что удобнее для вашего дистрибутива.
systemd-networkd
Создайте drop-in файл для вашего VPN-интерфейса, например /etc/systemd/network/10-vpn.network.d/routes.conf:
[Route]
Destination=104.21.32.0/24
Gateway=10.8.0.1
[Route]
Destination=172.67.182.0/24
Gateway=10.8.0.1
Примените изменения:
sudo systemctl restart systemd-networkd
NetworkManager dispatcher
Сохраните скрипт как /etc/NetworkManager/dispatcher.d/99-vpn-routes и сделайте исполняемым:
#!/bin/bash
INTERFACE="$1"
ACTION="$2"
if [ "$INTERFACE" = "<имя-вашего-vpn>" ] && [ "$ACTION" = "up" ]; then
ip route add 104.21.32.0/24 via 10.8.0.1
ip route add 172.67.182.0/24 via 10.8.0.1
# ... остальные маршруты
fi
sudo chmod +x /etc/NetworkManager/dispatcher.d/99-vpn-routes
При подъёме VPN NetworkManager вызовет скрипт автоматически.
systemd oneshot service (рекомендуемый)
Работает на любом дистрибутиве с systemd (Ubuntu, Debian, Fedora, Arch, RHEL, openSUSE — это практически все современные дистры). Корректно дожидается поднятия VPN-туннеля прежде чем добавлять маршруты — без race conditions и sleep-хаков.
sudo mv routes.sh /usr/local/bin/routes.sh
sudo chmod +x /usr/local/bin/routes.sh
sudo tee /etc/systemd/system/vpn-routes.service > /dev/null <<'EOF'
[Unit]
Description=Apply VPN split-tunnel routes
After=network-online.target wg-quick@wg0.service
Wants=network-online.target
Requisite=wg-quick@wg0.service
BindsTo=wg-quick@wg0.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/routes.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now vpn-routes.service
Замените wg-quick@wg0.service на свой VPN-юнит:
- OpenVPN:
openvpn-client@<name>.service - strongSwan / IPsec:
strongswan.service - Без привязки к VPN: уберите строки
Requisite=иBindsTo=, оставьте толькоAfter=network-online.target
Проверка:
systemctl status vpn-routes.service
journalctl -u vpn-routes.service
@reboot cron? Cron-демон обычно стартует до поднятия VPN-туннеля — ip route add запускается против ещё не существующего интерфейса, тихо падает, и вы обнаруживаете сломанные маршруты только при следующей перезагрузке. After= и Requisite= в systemd ждут VPN-юнит и убирают race. BindsTo= также останавливает маршруты когда VPN падает.
DNS leak — обязательно прочитать
Эта инструкция направляет трафик по IP. Она не направляет DNS. Ваш браузер всё равно спрашивает у системного резолвера (обычно это резолвер ISP, полученный по DHCP), какой IP у example.com — через VPN идёт только сам IP-трафик. ISP видит какие сайты вы посещаете, даже если данные зашифрованы.
Три варианта в зависимости от модели угроз:
- Полностью спрятать DNS от ISP (split-DNS). На systemd-resolved настройте per-link DNS только для тунелированных доменов:
Теперь запросы проsudo resolvectl dns wg0 10.0.0.1 sudo resolvectl domain wg0 ~example.com ~another-site.comexample.comидут через VPN, остальное — через дефолтный резолвер. Замените10.0.0.1на внутренний DNS вашего VPN-провайдера. - Снизить видимость для ISP (публичный DoH/DoT). Направьте системный резолвер на публичный шифрованный DNS:
ISP больше не видит запросы доменов; их видит публичный резолвер.sudo resolvectl dns wg0 1.1.1.1#cloudflare-dns.com sudo resolvectl dnsovertls wg0 yes - Принять leak. Если цель — обход блокировок, а не уход от слежки, это нормально — данные идут шифрованно, утекает только метаданные lookup'ов.
Проверить текущее состояние: dnsleaktest.com или browserleaks.com/dns — показанный резолвер должен принадлежать вашему VPN или выбранному DoH, не ISP. Локально resolvectl status показывает per-link DNS-конфигурацию.
IPv6 dual-stack bypass
Если у destination есть AAAA-запись (а у большинства популярных сайтов есть — Cloudflare, Google, AWS все dual-stack), ОС предпочитает IPv6 поверх IPv4 (RFC 6724). Маршруты добавленные по этой инструкции — только IPv4 — IPv6-трафик пройдёт мимо VPN через дефолтный v6-маршрут ISP. Итог: VPN выглядит работающим, но для dual-stack сайтов не делает ничего.
Быстрая проверка после поднятия VPN:
curl -6 -s -o /dev/null -w "remote=%{remote_ip}\n" https://example.com
ip -6 route get $(dig +short AAAA example.com | head -1)
Если IPv6-trace не идёт через VPN-интерфейс — вы обходите туннель. Два варианта решения:
- Маршрутизировать v6 через VPN тоже (если провайдер поддерживает IPv6). Сгенерируйте IPv6-маршруты в NetRoute Pro — тот же flow, другие префиксы (
2606:4700::/32и т.п.). - Отключить IPv6 системно:
Весь трафик откатывается на v4 и корректно тунелируется.sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1 sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1 # Постоянно: те же строки в /etc/sysctl.d/99-disable-ipv6.conf
Fail-closed (kill switch)
Когда VPN-туннель падает (смена сети, проблема у провайдера, sleep/wake), ядро удаляет маршруты привязанные к мёртвому интерфейсу — и трафик к ранее-тунелированным CIDR'ам откатывается на дефолтный маршрут через ISP. Итог: тихий leak без видимой ошибки. Чтобы включить fail-closed (блокировать вместо leak):
# nftables (современный Linux)
sudo nft add table inet vpnkill
sudo nft add chain inet vpnkill output { type filter hook output priority 0 \; }
sudo nft add rule inet vpnkill output ip daddr 1.1.1.0/24 oif != wg0 drop
sudo nft add rule inet vpnkill output ip daddr 8.8.8.0/24 oif != wg0 drop
# Повторить для каждого тунелированного CIDR.
Эквивалент через iptables:
sudo iptables -I OUTPUT ! -o wg0 -d 1.1.1.0/24 -j REJECT
sudo iptables -I OUTPUT ! -o wg0 -d 8.8.8.0/24 -j REJECT
Теперь трафик к этим префиксам через любой интерфейс кроме wg0 блокируется — VPN упал = заблокировано, а не утекло. Пользователь видит ошибку соединения (явный сигнал что VPN не работает) вместо тихого выхода через ISP. Это безопасный failure mode.
Проверка
ip route show | grep 10.8.0.1
Все нужные подсети должны быть привязаны к IP VPN-шлюза.
Откат
Скрипт сохраняет снимок таблицы маршрутов в /tmp/route-table.<timestamp>.txt до применения изменений — полезно для диагностики что именно изменилось. Чтобы удалить маршруты, добавленные NetRoute Pro, удалите каждый префикс:
for cidr in 1.1.1.0/24 8.8.8.0/24 162.159.0.0/16; do
sudo ip route del "$cidr" 2>/dev/null || true
done
Или, более консервативно, сгенерируйте обратный список из routes.sh, заменив replace (или add) на del:
awk '/ip route /{ sub(/^ip route (replace|add)/, "ip route del"); print }' routes.sh | sudo bash
Если что-то пошло совсем не так, снимок в /tmp/route-table.<timestamp>.txt показывает состояние ДО изменений — можно вручную восстановить нужное.
Частые проблемы
Network is unreachable
VPN-интерфейс выключен или не получил адрес. Проверьте:
ip link show
ip addr show
Permission denied
Команды ip route требуют root. Запускайте скрипт через sudo.
Пример конфигурационного файла
Готовый шаблон с комментариями. Замените примеры маршрутов выводом NetRoute Pro для ваших сайтов.
linux-routes.sh— Bash-скрипт с командамиip route add
#!/bin/bash
# Example Linux routing script for split tunneling.
# Generated by NetRoute Pro: https://alexander2k.github.io/netroute-site/
#
# Run as root or with sudo. Routes added here last until reboot —
# for persistence see the Linux guide (systemd-networkd / NetworkManager).
#
# Idempotent: uses `ip route replace` so re-running the script is safe.
# `add` would fail with "RTNETLINK answers: File exists" on a duplicate;
# combined with `set -e`, the first existing route would abort the script
# and skip the rest. `replace` creates if missing, updates if present.
set -euo pipefail
DEV="wg0" # VPN interface name (wg0, tun0, ppp0, ...)
GW="10.0.0.1" # VPN gateway IP (or use only "dev $DEV" if VPN is point-to-point)
# Snapshot current route table — useful for rollback if something breaks.
SNAPSHOT="/tmp/route-table.$(date +%s).txt"
ip route show > "$SNAPSHOT"
echo "Route table snapshot saved to $SNAPSHOT"
ip route replace 1.1.1.0/24 via "$GW" dev "$DEV"
ip route replace 8.8.8.0/24 via "$GW" dev "$DEV"
ip route replace 162.159.0.0/16 via "$GW" dev "$DEV"
# Verify with: ip route show
# Remove a single route: ip route del <CIDR>
# Full rollback (delete all routes added by this script):
# for cidr in 1.1.1.0/24 8.8.8.0/24 162.159.0.0/16; do
# ip route del "$cidr" 2>/dev/null || true
# done
Подсказка: Нужен конфиг без строк-комментариев? В настройках NetRoute Pro снимите галочку «Включать комментарии в экспортируемые файлы» — расширение выгрузит только команды маршрутизации. Полезно для роутеров, которые не принимают комментарии.
Все примеры конфигов на GitHub →
Официальная документация
- ip-route(8) man page (en)
- systemd.network(5) (en)
- NetworkManager Dispatcher (en)
- Arch Wiki: systemd-networkd (en)
Похожие инструкции
- Keenetic — маршруты из BAT-файла
- MikroTik — импорт
.rsc-скрипта в RouterOS - WireGuard — split tunneling через
AllowedIPs - OpenVPN — директивы
routeв клиентском конфиге
Готовы попробовать?
NetRoute Pro — бесплатное расширение Chrome для генерации маршрутов из любого сайта.
Установить расширение