Одиннадцатому филиалу достался роутер, который настраивали давно и без оглядки на корпоративные сети. Его локальная сеть живёт в диапазоне 10.8.0.0/24. Именно этот диапазон администратор много месяцев назад выбрал для туннеля WireGuard, и в нём уже сидят хаб с адресом 10.8.0.1 и десять филиальных peer. Получается забавная ситуация: туннельный адрес центра находится внутри чужой локальной сети. Роутер нового филиала, когда его попросят отправить пакет на 10.8.0.1, не станет искать туннель. Он решит, что адрес лежит в соседней комнате, и начнёт спрашивать про него по ARP у принтеров и кассовых терминалов.
Ни один ключ, ни один параметр WireGuard тут не виноват. Конфликт возник на уровне адресного плана, и чинить его нужно там же. Поэтому разговор о подключении филиала мы начнём не с команд, а с бумаги: нарисуем, какие адреса к чему относятся, и только потом дойдём до peer и AllowedIPs. Установку WireGuard с нуля оставим в стороне: считаем, что хаб уже работает и десять филиалов через него ходят.
Три множества, которые не должны пересекаться
Любой адрес, который встречается в такой схеме, принадлежит одному из трёх множеств. Путаница начинается, когда их смешивают в голове.
- Адреса локальных сетей филиалов (LAN). Это компьютеры, принтеры, телефоны, камеры. Их раздаёт местный DHCP, и администратор центра влияет на них слабо: выбор диапазона часто сделан до вас, прошивкой или предыдущим подрядчиком.
- Адреса туннеля. Это адреса самих интерфейсов WireGuard: по одному на каждого участника. Они нужны, чтобы у каждого peer была своя точка в общей сети поверх интернета. Эти адреса вы выдаёте целиком сами.
- Серверные ресурсы. Файловое хранилище, внутренний DNS, учётная система, всё, до чего филиалам нужно добраться в центре или на хабе.
Каждое множество должно занимать свой непересекающийся диапазон, и у каждого должен быть понятный принцип нарезки. Ниже учебный план, на котором мы будем разбирать всё остальное. Это условный пример для объяснения, а не описание чьей-то реальной сети.
| Назначение | Диапазон | Принцип |
|---|---|---|
| Туннель WireGuard | 10.8.0.0/24 | Хаб 10.8.0.1; филиал номер N получает 10.8.0.(10+N) |
| LAN филиалов | 10.20.0.0/16 | Филиал номер N получает 10.20.N.0/24 |
| Серверные ресурсы | 10.30.0.0/24 | Файловый сервер 10.30.0.10, внутренний DNS 10.30.0.53 |
| Резерв под будущее | 10.40.0.0/16 | Не выдаётся без записи в плане |
Принцип в таблице намеренно механический. Номер филиала виден и в туннельном адресе, и в третьем октете его LAN. Увидев в логах 10.8.0.14, вы без справочника знаете, что это четвёртый филиал и его пользователи сидят в 10.20.4.0/24. Всё, что делает план читаемым без обращения к памяти администратора, снижает вероятность ошибки у следующего человека, который будет добавлять двенадцатый филиал.
Заметьте также, что в плане нет ни одного диапазона вида 192.168.0.0/24 или 192.168.1.0/24. Это не случайность. Именно такие сети по умолчанию включены в домашние и офисные роутеры. Чем популярнее диапазон, тем выше шанс, что он где-то уже занят: у сотрудника, который работает из дома, в гостевой сети клиента или в старом филиале. Выбирая диапазоны для корпоративного плана, лучше брать менее очевидные куски частного пространства и записывать их.
Что на самом деле занято у нового филиала
Вернёмся к одиннадцатому филиалу. До любых действий нужно выяснить, что именно у него есть. Достаточно трёх вопросов к местному администратору или к самому роутеру:
- Какая сеть настроена на LAN-интерфейсе роутера и какую маску использует DHCP?
- Есть ли за основным роутером другие роутеры или точки доступа со своими подсетями? Во многих небольших офисах стоит каскад: провайдерский модем раздаёт одну сеть, за ним ещё один роутер раздаёт другую.
- Какой DNS выдаётся клиентам и есть ли у офиса собственные имена, которые нужно сохранить?
В нашем примере ответ на первый вопрос неприятный: LAN нового филиала живёт в 10.8.0.0/24. Теперь у нас есть три пути.
Путь первый: переселить филиал
Самое чистое решение — сменить подсеть филиала на 10.20.11.0/24 по плану. Это однократная работа: меняется адрес роутера, диапазон DHCP, статические адреса принтеров и камер, а также все места, где кто-то когда-то записал IP руками. Она неприятна, но делается один раз и убирает проблему навсегда. Любое другое решение будет напоминать о себе каждый раз, когда кто-то будет разбирать маршруты.
Путь второй: сдвинуть туннель
Можно рассуждать иначе: раз конфликт между двумя сетями, пусть уступит та, что меньше. Но туннельная сеть 10.8.0.0/24 уже прописана в конфигурации хаба и десяти филиалов. Менять её значит трогать одиннадцать узлов ради одного. Если же у вас пока пять филиалов вместо десяти, этот путь дешевле. Всё зависит от того, где окажется меньше правок.
Путь третий: трансляция адресов
Если переселить филиал нельзя (например, у него закрытое оборудование с жёстко записанными адресами), остаётся трансляция сетей, когда центр видит филиал под выдуманным диапазоном. Это работает, но усложняет жизнь: логи на серверах показывают не реальные адреса, а трансляционные, а диагностика требует держать в голове две таблицы соответствия. WireGuard сам такой трансляции не делает, она настраивается отдельно на маршрутизаторе. Для небольшой компании я бы выбирал этот вариант только когда два первых совсем невозможны.
В остальном тексте считаем, что выбран первый путь: филиал переехал в 10.20.11.0/24, а туннель остался 10.8.0.0/24.
Идентификаторы нового peer
Теперь можно заводить участника. У каждого peer в WireGuard есть пара ключей: закрытый остаётся на устройстве, открытый передаётся второй стороне (WireGuard Quick Start). Именно открытый ключ служит идентификатором: по нему хаб узнаёт, с кем разговаривает, и в нём же документация предлагает указывать peer при удалении (wg(8)). Значит, настоящий идентификатор филиала — ключ, а адреса — это его свойства.
Отсюда несколько практических следствий.
Ключи не нужно придумывать в плане и нельзя публиковать. В примерах ниже стоят заглушки вроде «ОТКРЫТЫЙ_КЛЮЧ_ФИЛИАЛА_11». Закрытый ключ нового филиала должен быть создан на самом устройстве филиала и никуда не уходить. Через хаб идёт только открытый.
Имя peer хранится у человека, а не в протоколе. WireGuard не знает, что этот ключ называется «Филиал Новосибирск». Поэтому в конфигурации стоит оставлять комментарий рядом с каждым peer, а в плане — таблицу «номер, название, открытый ключ (первые символы), туннельный адрес, LAN». Если сотрудник уволился, а ключ остался, вы хотя бы поймёте, чей он.
Туннельный адрес выдаётся по номеру из плана. Одиннадцатому филиалу достаётся 10.8.0.21. На хабе он указывается как /32: один адрес, одна машина. Если выдать филиалу целую туннельную подсеть, вы потеряете читаемость плана и займёте место, которое понадобится потом.
Endpoint запоминается из реальных пакетов. Документация отмечает, что адрес endpoint обновляется по корректно аутентифицированным пакетам (wg(8)). Для хаба это удобно: если у филиала динамический внешний адрес, хаб может не знать его заранее и узнает после первого пакета от филиала. Поэтому в конфигурации хаба для такого peer endpoint можно не писать, а в конфигурации филиала — указывать адрес хаба.
Если филиал находится за NAT провайдера, а центру иногда нужно самому инициировать соединение, пригодится PersistentKeepalive. Он поддерживает состояние NAT, по умолчанию выключен и нужен не каждой конфигурации (WireGuard Quick Start). Включайте его на стороне филиала только когда без него туннель действительно засыпает, и подбирайте интервал по наблюдению, а не по чужому примеру из интернета. Если у филиала роутер марки Keenetic или Netcraze, подробности клиентской части описаны в статье про настройку WireGuard-клиента на Keenetic и Netcraze.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.
AllowedIPs: одно поле, две обязанности
Теперь главное поле. В документации AllowedIPs описан как список адресов, которые допустимы во входящем трафике от peer, и одновременно как направления для исходящего (wg(8)). Эту двойственность стоит прочувствовать, потому что на ней стоит вся настройка.
Представьте, что у хаба в таблице десять строк. Каждая строка говорит: «Если мне нужно отправить пакет на такой-то адрес, я отправлю его этому peer. И, наоборот, если от этого peer пришёл пакет с адресом отправителя, которого нет в его списке, я его отброшу». Список один и тот же, но работает он как маршрутная таблица и как фильтр.
Для одиннадцатого филиала на хабе напишем так (ключ — заглушка):
[Peer]
# Филиал 11
PublicKey = ОТКРЫТЫЙ_КЛЮЧ_ФИЛИАЛА_11
AllowedIPs = 10.8.0.21/32, 10.20.11.0/24Первая запись — сам туннельный адрес филиала: пакеты хаба с адресом 10.8.0.1 к 10.8.0.21 пойдут к нужному peer. Вторая — его локальная сеть: всё, что хаб захочет отправить в 10.20.11.0/24, уйдёт через этого peer. Вместе с тем обратное правило: если от этого peer придёт пакет с адресом отправителя из другого диапазона, например 10.20.3.5, хаб его не примет. Это полезное свойство: взломанный или ошибочно настроенный филиал не сможет представиться другим филиалом.
Теперь противоположная сторона. На роутере филиала в разделе peer, описывающем хаб, список зависит от того, какие ресурсы вы хотите открыть. Начнём узко:
[Peer]
# Хаб
PublicKey = ОТКРЫТЫЙ_КЛЮЧ_ХАБА
Endpoint = АДРЕС_ХАБА:ПОРТ
AllowedIPs = 10.8.0.1/32, 10.30.0.10/32, 10.30.0.53/32Здесь написан не диапазон 10.30.0.0/24, а три конкретных адреса: сам хаб, файловый сервер и внутренний DNS. Всё остальное из серверной сети пока недоступно. Это сознательная скупость, и вот зачем.
Зачем сужать список
Широкий список легко писать и трудно проверять. Если вы сразу напишете 10.0.0.0/8, то пошлёте через туннель весь частный адресный мир, включая локальную сеть самого филиала. Роутер филиала получит два противоречащих друг другу правила: «10.20.11.0/24 — это здесь» и «10.0.0.0/8 — это в туннель». Как именно они разрешатся, зависит от реализации маршрутизации на конкретном устройстве, а надеяться на это не стоит. Пересечение лучше не допускать вовсе.
Та же ловушка есть на хабе. Если для филиала 11 по привычке написать 10.20.0.0/16 «на всякий случай, чтобы он видел остальные филиалы», этот диапазон перекроет LAN всех остальных филиалов, которые уже перечислены у других peer. В WireGuard один адрес не должен быть разрешён двум peer одновременно: иначе вы получите непредсказуемую картину, где трафик филиала 4 вдруг уходит в филиал 11. Хорошая привычка: перед добавлением нового peer пробежать глазами все существующие списки AllowedIPs и убедиться, что ни одна новая запись не пересекается со старыми. В нашем плане это просто, потому что каждая запись — это /32 из 10.8.0.0/24 или /24 из 10.20.0.0/16, и друг с другом они не пересекаются по построению.
IPv4 и IPv6 отдельно
Документация прямо говорит, что IPv4 и IPv6 в AllowedIPs перечисляются отдельно (wg(8)). Практическое следствие: если в филиале есть IPv6 и вы ничего про него не написали, он через туннель не пойдёт. Это может быть и хорошо, и плохо. Если IPv6 в офисе включён, но в плане его нет, имеет смысл решить, куда он должен идти, и либо описать его отдельной записью, либо отключить на роутере. Неожиданные пути для трафика рождаются как раз в такой серой зоне.
Что такое «разрешённый адрес» для DNS
Внутренний DNS с адресом 10.30.0.53 — отдельный повод для внимания. Если роутер филиала раздаёт клиентам этот DNS, то запросы пойдут в туннель, а значит адрес сервера обязан стоять в AllowedIPs хаба на стороне филиала. Забыть его просто, потому что файловый сервер вы проверяете руками по IP, и всё работает, а имена не разрешаются. Тогда сотрудники жалуются, что «шара не открывается», хотя туннель в порядке. Поэтому в нашем примере DNS внесён в список наравне с файловым сервером.
Сначала один сервис, потом вся сеть
Теперь у нас есть план, уникальные идентификаторы и узкие списки. Включать широкий доступ рано. Сначала проверим один путь целиком: от одного компьютера в 10.20.11.0/24 до файлового сервера 10.30.0.10.
Путь содержит несколько звеньев, и поломка может быть в любом:
- Роутер филиала знает, что 10.30.0.10 надо отправлять в туннель.
- Хаб принимает пакет от филиала и считает адрес отправителя допустимым.
- Хаб знает, как передать пакет серверу в серверной сети.
- Сервер знает, что ответ на 10.20.11.x надо вернуть через хаб.
- Ответ проходит хаб и возвращается к филиалу по тому же peer.
Четвёртый пункт ломается чаще всего. Хаб и туннель могут работать прекрасно, а файловый сервер не знает про сеть 10.20.11.0/24 и отправляет ответы на свой шлюз по умолчанию, где они пропадают. Симптом: пакеты до сервера доходят, ответов нет. Это не проблема WireGuard, а проблема маршрута возврата. Если файловый сервер стоит на самом хабе, вопроса нет. Если он за хабом, на нём или на соседнем маршрутизаторе нужен маршрут в 10.20.0.0/16 через хаб.
Порядок проверки такой. Сначала смотрим состояние на хабе командой wg show: она показывает peer и состояние туннеля (WireGuard Quick Start). Если у нового peer нет свежего рукопожатия, дальше идти бессмысленно: проблема в ключах, endpoint или в том, что порт не доходит. Когда рукопожатие есть, с одного компьютера филиала проверяем доступность единственного адреса 10.30.0.10, а затем нужного порта на нём. Только после этого проверяем DNS по имени. Широкий диапазон добавляем в самую последнюю очередь, если он вообще нужен.
Принцип понятен: каждая проверка отвечает на один вопрос. Если вы включили сразу всё, а сотрудник пишет «не открывается», то у вас пять подозреваемых. Если вы включили один адрес и он не отвечает, подозреваемых два-три, и они лежат на одной линии.
Как вносить правку на живом хабе
Хаб уже обслуживает десять филиалов, и ронять их ради одиннадцатого не хочется. Здесь пригодится различие, которое документация проводит прямо: изменение работающего интерфейса и изменение конфигурационного файла — разные действия, а syncconf применяет только различия без пересоздания всех peer (wg(8)). Из этого следует рабочая последовательность: допишите peer в файл, чтобы после перезагрузки он не пропал, и примените различия к живому интерфейсу, не перезапуская его целиком. Если файл правили, а интерфейс нет, новый филиал не заработает до применения. Если правили интерфейс, а файл нет, филиал исчезнет после перезагрузки сервера и вы потратите вечер на разбирательство, почему вчера всё работало.
Если что-то пошло не так, peer можно убрать: документация предусматривает форму wg set ... peer ... remove с указанием открытого ключа (wg(8)). Удаляется только он, остальные десять не затрагиваются.
И маленькое предупреждение про секреты. Выгрузки конфигурации работающего интерфейса, в том числе wg showconf и машинный дамп, могут содержать секретные данные (wg(8)). Не вставляйте вывод таких команд в чат с коллегой, в тикет или в публичный репозиторий. Если нужно показать, как выглядит peer, перепишите его вручную с заглушками, как в примерах выше.
Хаб как отдельный ресурс: что ему нужно от сервера
Хаб в такой схеме — точка, через которую проходит трафик всех филиалов к серверным ресурсам. Нагрузка у него специфичная: много небольших пакетов, шифрование и дешёвая маршрутизация, но почти нет тяжёлых вычислений. Заранее сказать, сколько филиалов потянет конкретный сервер, нельзя: всё зависит от того, что в филиалах делают люди, какие у них каналы и сколько данных гоняют через файловый сервер. Поэтому разумно начинать с небольшой конфигурации, замерять и расти по факту.
Для такой задачи подойдёт VPS MAATRIX: у серверов NVMe, процессоры AMD EPYC и root-доступ, а root здесь действительно нужен, потому что вы будете включать пересылку пакетов и править сетевые правила. В публичном предложении перечислены локации UK, US, RU и FR; расположение хаба имеет смысл выбирать ближе к большинству филиалов и серверных ресурсов, чтобы лишние задержки не набегали на каждом пакете. Для первого теста можно взять тариф Ba (1 vCPU, 2 ГБ RAM, 40 ГБ NVMe) или Uab (2 vCPU, 4 ГБ RAM, 80 ГБ NVMe) и посмотреть, как ведёт себя нагрузка. Если филиалов станет больше или появится тяжёлый трафик, старшие тарифы Heka, Maat и Djed дают больше ядер и памяти. Эти цифры — отправная точка для эксперимента, а не обещание ёмкости: реальную нагрузку покажут ваши замеры.
Новый филиал в общей картине
Когда одиннадцатый филиал заработал, адресный план нужно обновить сразу же, пока детали свежи. Вот как выглядит итоговая запись по нашему учебному плану:
| № | Туннельный адрес | LAN | Открыто на стороне филиала |
|---|---|---|---|
| 1 | 10.8.0.11/32 | 10.20.1.0/24 | по записи в реестре |
| … | … | … | … |
| 10 | 10.8.0.20/32 | 10.20.10.0/24 | по записи в реестре |
| 11 | 10.8.0.21/32 | 10.20.11.0/24 (ранее 10.8.0.0/24) | 10.8.0.1, 10.30.0.10, 10.30.0.53 |
В реестре важны не только строки, но и пометки. Запись «ранее 10.8.0.0/24» объясняет, почему у филиала сохранились старые закладки в документах и почему в его журналах могут встречаться старые адреса. Такие маленькие следы экономят часы тому, кто будет разбираться через год.
Ещё две строки стоит завести рядом с реестром. Первая: правило нарезки. «Туннель — 10.8.0.0/24, филиал N получает 10.8.0.(10+N). LAN — 10.20.N.0/24. Серверы — 10.30.0.0/24. Диапазон 10.40.0.0/16 — в резерве». Вторая: что делать, если у нового филиала адрес уже занят. Ответ из нашего разбора: сначала просить переселить его в свой диапазон, затем думать о трансляции, и только в крайнем случае переписывать туннель.
Когда придёт двенадцатый филиал, вы возьмёте реестр, найдёте свободный номер, спросите у местного администратора, какая у него сеть, и сверите её с таблицей. Если сеть чужая и свободная, останется выдать туннельный адрес по правилу, написать два списка AllowedIPs и проверить один сервис. Если сеть пересекается с планом, вы уже знаете три варианта решения и их цену. Расследовать, кто и зачем когда-то занял 10.8.0.0/24, больше не придётся: ответ уже записан в плане.