← На главную

Добавление маршрутов на 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) прервал бы скрипт.

Что понадобится

Шаг 1. Сгенерируйте .sh в NetRoute Pro

  1. Откройте нужный сайт в Chrome
  2. Запустите расширение NetRoute Pro
  3. Выберите платформу Linux
  4. Укажите IP VPN-шлюза (например 10.8.0.1)
  5. Задайте маску агрегации (рекомендуется /24)
  6. Нажмите Analyze Website
  7. Скачайте routes.sh
Совет: включите RIPE BGP оптимизацию — подстановка BGP-префиксов даёт стабильные подсети, которые не ломаются при ротации IP у Cloudflare/Fastly. Важно: RIPE BGP возвращает все префиксы анонсируемые ASN — для multi-tenant CDN (Cloudflare AS13335, AWS AS16509, DigitalOcean AS14061) это десятки тысяч IP, покрывающих несвязанные сайты. BGP-оптимизация подходит для single-tenant ASN; для shared CDN оставьте обычную /24 CIDR-агрегацию.

Шаг 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-юнит:

Проверка:

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 видит какие сайты вы посещаете, даже если данные зашифрованы.

Три варианта в зависимости от модели угроз:

  1. Полностью спрятать 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.com
    Теперь запросы про example.com идут через VPN, остальное — через дефолтный резолвер. Замените 10.0.0.1 на внутренний DNS вашего VPN-провайдера.
  2. Снизить видимость для ISP (публичный DoH/DoT). Направьте системный резолвер на публичный шифрованный DNS:
    sudo resolvectl dns wg0 1.1.1.1#cloudflare-dns.com
    sudo resolvectl dnsovertls wg0 yes
    ISP больше не видит запросы доменов; их видит публичный резолвер.
  3. Принять 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-интерфейс — вы обходите туннель. Два варианта решения:

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 для ваших сайтов.


#!/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 →

Официальная документация

Готовы попробовать?

NetRoute Pro — бесплатное расширение Chrome для генерации маршрутов из любого сайта.

Установить расширение