Apache перенаправление без номера порта

Вопрос или проблема

Это возможно не сработает, но всё же попробую: я хочу создать образ контейнера для Apache без необходимости работать от имени root. Я настроил VirtualHost на прослушивание порта 8080 вместо любого порта <1024. Перед Apache стоит прокси, который перенаправляет трафик с порта 80 на порт 8080 контейнера. Однако, когда я заставляю Apache делать редирект, он всегда добавляет порт в заголовок Location. Поэтому возвращаемый редирект выглядит как "Location: http://mysite:8080/index“, что не сработает, так как на порту 8080 нет публичного слушателя.

Есть ли способ сказать Apache никогда не добавлять номер порта к этим редиректам? Я пытался поиграть с UseCanonicalPhysicalPort, но это не дало желаемого эффекта. Есть ли способ предотвратить добавление номера порта к чему угодно?

ИЗМЕНЕНИЕ

Хорошо, похоже, это поведение закодировано в программе, когда я смотрю на исходный код mod_rewrite, я замечаю, что оно вызывает “ap_is_default_port”, чтобы определить, нужно ли добавлять порт в ответ или нет. Единственный способ переопределить это — переопределить эту строку в исходном коде, я думаю. Если кто-то знает лучший ответ, я все уши.

Слишком длинно для комментария

Имхо, вы пытаетесь решить не ту проблему

Проблема не в том, что Apache включает номер порта, на котором он слушает, в заголовок Location (потому что для Apache это правильное поведение, он действительно слушает на порту 8080), а проблема в том, что ваш обратный прокси это не исправляет.

Обычно обратный прокси должен переписывать заголовки расположения (и другие) и изменять любые ссылки на внутренние URI, которые используют серверы на заднем плане, на URI, которые клиенты должны использовать, чтобы достичь обратного прокси / балансировщика нагрузки.

Проверьте конфигурацию вашего обратного прокси (traefik), чтобы выяснить, почему этого не происходит.

Суть в том, что это можно достичь, отправив заголовок Host: mysite:80 в Apache, изменив конфигурацию обратного прокси. Обратите внимание, что часть :80 имеет значение. (К сожалению, этот ответ лежит вне конфигурации Apache, но поскольку редакция опроса спрашивает о любом лучшем ответе, это определенно лучше, чем модификация исходного кода Apache и его перекомпиляция.)

Пример фрагмента конфигурации Traefik:

labels:
  - "traefik.http.middlewares.testHeader.headers.customrequestheaders.Host=mysite:80"

Для nginx (который я тестировал более обширно):

proxy_set_header Host mysite:80;
# Или, чтобы использовать имя хоста из запроса:
proxy_set_header Host $host:80;
# Обратите внимание, что переменная $host никогда не содержит номера порта, даже если он присутствует в заголовке Host оригинального запроса.

Для HTTPS используйте 443 вместо этого. В любом случае, явный номер порта, равный порту по умолчанию для протокола, нужен в заголовке запроса, чтобы заставить Apache сгенерировать заголовок ответа без номера порта, например Location: http://mysite/index".


Как это работает:

Оказывается, Apache HTTPd генерирует URL-адреса перенаправления, смотря на заголовок запроса Host, а также на номер порта, на котором он слушает. Изучая исходный код (ссылка на него была в вопросе), эксперименты показывают, что Apache использует следующую последовательность предпочтений для того, чтобы сделать URL абсолютным (например, при генерации перенаправления Location):

  1. Явленный номер порта из Host, как в example.com:1111
  2. Порт, на котором слушает Apache (где был получен запрос), как в Listen 2222
  3. Порт по умолчанию протокола (443 для HTTPS, 80 для HTTP)

Интересно, что Host: example.com обрабатывается иначе, чем Host: example.com:80 на первом этапе. Я не специалист по IETF RFC, но ожидал бы, что первый является сокращением второго на основе правил нормализации URL, но, похоже, Apache интерпретировал это иначе и считает порт неопределенным в первом случае. Поэтому добавление номера порта к Host переопределяет порт прослушивания.

Перед генерацией заголовка Location Apache нормализует сгенерированный абсолютный URL. В этом процессе он осознает, что :80 является стандартным портом HTTP и исключает его из заголовка ответа, то же самое для https://myhost:443. Не углубляясь в детали исходного кода, URL прошел через цепочку преобразований вроде этого:

/index ==> http://mysite:80/index ==> http://mysite/index

…что является долгим и окольным путем к достижению желаемого результата. Я знаю, что это старый вопрос, но надеюсь, что это поможет следующему человеку, который сюда попал через поиск.

Ответ или решение

Перенаправление в Apache без указания номера порта: Полное решение вопроса

В данной статье мы разберем, как корректно настроить перенаправление в Apache без добавления номера порта в заголовок Location, особенно когда Apache работает на нестандартном порту (например, 8080) и перед ним расположен обратный прокси-сервер, который направляет трафик с порта 80.

Ситуация

Вы хотите создать контейнерный образ для Apache, который не требует запуска с привилегиями суперпользователя. Для этого вы настроили VirtualHost, чтобы он прослушивал порт 8080. Ваш обратный прокси (например, Traefik или Nginx) направляет трафик с порта 80 на порт 8080 внутри контейнера. Однако, когда Apache выполняет перенаправление, он добавляет номер порта в заголовок Location, что приводит к ошибке, так как клиент пытается обратиться к порту 8080, к которому нет доступа извне.

Причина проблемы

Apache добавляет номер порта в заголовок Location, основываясь на информации из заголовка Host, а также на порту, к которому он подключен. Стандартное поведение Apache подразумевает, что если запрос приходит на определенный порт, этот порт будет включен в ответ. Это поведение можно изменить, корректируя заголовок Host, который передается к серверу Apache.

Решение проблемы

Чтобы избежать добавления номера порта в заголовок Location, необходимо внести изменения в конфигурацию вашего обратного прокси, чтобы он отправлял правильный заголовок Host.

Для Nginx

Если вы используете Nginx в качестве обратного прокси, добавьте следующее в ваш конфигурационный файл:

proxy_set_header Host mysite:80;

Или, чтобы использовать хост, указанный в запросе:

proxy_set_header Host $host:80;
Для Traefik

Если вы используете Traefik, добавьте следующую метку в вашу конфигурацию:

labels:
  - "traefik.http.middlewares.testHeader.headers.customrequestheaders.Host=mysite:80"

Как это работает

Apache генерирует URL для перенаправления, анализируя заголовок Host и порт, на котором он слушает. Если заголовок Host содержит явный номер порта (например, mysite:80), то этот номер будет использоваться при формировании заголовка Location. Если такой номер отсутствует, Apache использует свой порт, который находится в конфигурации.

Последовательность, по которой Apache генерирует абсолютный URL, выглядит следующим образом:

  1. Явный номер порта из Host, например, example.com:1111.
  2. Порт, на котором Apache принимает запрос, например, Listen 8080.
  3. Стандартный порт для протокола (443 для HTTPS и 80 для HTTP).

Таким образом, если вы измените заголовок Host на mysite:80, Apache может правильно генерировать URL без добавления порта в заголовок Location.

Заключение

Корректируя заголовок Host, вы можете избежать добавления порта, на котором Apache слушает, в перенаправлениях. Это решение позволит вашему приложению правильно обрабатывать запросы без необходимости изменения исходного кода Apache, что является предпочтительным вариантом для поддержания безопасной и стабильной работы вашего сервера.

Если у вас остались вопросы или вам нужна помощь с конкретной конфигурацией, не стесняйтесь обращаться за дополнительными разъяснениями.

Оцените материал
Добавить комментарий

Капча загружается...