Почему Port-Share заставляет всех посетителей сайта выглядеть как localhost
Бэкенд видит шаг переадресации, а не браузер. Проверьте, где теряется адрес источника, и затем решите, какой компонент вправе за него ручаться.
Каждая строка в журнале доступа показывает один и тот же адрес loopback, хотя страница загружается и сертификат проверяется правильно. Ничего не сломано в смысле недоступности, и именно поэтому это тянется месяцами. Сломалось сопоставление: веб-бэкенд записывает адрес шага, который переслал соединение, и каждое последующее решение, доверявшее журналу, унаследовало тот же неверный ответ.
Проверки ниже идут от кабеля внутрь. Остановитесь на первой, которая объясняет видимое значение, потому что каждый следующий шаг предполагает, что предыдущие уже верны. Ни одна из них не требует угадывать конфигурацию фронтенда.
Следуйте двум соединениям, а не строке журнала
Port-Share мультиплексирует два протокола на одном слушателе TCP. OpenVPN проверяет первые байты входящего соединения, оставляет его, когда оно похоже на его собственный протокол, и передаёт всё остальное второму назначению. Это назначение обычно веб-сервер на том же хосте, поэтому принятый сокет веб-сервера имеет процесс OpenVPN в качестве партнёра.
ss -ltnp 'sport = :443'
ss -tnp 'dport = :8080'
Первая команда показывает, кому принадлежит публичный слушатель. Вторая показывает соединения, приходящие на порт бэкенда, и адрес их партнёра — это то, что напечатает журнал доступа. Если этот партнёр — loopback, журнал точен, а информация потерялась слоем раньше. Переименование поля в журнале или включение модуля IP клиента не вернёт адрес, который соединение никогда не несло.
Это проверка, которая решает всё остальное. Если партнёр бэкенда — адрес браузера, то совместное использование порта не ваша проблема, а формата журнала.
Пересылка транспорта — это не внедрение заголовка
Пересыльщик перемещает байты. Он не разбирает HTTP, поэтому не может вставить заголовок в запрос, который никогда не читает как запрос, и не может ничего добавить в поток TLS, который пропускает нетронутым. Модуль, ожидающий заголовок прокси, будет и дальше ждать тот, который не производит ни один компонент.
Исходный адрес могут нести два механизма, и оба требуют согласия на обоих концах. Протокол PROXY добавляет небольшой заголовок в начало соединения, и бэкенд должен быть настроен его ожидать; бэкенд, который его не ожидает, примет эти байты за начало запроса и откажет запутанным образом. Доверенные заголовки прокси вроде X-Forwarded-For работают, когда прокси, понимающий HTTP, их устанавливает, а бэкенду сообщают, какие партнёры вправе их подтверждать.
Ни то, ни другое не автоматично, и ни то, ни другое не безопасно по умолчанию. Бэкенд, который верит любому входящему пересланному заголовку, позволяет клиенту выбрать собственный адрес, что превращает неточность в журнале в обход контроля доступа. Запустите демонстрацию один раз на тестовом хосте, прежде чем доверять какому-либо заголовку на производственном пути.
curl -sS -H 'X-Forwarded-For: 127.0.0.1' https://site.example.com/health
grep -F '127.0.0.1' /var/log/nginx/access.log | tail -n 3
Необязательный каталог сопоставления источников
У совместного использования порта есть необязательный аргумент каталога, который записывает сопоставление между исходным адресом источника и пересылающим соединением на платформах, где эта функция реализована. Ожидается, что веб-сторона будет обращаться к этому сопоставлению; это не заголовок, и оно не внедряется в запрос.
Этот замысел стоит знать, потому что он объясняет, почему одни развёртывания сообщают настоящие адреса, а другие нет, при внешне одинаковой конфигурации фронтенда. Разница на принимающей стороне, и обычно она живёт в модуле или патче, который большинство упакованных веб-серверов не включает по умолчанию. Прочитайте в документации своего веб-сервера, какой именно хук он предлагает, и подтвердите, что модуль загружен, а не предполагайте это.
Если вы пойдёте этим путём, рассматривайте это как интеграцию из двух половин: сопоставление, которое пишет пересыльщик, и поиск, который выполняет бэкенд. Проверьте и то и другое и подтвердите, что каталог переживает перезапуск и не растёт безгранично на занятом слушателе.
Решите, какой компонент ручается за адрес
Прежде чем менять конфигурацию, назовите компонент, которому разрешено утверждать адрес клиента, и компоненты, которым разрешено ему верить. Один записанный ответ предотвращает обычный дрейф, когда три разных слоя доверяют каждый своему источнику.
Три схемы покрывают большинство потребностей. Держите публичный слушатель и веб-слушатель раздельно, чтобы веб-сервер видел настоящих партнёров и проблемы сопоставления не было. Поставьте впереди обратный прокси, понимающий HTTP, завершите или разберите запрос там и дайте ему установить пересланный заголовок для бэкенда, который доверяет только этому прокси. Либо оставьте совместное использование порта и примите, что журналы показывают шаг, а правила доступа пишутся против идентичности приложения, а не адреса.
Что не работает — это трактовка пересланного адреса loopback как доказательства того, что запрос возник на этой машине. Этот вывод прямо обратный: адрес присутствует именно потому, что локальный компонент установил соединение. Правило, написанное так, впускает каждого, кто может достичь слушателя.
Проверяйте правило, а не страницу
Загружающаяся страница доказывает, что путь пересылки работает, и ничего не говорит о сопоставлении. Проверьте потребителя адреса: правило доступа, ограничение скорости, запись аудита, географический поиск.
curl -sS -o /dev/null -w '%{http_code}\n' https://site.example.com/
tail -n 5 /var/log/nginx/access.log
grep -c '' /var/log/nginx/access.log
Сравните разрешённый внешний запрос с записями и фронтенда, и бэкенда и подтвердите, что правило, которое должно отказывать, по-прежнему отказывает, а то, которое должно допускать, по-прежнему допускает. Если строка журнала верна, но правило по-прежнему ведёт себя так, будто все локальны, правило читает другое поле, не то, которое вы исправили.
Завершите, записав цепочку сопоставления в заметки о развёртывании: какой слушатель, какой пересыльщик, какой заголовок или сопоставление и какой бэкенд настроен ему доверять. Следующему человеку, который прочтёт строку журнала, понадобятся все четыре, и именно отсутствие этой заметки заставляет тот же тикет открываться снова год спустя. Держите её рядом с конфигурацией, а не в ветке чата.