MAATRIX / Блог / Site-to-site VPN между двумя офисами на WireGuard

Site-to-site VPN между двумя офисами на WireGuard

MAATRIX

Когда в двух офисах свои локальные сети и людям нужен постоянный доступ к общим ресурсам — файловому серверу, 1С, внутренним сервисам — тянуть отдельный VPN-клиент на каждый компьютер неудобно и ненадёжно. Правильное решение — site-to-site VPN: два шлюза на WireGuard связывают сети между собой один раз, а дальше все машины в обоих офисах видят друг друга напрямую, без клиентов и без ручной настройки на каждом устройстве. Ниже — рабочая схема с двумя серверами, реальными конфигами и объяснением, почему в site-to-site AllowedIPs указывают не на один хост, а на всю подсеть.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Site-to-site и remote access — в чём разница на уровне конфига

В обычном клиентском WireGuard (remote access) у вас один сервер и много клиентов: у каждого клиента в AllowedIPs стоит его собственный /32-адрес, и сервер просто раздаёт трафик по одному тоннелю на пользователя. Про эту схему подробнее в статье про разницу между site-to-site и remote access VPN.

Site-to-site устроен иначе: тоннель всего один (между двумя шлюзами), но через него ходит трафик не двух хостов, а двух целых сетей. Ключевое отличие в конфиге — AllowedIPs. У клиента это 10.10.0.5/32 — один адрес. У site-to-site шлюза это 10.10.0.0/24 — вся офисная подсеть целиком. WireGuard не различает "клиента" и "шлюз" на уровне протокола — разница только в том, какие маршруты вы прописываете и включаете ли форвардинг пакетов между интерфейсами.

Отсюда и практическое следствие: в site-to-site шлюз должен не только принимать зашифрованный трафик, но и пересылать его дальше в локальную сеть офиса (ip_forward + NAT или прозрачная маршрутизация), а на офисном роутере должен появиться маршрут "сеть другого офиса — через этот шлюз".

Схема сети и план адресации

Возьмём для примера два офиса с разными подсетями и серверами на публичных IP (свои VPS или выделенные серверы — не важно, лишь бы был статический внешний адрес и открытый UDP-порт).

Офис A (Москва)Офис B (Казань)
Локальная подсеть10.10.0.0/2410.20.0.0/24
WireGuard-сервер, LAN-адрес10.10.0.110.20.0.1
Публичный IP сервера203.0.113.10198.51.100.20
Адрес в тоннеле (wg0)10.99.99.1/3010.99.99.2/30
Порт WireGuard51820/udp51820/udp

Тоннельная сеть 10.99.99.0/30 нужна только для связи двух серверов между собой — по ней ничего, кроме служебного трафика WireGuard, не ходит. Важно, чтобы подсети офисов не пересекались (10.10.0.0/24 и 10.20.0.0/24 не должны совпадать и не должны накладываться на тоннельную сеть) — иначе маршрутизация станет неоднозначной и пакеты начнут теряться или уходить не туда.

Оба сервера должны стоять на границе своей локальной сети — либо быть самим шлюзом (default gateway для офиса), либо иметь маршрут "все хосты локалки идут через меня" со стороны LAN-коммутатора/роутера. Если WireGuard-сервер — не основной шлюз офиса, на офисном роутере нужно прописать статический маршрут до сети второго офиса через IP этого сервера в локалке.

Арендуйте сервер под свои задачи!

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Установка WireGuard и генерация ключей

Установка одинаковая на обоих серверах, подробный разбор пакетов и репозиториев — в статье про установку WireGuard на VPS. Кратко, на Ubuntu 24.04:

apt update
apt install -y wireguard

Генерируем ключевую пару на каждом сервере отдельно — приватный ключ никогда не покидает свой сервер:

cd /etc/wireguard
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
cat privatekey publickey

После этого у вас будет четыре значения: приватный и публичный ключ сервера A, приватный и публичный ключ сервера B. Публичные ключи нужно обменять между серверами — они пойдут в конфиг друг друга как PublicKey у пира.

Включаем форвардинг пакетов на обоих серверах — без этого сервер примет трафик из тоннеля, но не перешлёт его дальше в локальную сеть:

echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.d/99-wireguard.conf
sysctl --system

Конфигурация серверов: AllowedIPs на всю подсеть

Это центральная часть схемы. Конфиг сервера A (/etc/wireguard/wg0.conf):

[Interface]
Address = 10.99.99.1/30
ListenPort = 51820
PrivateKey = <приватный_ключ_сервера_A>
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT

[Peer]
PublicKey = <публичный_ключ_сервера_B>
Endpoint = 198.51.100.20:51820
AllowedIPs = 10.99.99.2/32, 10.20.0.0/24
PersistentKeepalive = 25

Конфиг сервера B — зеркальный:

[Interface]
Address = 10.99.99.2/30
ListenPort = 51820
PrivateKey = <приватный_ключ_сервера_B>
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT

[Peer]
PublicKey = <публичный_ключ_сервера_A>
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.99.99.1/32, 10.10.0.0/24
PersistentKeepalive = 25

Смотрите на строку AllowedIPs: на сервере A она включает не только тоннельный адрес соседа (10.99.99.2/32), но и всю подсеть офиса B (10.20.0.0/24). Именно эта запись говорит WireGuard "весь трафик к 10.20.0.0/24 заворачивай в этот тоннель" — и одновременно служит фильтром: пакеты, пришедшие от пира с адресами вне AllowedIPs, будут отброшены. Если забыть добавить подсеть и оставить только /32-адрес соседа, тоннель поднимется и будет пинговаться между серверами, но трафик из локальных сетей ходить не будет — частая причина, почему "тоннель есть, а связи с офисом нет" (подробнее о похожей проблеме — в статье про WireGuard, где хендшейк есть, а трафика нет).

PersistentKeepalive = 25 нужен, если хотя бы один сервер может быть за NAT или если провайдер разрывает неактивные UDP-сессии — без keepalive тоннель будет "засыпать" и первый пакет после паузы будет теряться.

Поднимаем интерфейс на обоих серверах:

wg-quick up wg0
systemctl enable wg-quick@wg0

Маршрутизация и NAT на границе офиса

Если WireGuard-сервер — это одновременно основной шлюз офиса (default gateway для всех локальных машин), дополнительная маршрутизация не нужна: форвардинга и AllowedIPs достаточно, все хосты и так ходят через него.

Если же в офисе отдельный роутер (Mikrotik, Keenetic, pfSense), а WireGuard поднят на отдельном сервере внутри локалки, на роутере офиса A нужно добавить статический маршрут до сети офиса B через адрес WG-сервера в локальной сети:

ip route 10.20.0.0/24 via 10.10.0.1

Аналогично на роутере офиса B — маршрут до 10.10.0.0/24 через 10.20.0.1. Без этого шага компьютеры в локалке не будут знать, куда слать пакеты для чужой подсети, и трафик уйдёт в default gateway "в интернет", а не в тоннель.

NAT (маскарадинг) в этой схеме обычно не нужен — оба конца видят реальные адреса друг друга, и это осознанное преимущество site-to-site: с машины 10.10.0.5 можно достучаться напрямую до 10.20.0.8, без подмены адресов. NAT потребуется, только если подсети офисов пересекаются и их нельзя перенумеровать (тогда придётся городить NAT66/NAT44 с трансляцией диапазонов — отдельная и менее приятная тема, которую лучше решать заранее правильным планом адресации, а не постфактум).

Если на серверах включён iptables/nftables с политикой DROP по умолчанию, не забудьте открыть входящий UDP-порт WireGuard и разрешить FORWARD между wg0 и внутренним интерфейсом:

iptables -A INPUT -p udp --dport 51820 -j ACCEPT
iptables -A FORWARD -i wg0 -o eth1 -j ACCEPT
iptables -A FORWARD -i eth1 -o wg0 -j ACCEPT

(где eth1 — интерфейс, смотрящий в локальную сеть офиса).

Проверка тоннеля и типичные ошибки

Первым делом смотрим статус на обоих серверах:

wg show

В выводе должны быть строки latest handshake с недавним временем и ненулевые счётчики transfer — это подтверждает, что серверы вообще видят друг друга. Дальше проверяем по уровням:

  1. Пинг между серверами по тоннельным адресам: ping 10.99.99.2 с сервера A. Если не проходит — проблема на уровне UDP/маршрута до Endpoint (файрвол провайдера, неверный публичный IP, закрытый порт).
  2. Пинг из локалки A в локалку B: с любой машины офиса A — ping 10.20.0.1, затем ping 10.20.0.8 (реальный хост). Если первое проходит, а второе нет — не работает форвардинг или маршрут на роутере офиса B.
  3. Проверка форвардинга: sysctl net.ipv4.ip_forward должен вернуть 1 на обоих серверах.
  4. Проверка AllowedIPs: wg show wg0 allowed-ips — убедитесь, что там действительно вся подсеть, а не только /32.

Частые причины, по которым "хендшейк есть, а трафика между офисами нет": неверные AllowedIPs (только тоннельный адрес без подсети), отсутствие маршрута на локальном роутере, забытый ip_forward, или дублирующаяся адресация (одна и та же подсети 10.0.0.0/24 в обоих офисах "по умолчанию" на роутерах из коробки — это встречается на удивление часто). Разбор похожих ситуаций есть в статьях про типичные ошибки WireGuard на сервере и про случаи, когда тоннель не поднимается.

Если тоннель поднят, но постоянно рвётся при простое — это почти всегда отсутствующий или слишком большой PersistentKeepalive при NAT на одной из сторон; 25 секунд — разумное значение по умолчанию, уменьшать его без необходимости не стоит (лишний трафик и нагрузка на оба конца).

Отказоустойчивость и что дальше

Site-to-site тоннель на WireGuard — это единая точка отказа: если сервер A недоступен, связь между офисами пропадает целиком. Для критичных сценариев имеет смысл держать резервный конфиг на втором сервере (можно даже в третьей локации, как транзитный узел) и переключаться на него вручную или скриптом при мониторинге хендшейка. Резервное копирование самих конфигов и ключей тоже не будет лишним — если сервер придётся поднимать заново, восстановление из бэкапа с готовыми wg0.conf и ключами быстрее, чем пересобирать всю схему адресации с нуля.

Также стоит настроить внешний мониторинг доступности порта 51820 и алерты по пропаданию хендшейка — тоннель WireGuard не сообщает о разрыве сам, он просто перестаёт передавать пакеты, и без мониторинга проблему обычно замечают только тогда, когда кто-то в офисе не может достучаться до сервера. Если вдобавок к site-to-site нужен ещё и защищённый доступ к RDP-серверам через тот же тоннель — это работает без дополнительной настройки, трафик просто идёт через уже поднятую подсетевую маршрутизацию (детали — в статье про RDP через WireGuard).

Арендуйте сервер под свои задачи!

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли связать больше двух офисов одной схемой?

Да, но это уже не строго "site-to-site", а mesh: каждому серверу нужен отдельный [Peer]-блок на каждый другой офис, и в AllowedIPs каждого пира — подсеть именно этого офиса. При росте числа офисов вручную поддерживать такие конфиги становится неудобно, тогда есть смысл посмотреть в сторону инструментов вроде Netmaker, которые автоматизируют mesh поверх WireGuard.

Что если один из офисов сидит за NAT провайдера и не имеет статического публичного IP?

Тогда роль "публичной точки" стоит отдать серверу с внешним статическим адресом (арендованный VPS), а офис без своего IP настраивается как клиент с PersistentKeepalive, чтобы держать сессию открытой самостоятельно — Endpoint в его конфиге просто не указывается, инициатором соединения выступает он сам.

Обязательно ли использовать /24 для локальных сетей?

Нет, размер подсети зависит от количества устройств в офисе — может быть /25, /26 или крупнее. Главное правило прежнее: подсети обоих офисов и тоннельная сеть не должны пересекаться.

Нужно ли шифровать трафик поверх WireGuard дополнительно (например, TLS для внутренних сервисов)?

Сам WireGuard уже даёт шифрование канала между серверами, дополнительный TLS — это про защиту конкретного приложения (например, HTTPS для внутреннего веб-интерфейса), а не требование протокола. Обычно достаточно WireGuard, если только у сервиса нет отдельных требований комплаенса.

Как быстро проверить, что маршрут действительно живёт в тоннеле, а не идёт мимо?

Команда traceroute или mtr до адреса в другой офисной подсети — первым хопом после локального шлюза должен быть тоннельный адрес соседнего сервера (10.99.99.x), а не публичный маршрут провайдера.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →