OpenVPN и HTTPS на порту 443: кому принадлежит слушатель?
TCP и UDP 443 — разные сокеты. Совместное использование одного TCP-слушателя требует владельца, а разделение порта OpenVPN — узкая договорённость, а не трюк с прокси.
Две службы могут обе отвечать на порту 443, никогда не конкурируя, потому что слушатель определяется транспортом, адресом и портом вместе, а не одним номером. Поставьте веб-сервер и OpenVPN на одну машину, и единственный вопрос, на который стоит ответить первым, — какой сокет каждый процесс просит у ядра. Запишите этот список до правки конфигурации, и большинство ошибок «адрес уже используется» объяснят себя сами. Всё после списка — это выбор между UDP-слушателем, общим TCP-сокетом или фронтендом, который маршрутизирует по протоколу.
Начните с сокета, который просит каждый процесс
Bind удаётся или не удаётся по этой тройке, поэтому два демона сталкиваются только тогда, когда совпадают все три части. Именно поэтому сайт на TCP 443 неограниченно сосуществует со слушателем OpenVPN на UDP 443, и поэтому же перенос одного из них на второй локальный адрес того же хоста тоже прекращает спор. Читайте живые слушатели, а не файлы, которые должны были их создать, потому что устаревший include или забытый unit-файл переживает правку, которую вы помните.
| Line in the listener list | What it establishes | What to do next |
|---|---|---|
| One udp row and one tcp row, each on 443 | Separate transport sockets, nothing contested | Point the VPN profile at udp and stop editing |
| A single tcp address and port listed by two processes | A real bind collision between two daemons | Move one service, or put a dispatcher in front of both |
| A proxy process owns the socket, no vpn process | The proxy accepts and has to hand off correctly | Check that its backend speaks the protocol it forwards |
Запустите ss -lntup от root и прочитайте каждую строку, где упоминается 443, включая записи IPv6. Обычно универсальный слушатель v6 принимает и трафик v4, и именно так забытый слушатель держит порт занятым после того, как вы изменили файл, который считали ответственным. Если имя процесса вас удивит, сузьте вывод с помощью ss -lntup 'sport = :443' прежде чем что-либо трогать.
Переключите туннель на UDP, когда сеть это позволяет
UDP-слушатель полностью обходит столкновение и обычно является самым коротким исправлением, поскольку ни один сокет не делится и никакой дополнительный продукт не встаёт на путь. Но это не бесплатно. Некоторые клиентские сети отбрасывают UDP 443, не отправляя reset, поэтому туннель перестаёт устанавливаться вместо того, чтобы не суметь bind, и пользователь сообщает, что VPN не работает, без ошибки для чтения. UDP-слушатель также переживает перезапуск веб-слоя, что важно на машине, чей сайт часто переразвёртывают. Проверяйте из сети, где сидят пользователи, потому что оболочка на сервере доказывает лишь то, что сервер достигает сам себя.
Меняйте транспорт в конфигурации сервера и в профиле клиента одновременно. Профиль, который всё ещё просит TCP, будет крутиться в циклах переподключений против слушателя только с UDP, и это выглядит как сбой сети, пока вы не сравните два файла.
Пусть процесс VPN владеет TCP 443, а остальное переправляется
Community OpenVPN в режиме TCP-сервера читает первые байты входящего соединения и переправляет всё, что не является его собственным протоколом, на HTTPS-бэкенд, и для этого служит директива port-share. Бэкенд — обычный веб-сервер с включённым TLS, названный в этой директиве хостом и портом, а не URL.
port-share 10.0.0.5 8080
На машине, где у сайта есть второй частный адрес, эта строка отправляет не-VPN трафик на 10.0.0.5:8080, поэтому виртуальный хост HTTPS должен быть привязан там, а брандмауэр должен разрешать локальный переход. Веб-сервер должен сам завершать TLS, потому что приходящие байты — это исходное рукопожатие браузера, и ничто между ними их не расшифровало. Направьте директиву на обычный HTTP-слушатель, и браузер получит ошибку недопустимого метода, которая читается как сломанный сайт, а не как неправильно размещённый бэкенд. Директива существует только в режиме TCP-сервера, а у UDP-слушателя нет потока для проверки.
Поскольку процесс VPN принимает каждое соединение, веб-приложение видит переправленный запрос приходящим с одного из собственных адресов хоста, а не от посетителя. Всё, что нуждается в настоящем адресе клиента, зависит от поддержки протокола PROXY в бэкенде или от фронтенда, который её добавляет. Перенос бэкенда на другой локальный адрес не возвращает адрес посетителя; он меняет только то, какой из адресов хоста сайт записывает. Запишите это ограничение в заметки о развёртывании, прежде чем отчёт аналитики поднимет вопрос.
Обратный прокси — неподходящий инструмент; маршрутизатор четвёртого уровня — нет
HTTP-обратный прокси завершает TLS, чтобы читать запросы, а значит, не может пропустить поток OpenVPN нетронутым. Маршрутизатор четвёртого уровня, который переправляет по SNI или по осмотру первого пакета, может стоять перед обоими, при условии что он не завершает сессию, от которой зависит VPN. Два устройства выглядят одинаково на схеме и ведут себя совершенно по-разному на сокете.
Коммерческий Access Server поставляется с собственными настройками разделения порта, и они не соответствуют директиве сообщества один к одному. Определите продукт и версию, прежде чем адаптировать руководство, написанное для другого. Скопированная настройка, которую молча игнорируют, хуже отсутствия настройки, потому что список слушателей после этого всё ещё выглядит правдоподобно.
Проверяйте сайт и туннель как два отдельных пути
Загрузите сайт и подключите туннель, затем снова прочитайте список слушателей, чтобы увидеть, какой процесс теперь владеет 443. Загрузившаяся страница ничего не доказывает о VPN, а подключившийся туннель ничего не доказывает о сайте, хотя оба используют один и тот же номер. Три команды ниже проверяют общий сокет, веб-путь и службу VPN именно в этом порядке.
ss -lntup 'sport = :443' curl -sI https://vpn.example.com/ | head -n 1 journalctl -u openvpn-server@server -n 20
Сравните адрес клиента в журнале доступа бэкенда с адресом в журнале VPN для одного и того же момента. Если сайт записывает каждого посетителя как сам хост, переправка работает, а обработка адреса — нет. Если оба журнала молчат, фронтенд так и не передал соединение. В любом случае список слушателей решает, кто принимает сокет, и именно это нужно подтвердить, прежде чем менять ещё один файл.
Оставьте эту карту слушателей рядом с конфигурацией, чтобы следующий человек, который тронет 443, знал, какой процесс принимает и куда ушёл другой протокол. Подтвердите владение после изменения, а не полагайтесь на то, что правка должна была сделать.