Сервер и клиент OpenVPN на одном хосте: почему клиенты отваливаются
Хост, который одновременно обслуживает OpenVPN и сам им пользуется, может держать туннель поднятым, а локальные клиенты при этом перестают получать ответы. Причин две: общий пул адресов и новый маршрут по умолчанию.
Добавьте клиентский профиль на машину, где уже работает VPN-сервер, и первой жертвой станет исходная служба. Новый туннель может вообще не подняться или подняться, а существующие клиенты сервера тихо перестанут получать ответы. Две коллизии дают оба результата: пул туннелей, который уже используется, и маршрут по умолчанию, установленный новой клиентской половиной и закрывающий всю таблицу. Ни одна из них не выдаёт сообщение об ошибке OpenVPN, поэтому сбой читают как проблему сервера.
Одна машина, две роли и два несовместимых ответа на вопрос, куда должны идти ответы.
Тот же пул, два сервера: кто побеждает
Каждому экземпляру сервера нужна собственная подсеть туннеля. Копирование строки вроде server 10.8.0.0 255.255.255.0 во вторую конфигурацию даёт двум экземплярам один и тот же префикс, и итог — либо отказ запускаться, либо тихая борьба, в которой клиенты одного сервера получают адреса, которые другой тоже считает своими. Разные UDP-порты и разные имена устройств не помогают, потому что ни то ни другое не затрагивает адресное пространство. Смените второй пул и смените его везде, где маршруты о нём упоминают.
Перечислите, что уже работает, перед правками: ip -4 addr show показывает туннельные устройства, ss -lunp показывает слушателей, а systemctl list-units называет юниты. Одного взгляда на адреса туннелей достаточно, чтобы понять, пересекаются ли пулы.
Что клиентский профиль добавляет в таблицу
Клиентская половина пишет маршруты сразу после подключения. redirect-gateway def1 делит маршрут по умолчанию на 0.0.0.0/1 плюс 128.0.0.0/1, оба идут через новое устройство, вместе с маршрутом к хосту удалённого сервера, намеренно привязанным к физическому интерфейсу. Эта привязка нужна, чтобы туннель сохранял путь для собственного транспорта. Всё остальное, включая ответы, которые локальный сервер должен своим клиентам, теперь идёт по новому маршруту по умолчанию и уходит через удалённый канал.
Значит, вторая коллизия — не сломанный туннель. Это работающий туннель не на своём месте в таблице.
Три способа развести роли
Наименее инвазивное исправление убирает маршрут по умолчанию из клиентского профиля: route-nopull плюс явные строки route для удалённых префиксов, так что локальная таблица меняется только там, где вы просили. Следующий шаг — правило политики, освобождающее локальную подсеть туннеля: ответы локальным клиентам уходят через тот интерфейс, по которому пришли, даже при наличии маршрута по умолчанию. Самое основательное — отдельное сетевое пространство имён для клиентской роли: оно полностью убирает общую таблицу, но требует второго контекста маршрутизации в обслуживании.
Какой бы путь вы ни выбрали, исключение должно называть локальную подсеть туннеля, а не LAN. У ответа, который отправляет локальный сервер, пункт назначения — адрес туннеля, поэтому исключение в форме LAN к нему никогда не подходит.
Который из двух экземпляров виноват
Остановите клиентский экземпляр и перепроверьте исходных клиентов. Мгновенное восстановление означает маршрутизацию, а не сервер. Верните клиент и проследите один ответ с помощью ip route get, которому заданы и адрес источника, и адрес назначения: он показывает путь, который выберет ядро, после чего посмотрите на интерфейс, который пакеты реально используют, с помощью tcpdump -ni any port 1194. Файл состояния сервера, записываемый каждые несколько секунд через директиву status, содержит список подключённых клиентов и счётчики байтов в обе стороны.
Сверьте эти счётчики между собой. Трафик, который уходит и не возвращается, — это ответ про маршрутизацию, а не проблема рукопожатия.