// DevOps
Направляем трафик из локальной подсети через удалённый сервер (IPIP + Policy Routing)
Опубликовано 22.09.2026
Руководство показывает, как настроить два Linux-сервера так, чтобы весь интернет-трафик из определённой локальной подсети (например, 10.100.10.0/24) уходил не через её обычный шлюз, а через IPIP-туннель на удалённый сервер, который выпускает его в интернет.
Схема нужна, когда сервисы одной подсети должны выходить в интернет с IP-адреса другого сервера: для централизованного NAT, работы с партнёрами по белому списку адресов или единой точки выхода для нескольких площадок. Остальной трафик самого шлюза при этом идёт обычным путём.
IPIP не шифрует трафик. Если туннель проходит через интернет и данные нужно защищать, используйте WireGuard или IPsec — о вариантах связи между площадками см. статью «Резервирование каналов связи: между офисами».
Исходные данные (условные адреса)
| Роль | Имя | Внешний (WAN) IP | Интерфейс WAN | Адрес в туннеле | Примечание |
|---|---|---|---|---|---|
| Сервер А | Локальный шлюз | 198.51.100.10 | eth0 | 10.254.0.1/30 | Шлюз подсети 10.100.10.0/24 |
| Сервер Б | Удалённый узел выхода | 203.0.113.20 | eth0 | 10.254.0.2/30 | Выпускает трафик в интернет |
- Подсеть для маршрутизации:
10.100.10.0/24 - Имя туннеля:
ipip0 - Сеть туннеля:
10.254.0.0/30
Шаг 1: Настройка сервера Б (узел выхода)
Задача: принять IPIP-туннель от сервера А и выпускать трафик подсети 10.100.10.0/24 в интернет через NAT с адресом 203.0.113.20.
1.1. Включаем пересылку пакетов
sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/90-ipip-forward.conf1.2. Туннель, обратный маршрут, межсетевой экран и NAT
#!/bin/sh
set -e
TUN_NAME="ipip0"
REMOTE_IP="198.51.100.10"
LOCAL_IP="203.0.113.20"
TUN_NET="10.254.0.2/30"
TUN_PEER="10.254.0.1"
WAN_IFACE="eth0"
CLIENT_NET="10.100.10.0/24"
echo "[*] Создаю туннель $TUN_NAME"
ip tunnel del "$TUN_NAME" 2>/dev/null || true
ip tunnel add "$TUN_NAME" mode ipip remote "$REMOTE_IP" local "$LOCAL_IP" ttl 64
ip addr add "$TUN_NET" dev "$TUN_NAME"
ip link set "$TUN_NAME" up mtu 1480
echo "[*] Обратный маршрут к подсети клиентов через туннель"
ip route replace "$CLIENT_NET" via "$TUN_PEER" dev "$TUN_NAME"
echo "[*] Настраиваю iptables"
iptables -I INPUT -p 4 -s "$REMOTE_IP" -j ACCEPT
iptables -A FORWARD -i "$TUN_NAME" -s "$CLIENT_NET" -o "$WAN_IFACE" -j ACCEPT
iptables -A FORWARD -i "$WAN_IFACE" -d "$CLIENT_NET" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s "$CLIENT_NET" -o "$WAN_IFACE" -j SNAT --to-source "$LOCAL_IP"
iptables -t mangle -A FORWARD -o "$WAN_IFACE" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
echo "[OK] Сервер Б готов."Обратный маршрут обязателен: после обратного преобразования адресов ответы адресованы машинам подсети 10.100.10.0/24, и без этого маршрута сервер Б отправит их в интернет, а не в туннель.
IPIP добавляет к каждому пакету 20 байт заголовка, поэтому MTU туннеля — 1480. Правило TCPMSS --clamp-mss-to-pmtu уменьшает размер TCP-сегментов под этот MTU, чтобы соединения не зависали из-за проблем с PMTU Discovery.
Шаг 2: Настройка сервера А (локальный шлюз)
Задача: направлять трафик подсети 10.100.10.0/24, идущий в интернет, в туннель к серверу Б.
2.1. Пересылка пакетов и rp_filter
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.rp_filter=2
sysctl -w net.ipv4.conf.default.rp_filter=2
cat <<EOF > /etc/sysctl.d/90-ipip-gw.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
EOFРежим rp_filter=2 (loose) нужен, потому что маршрутизация здесь асимметричная: ответы из интернета приходят через туннель, а не через интерфейс, в который смотрит маршрут по умолчанию. Ядро применяет максимальное из значений all и интерфейса — почему так и как это проверить, разобрано в статье «Что такое rp_filter».
2.2. Создаём IPIP-туннель
#!/bin/sh
set -e
TUN_NAME="ipip0"
REMOTE_IP="203.0.113.20"
LOCAL_IP="198.51.100.10"
TUN_NET="10.254.0.1/30"
TUN_PEER="10.254.0.2"
echo "[*] Поднимаю туннель $TUN_NAME"
ip tunnel del "$TUN_NAME" 2>/dev/null || true
ip tunnel add "$TUN_NAME" mode ipip remote "$REMOTE_IP" local "$LOCAL_IP" ttl 64
ip addr add "$TUN_NET" dev "$TUN_NAME"
ip link set "$TUN_NAME" up mtu 1480
echo "[OK] Туннель поднят."2.3. Policy routing
Добавляем таблицу маршрутизации
grep -q "100[[:space:]]tunnel_route" /etc/iproute2/rt_tables || echo "100 tunnel_route" >> /etc/iproute2/rt_tablesЕсли файла /etc/iproute2/rt_tables в системе нет, создайте его вручную либо используйте в командах номер таблицы 100 вместо имени.
Добавляем маршрут по умолчанию в эту таблицу
ip route add default via 10.254.0.2 dev ipip0 table tunnel_routeСоздаём правило
ip rule add from 10.100.10.0/24 table tunnel_route pref 1000
ip route flush cacheПравило отправляет в туннель весь трафик подсети, включая обращения к другим локальным сетям. Если подсеть должна обращаться к соседним сетям напрямую, добавьте перед ним правило с меньшим номером, например ip rule add from 10.100.10.0/24 to 10.0.0.0/8 table main pref 900.
2.4. Межсетевой экран
CLIENT_NET="10.100.10.0/24"
TUN_NAME="ipip0"
iptables -A FORWARD -s "$CLIENT_NET" -o "$TUN_NAME" -j ACCEPT
iptables -A FORWARD -i "$TUN_NAME" -d "$CLIENT_NET" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t mangle -A FORWARD -o "$TUN_NAME" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
echo "[OK] Межсетевой экран и policy routing настроены."Шаг 3: Проверка
Маршрут для трафика самого сервера А
ip route get 8.8.8.8Ожидается обычный маршрут:
8.8.8.8 via <ваш_шлюз> dev eth0 src 198.51.100.10 ...Маршрут для пакета из подсети
Чтобы проверить пересылку, укажите интерфейс, на который пакет приходит из локальной сети (iif): без него ядро проверяет маршрут для пакета, созданного на самом сервере.
ip route get 8.8.8.8 from 10.100.10.50 iif eth1Здесь eth1 — интерфейс сервера А в сторону подсети 10.100.10.0/24. Ожидается маршрут через туннель:
8.8.8.8 from 10.100.10.50 via 10.254.0.2 dev ipip0 ...Диагностика
1. Туннель
ip addr show dev ipip0
ip -s tunnel show
ping -I ipip0 10.254.0.2Если ping не проходит, проверьте, что межсетевые экраны обоих серверов и провайдеров пропускают протокол IPIP (IP-протокол 4).
2. Policy routing
ip rule show
ip route show table tunnel_routeВ выводе ip rule show должна быть строка:
1000: from 10.100.10.0/24 lookup tunnel_route3. NAT на сервере Б
iptables -t nat -L POSTROUTING -v -nПри активном трафике счётчики правила SNAT должны расти.
4. Внешний адрес для машин подсети
На любой машине из подсети 10.100.10.0/24:
curl -4 ifconfig.meОжидается 203.0.113.20.
5. MTU и MSS
Если TCP-соединения зависают:
ip link show ipip0
ping -M do -s 1452 8.8.8.8Пакет в 1452 байта данных плюс 28 байт заголовков ICMP и IP как раз укладывается в MTU туннеля 1480. Проверьте, что у туннеля mtu 1480 и что правило --clamp-mss-to-pmtu на месте.
6. tcpdump
tcpdump -ni ipip0
tcpdump -ni eth0 host 8.8.8.87. Временное журналирование
iptables -I FORWARD 1 -j LOG --log-prefix "[FORWARD] "
tail -f /var/log/kern.logПосле диагностики удалите это правило: оно пишет в журнал каждый пересылаемый пакет.
8. Обратный путь
С машины в подсети:
traceroute 8.8.8.8Первым хопом должен быть сервер А, следующим — адрес сервера Б в туннеле 10.254.0.2. С сервера Б:
traceroute -s 10.254.0.2 10.100.10.10Если трассировка с сервера Б уходит в интернет, а не в туннель, проверьте обратный маршрут из шага 1.2.
9. Сохранение настроек
Команды выше действуют до перезагрузки. Правила iptables сохраняются так (в Debian и Ubuntu — пакет iptables-persistent):
iptables-save > /etc/iptables/rules.v4Туннель, маршруты и правила policy routing после перезагрузки нужно создавать заново: удобнее всего оформить скрипты из шагов 1.2, 2.2 и 2.3 в службу systemd. Вывод ip rule show, сохранённый в файл, сам по себе ничего не восстанавливает.
Дополнительные рекомендации
| Пункт | Рекомендация |
|---|---|
| MTU | 1480 для туннеля и TCPMSS clamp на обоих серверах |
| Межсетевой экран | На новых системах удобнее nftables |
| Автозапуск | Запуск туннеля и маршрутов через systemd |
| Мониторинг | tcpdump -i ipip0 показывает трафик в туннеле |
| Безопасность | Разрешайте IPIP только с адреса второго сервера; для шифрования — WireGuard или IPsec |
Похожая задача на MikroTik — вернуть ответ через тот же шлюз, через который пришёл запрос, — разобрана в статье «MikroTik: возврат трафика через тот же шлюз».
Итог
Весь интернет-трафик подсети 10.100.10.0/24 выходит в интернет с адреса сервера Б (203.0.113.20), а сервер А продолжает использовать свой обычный маршрут. Для работы схемы нужны три вещи: туннель с правильным MTU, правило policy routing на сервере А и обратный маршрут к подсети на сервере Б.
// Contact
Нужна помощь?
Свяжись со мной и я помогу решить проблему
Написать в TelegramОтвечаю в течение рабочего дня (03:00–13:00 GMT)
Или оставьте заявку здесь:
// Related