Редирект портов в Nginx: перенаправление между 80, 443 и нестандартными портами | AdminWiki

Редирект портов в Nginx: перенаправление между 80, 443 и нестандартными портами

05 сентября 2026 16 мин. чтения
Содержание статьи

В Nginx выбор зависит от результата, который должен получить клиент. Если браузер или API-клиент должен перейти на новый адрес, схему или внешний порт, сервер возвращает HTTP-ответ 301 или 302 с заголовком Location. Если пользователь должен сохранить URL, а запрос нужно передать приложению на 127.0.0.1:8080, 9000, 8443 или другом endpoint, используется proxy_pass.

Пример: запрос к http://example.com обычно перенаправляют с порта 80 на https://example.com через return 301. Запрос к https://example.com, который должен обслужить приложение на локальном порту 8080, проксируют через proxy_pass http://127.0.0.1:8080;. В браузере при этом остается адрес с портом 443.

HTTP-редирект не переносит пакеты и не открывает доступ к сервисному порту. Nginx отправляет ответ, клиент получает новый URL и самостоятельно выполняет второй запрос. При reverse proxy клиент общается только с Nginx, а соединение с backend устанавливает сам сервер.

Короткий ответ: редирект меняет URL, а proxy_pass передает запрос

Когда использовать 301 или 302

Код 301 Moved Permanently подходит для постоянного изменения адреса. Типичный пример, редирект с HTTP на HTTPS после полной проверки TLS-конфигурации. Браузеры и поисковые роботы могут запоминать такой ответ, поэтому менять направление 301 во время диагностики неудобно.

Код 302 Found применяют для временного перехода. Он подходит для тестовой публикации, миграции приложения, временного вывода сервиса на порт 8443 или проверки нового домена. Клиент получает новый адрес через заголовок Location:

HTTP/1.1 302 Found
Location: https://example.com:8443/app/

В конфигурации Nginx статус задает директива return:

return 301 https://example.com$request_uri;
return 302 https://example.com:8443$request_uri;

Для рабочих изменений сначала используйте 302. После проверки замените его на 301, если переход должен стать постоянным.

Когда использовать proxy_pass

proxy_pass нужен, когда Nginx выступает обратным прокси. Клиент подключается к публичному адресу, а Nginx передает запрос внутреннему сервису. Приложение может слушать 127.0.0.1:8080, адрес Docker-сервиса или внутренний IP отдельного узла.

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

URL в браузере не меняется. Порт 8080 остается внутренней деталью схемы, а наружу можно оставить доступ только к 443. Подробный разбор reverse proxy, TLS-терминации и заголовков приведен в пошаговом руководстве по обратному прокси на Nginx.

Что происходит с портом в адресе

СценарийЧто видит клиентЧто делает Nginx
Редирект 80 на 443Сначала HTTP, затем HTTPSВозвращает 301 или 302 с новым URL
Прокси на localhost:8080Только публичный домен и HTTPSПередает запрос приложению на 8080
Редирект на внешний 8443Адрес с явным :8443Сообщает клиенту подключиться к новому порту
Прокси на внутренний 8443Публичный адрес без :8443Сам устанавливает соединение с сервисом на 8443

Порты 80 и 443 считаются стандартными для HTTP и HTTPS, поэтому браузер обычно не показывает их в URL. Порт 8080, 8443 или 18080 виден пользователю только при редиректе на полный адрес с этим номером.

Как сделать редирект в Nginx с 80 на 443

Постоянный редирект HTTP на HTTPS

Для перенаправления всех HTTP-запросов создайте отдельный server block с listen 80. Простое правило через return легче проверить и поддерживать, чем набор правил rewrite.

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    return 301 https://$host$request_uri;
}

$host сохраняет имя хоста из запроса в нормализованном виде. $request_uri содержит путь и параметры запроса, поэтому переход с /login?next=dashboard сохранит полный URI.

Если нужен один канонический домен, укажите его явно:

return 301 https://example.com$request_uri;

Такой вариант заодно объединяет обращения к www.example.com и example.com в один адрес. Проверьте, что DNS обоих имен указывает на нужный Nginx.

Временный 302 для проверки настройки

На этапе проверки замените статус:

return 302 https://$host$request_uri;

Браузер может кэшировать 301, поэтому результат теста иногда сохраняется даже после изменения конфигурации. Для диагностики используйте curl, приватное окно браузера или отдельное тестовое имя. После проверки выполните замену 302 на 301 и еще раз проверьте заголовок Location.

Редирект на HTTPS не проверяет доступность порта 443. Он только сообщает клиенту новый адрес. Если на 443 нет работающего TLS server block, пользователь получит ошибку соединения после корректного ответа 301.

Что должно работать на 443

Для приема HTTPS-запросов нужен server block с четырьмя обязательными элементами:

  • listen 443 ssl;;
  • корректный server_name;
  • путь к ssl_certificate;
  • путь к ssl_certificate_key.
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

В этом блоке location может отдавать статику, передавать запрос приложению или возвращать другой ответ. Полная конфигурация reverse proxy приведена в следующем разделе. Дополнительные готовые server block для SSL, proxy_pass и типовых задач собраны в подборке рабочих конфигураций Nginx.

Проксирование с 443 на backend с нестандартным портом через proxy_pass

Минимальный HTTPS reverse proxy на localhost:8080

Схема выглядит так: клиент подключается к https://example.com:443, Nginx расшифровывает TLS и отправляет обычный HTTP-запрос локальному приложению на 8080.

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Заголовки передают приложению сведения о первоначальном запросе:

  • Host сообщает домен, который запросил клиент;
  • X-Real-IP содержит адрес клиента, который видит Nginx;
  • X-Forwarded-For сохраняет цепочку адресов прокси;
  • X-Forwarded-Proto сообщает, что снаружи использовалась схема HTTPS.

Без этих заголовков приложение может записывать IP Nginx вместо IP пользователя, формировать неправильные абсолютные ссылки или отправлять повторный редирект на HTTPS.

Backend на другом сервере или Docker-хосте

Внутренний сервис может находиться на другом узле:

location / {
    proxy_pass http://192.168.50.10:18080;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Адрес 192.168.50.10:18080 должен быть доступен именно с сервера, где работает Nginx. Проверка с ноутбука администратора не заменяет проверку с Nginx-хоста. Убедитесь, что backend слушает нужный интерфейс, маршрут существует, а firewall разрешает соединение от IP Nginx.

В Docker-сети вместо IP часто используют DNS-имя сервиса:

location / {
    proxy_pass http://app:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Имя app разрешится только внутри подходящей Docker network. Если Nginx работает на хосте, а приложение в контейнере, используйте опубликованный порт хоста или отдельный сетевой маршрут.

Для отдельного Nginx-узла, тестового стенда или Docker-хоста подойдет облачный сервер с изменяемыми ресурсами. Например, Timeweb Cloud предлагает VDS, VPS, базы данных, хранилище и Kubernetes, что позволяет вынести reverse proxy на самостоятельный узел.

Как завершающий слэш в proxy_pass меняет URI

Завершающий слэш определяет, сохранит ли Nginx префикс из location. Сравните два варианта:

location /app/ {
    proxy_pass http://127.0.0.1:8080;
}

Запрос к /app/users уйдет на backend как /app/users, потому что URL передается целиком.

location /app/ {
    proxy_pass http://127.0.0.1:8080/;
}

В этом случае префикс /app/ заменяется на /. Запрос /app/users попадет на backend как /users.

Ошибка в завершающем слэше часто приводит к ответу 404. Проверяйте фактический путь в access log Nginx и логах приложения. Для маршрутизации нескольких URI пригодится руководство по location, proxy_pass и rewrite.

Проксирование WebSocket и долгих соединений

Обычного HTTP-проксирования недостаточно для WebSocket. Передайте upgrade-заголовки и включите HTTP/1.1:

location /socket/ {
    proxy_pass http://127.0.0.1:9000;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection upgrade;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_read_timeout 3600s;
}

Редирект 301 или 302 не заменяет такое проксирование. При редиректе клиент должен заново подключиться к новому адресу, а WebSocket-сервису требуется корректное установление длительного соединения через Nginx.

Практические сценарии: перенос приложения, временная публикация и единая точка входа

Перенос приложения на другой внутренний порт

Исходная схема: пользователи открывают https://example.com, а приложение работает на 127.0.0.1:8080. После миграции приложение слушает 127.0.0.1:18080. Публичный URL менять не требуется.

Для миграции измените endpoint в upstream:

upstream app_backend {
    server 127.0.0.1:18080;
}

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://app_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  1. Запустите приложение на новом порту.
  2. Проверьте его с Nginx-хоста: curl http://127.0.0.1:18080/health.
  3. Проверьте синтаксис: nginx -t.
  4. Примените изменения: systemctl reload nginx.
  5. Проверьте публичный URL через HTTPS.
  6. Закройте старый порт 8080 после подтверждения работы.

Пользователи не видят внутреннюю миграцию и продолжают обращаться к тому же домену.

Временная публикация сервиса на 8443

Сначала определите, должен ли пользователь видеть номер порта.

Если клиент должен перейти на https://example.com:8443, настройте внешний TLS-порт 8443 и верните временный редирект:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    return 302 https://example.com:8443$request_uri;
}

server {
    listen 8443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Порт 8443 должен быть разрешен в firewall и доступен из сети клиента. На нем должен работать TLS handshake с сертификатом для имени example.com. Сертификат не привязывается к номеру порта, но TLS-сервис обязан использовать подходящий сертификат.

Если номер 8443 не должен появляться в браузере, оставьте вход на 443 и проксируйте запрос во внутренний сервис:

location /temporary/ {
    proxy_pass http://127.0.0.1:8443;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Для временного публичного адреса используйте 302. Это упростит отмену теста и снизит риск долгого кэширования.

Объединение нескольких сервисов за одним Nginx

Один Nginx может обслуживать несколько приложений через разные поддомены:

server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 443 ssl;
    server_name admin.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Схема с поддоменами обычно проще для приложений. Каждое приложение получает собственный корневой путь, отдельные правила доступа и понятный адрес.

Маршрутизация через подпути выглядит так:

location /app/ {
    proxy_pass http://127.0.0.1:8080/;
}

location /admin/ {
    proxy_pass http://127.0.0.1:9000/;
}

Перед выбором подпути проверьте, умеет ли приложение работать с базовым префиксом /app/ или /admin/. Многие панели и API формируют абсолютные ссылки с корнем /, что приводит к загрузке ресурсов не из того location.

Редирект с 443 на нестандартный внешний порт

Nginx может перенаправить HTTPS-клиента на внешний порт 8443:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    return 302 https://example.com:8443$request_uri;
}

После ответа 302 клиент сам подключится к 8443. Поэтому нужно проверить три условия:

  • клиент видит маршрут к порту 8443;
  • firewall пропускает входящие соединения на 8443;
  • на 8443 работает TLS-сервис с сертификатом для нужного имени.

Для постоянного перехода замените 302 на 301. В большинстве публичных схем безопаснее оставить один вход на 443 и использовать proxy_pass. Так внутренние сервисные порты не приходится раскрывать клиентам и фильтровать в нескольких местах.

SSL и схема запроса: как избежать циклических редиректов

TLS завершается на Nginx, backend работает по HTTP

Распространенная схема выглядит так:

клиент - HTTPS:443 - Nginx - HTTP:8080 - приложение

Шифрование заканчивается на Nginx. Внутренний HTTP-трафик идет по localhost или защищенной серверной сети и не означает, что внешний сайт работает без HTTPS.

Передайте приложению исходную схему:

proxy_set_header X-Forwarded-Proto $scheme;

Приложение должно доверять этому заголовку только от известного reverse proxy. Иначе клиент сможет подставить собственное значение и повлиять на логику формирования ссылок или редиректов.

Как возникает бесконечный HTTPS-редирект

Цикл появляется, когда внешний балансировщик или CDN принимает HTTPS, а до Nginx подключается по HTTP. Для Nginx значение $scheme в такой схеме равно http. Если server block отправляет каждый такой запрос на HTTPS, балансировщик снова передает его Nginx по HTTP, и переход повторяется.

Проверьте, где завершается TLS:

  • если TLS завершается на балансировщике, канонический редирект лучше выполнять там;
  • если редирект выполняет Nginx, балансировщик должен передавать достоверный X-Forwarded-Proto: https;
  • приложение и Nginx должны быть настроены на доверие к заголовку только от адресов балансировщика;
  • проверьте, не отправляет ли само приложение дополнительный переход на HTTPS.

Не используйте значение X-Forwarded-Proto от любого внешнего клиента без фильтрации. Иначе пользователь сможет подменить схему запроса.

Когда backend сам требует HTTPS

Если внутренний сервис слушает TLS на 8443, укажите схему https в proxy_pass:

location / {
    proxy_pass https://127.0.0.1:8443;

    proxy_ssl_server_name on;
    proxy_ssl_name backend.example.internal;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

proxy_ssl_server_name on включает передачу SNI backend-сервису. proxy_ssl_name задает имя, с которым внутренний сервер выбирает сертификат. Если сертификат backend выпущен внутренним центром сертификации, добавьте этот CA в доверенное хранилище Nginx и включите проверку сертификата. Отключать проверку через proxy_ssl_verify off допустимо только для изолированной диагностики, но не для рабочей схемы.

Сертификат и нестандартный порт

TLS-сертификат связан с именем хоста, а не с номером порта. Один сертификат для example.com может обслуживать 443 и 8443. На каждом порту все равно должен работать корректный TLS server block, а firewall должен пропускать соединения.

Если клиент обращается к https://example.com:8443, сертификат проверяется для имени example.com. Ошибка появится, если сервис на 8443 отдаст сертификат для другого имени или вообще будет ожидать обычный HTTP.

Сетевой доступ: localhost, Docker и firewalld

Что означает localhost для Nginx

127.0.0.1 указывает на текущий сетевой namespace. Если Nginx работает на хосте, 127.0.0.1:8080 означает порт хоста. Если Nginx запущен в контейнере, это порт самого контейнера, а не соседнего контейнера и не Docker-хоста.

  • Nginx на хосте, приложение на хосте: используйте 127.0.0.1:8080, если приложение слушает loopback.
  • Nginx в Docker, приложение в той же Docker-сети: используйте имя сервиса и внутренний порт, например http://app:8080.
  • Nginx в Docker, приложение на хосте: настройте доступ к адресу хоста, который доступен из контейнера.
  • Приложение на другом сервере: используйте внутренний IP или DNS-имя и проверьте маршрут с Nginx.

Ошибка в понимании localhost часто приводит к 502 Bad Gateway, хотя само приложение работает.

Docker port publishing и доступ через хост

Публикация Docker-порта сочетает перенаправление и фильтрацию пакетов. Запрос к опубликованному адресу может проходить через маршрутизацию Docker-хоста, даже если прямой запрос к адресу контейнера не работает.

Проверьте фактическую публикацию:

docker ps
docker inspect my-app
ss -ltnp
ip route

Смотрите адрес привязки порта. Запись вида 127.0.0.1:18080->8080/tcp ограничивает доступ хостом. Публикация на 0.0.0.0:18080 разрешает подключение через сетевые интерфейсы, если firewall и маршрут пропускают трафик.

Проверяйте доступность с нескольких точек:

  • с самого Nginx-хоста;
  • с узла LAN;
  • с внешнего сервера;
  • через публичный URL Nginx.

Сервис может быть доступен через IP Docker-хоста и опубликованный порт, но недоступен по прямому IP контейнера. Поэтому тест одного адреса не описывает все сетевые пути.

Почему reload firewalld может изменить доступность

При штатной интеграции Docker с firewalld создается зона docker с политикой ACCEPT и правило docker-forwarding. Эти настройки участвуют в пересылке трафика к контейнерам и опубликованным портам.

В затронутых конфигурациях reload firewalld может удалить правила Docker, после чего Docker Engine восстанавливает их по уведомлению firewalld. Из-за этого после изменения firewall сервис иногда становится доступен по другому пути или временно теряет доступность.

Для сценария с Docker известна регрессия CVE-2025-54388. Она затрагивала Moby/Docker Engine версий 28.2.0-28.3.2. Исправление выпустили в версии 28.3.3 29 июля 2025 года. Версию нужно проверять на сервере Docker:

docker version --format '{{.Server.Version}}'

Версия клиента Docker не подтверждает версию демона. Сама проблема не открывает неопубликованные порты в интернете автоматически. Для обхода фильтрации нужен подходящий маршрут через Docker-хост, поэтому проверяйте фактическую топологию сети.

Проверка каждого сетевого маршрута

Сначала зафиксируйте карту соединений:

  1. откуда приходит клиент;
  2. на каком IP и порту слушает Nginx;
  3. на каком IP и порту слушает backend;
  4. через какой адрес Nginx обращается к backend;
  5. какие правила Docker и firewall обрабатывают пакет.

Базовые проверки на Nginx-хосте:

curl -v http://127.0.0.1:8080/health
curl -v http://192.168.50.10:18080/health
ss -ltnp
firewall-cmd --list-all
ip route get 192.168.50.10

Если первый запрос работает, а второй завершается ошибкой, проблема находится между узлами или в bind-адресе backend. Если оба запроса работают, но публичный URL возвращает 502, проверяйте активный server block, имя upstream, SELinux-политику и error log Nginx.

Как проверить редирект в Nginx через curl

Проверка активной конфигурации и reload

Сначала убедитесь, что Nginx читает файл, который вы изменили:

nginx -t
nginx -T
systemctl reload nginx

nginx -t проверяет синтаксис. Команда nginx -T выводит объединенную активную конфигурацию, включая подключенные файлы. Найдите в ней нужный server_name, listen, return и proxy_pass.

Синтаксическая проверка не подтверждает доступность backend. Nginx может успешно загрузить конфигурацию с ошибочным IP, закрытым портом или недоступным Docker-сервисом.

Проверка редиректа с 80 на 443

Запросите только заголовки:

curl -I http://example.com/path

Ожидаемый результат:

HTTP/1.1 301 Moved Permanently
Location: https://example.com/path

Для проверки параметров запроса используйте URL с query string:

curl -I 'http://example.com/path?mode=full'

В заголовке Location должен сохраниться путь и параметр mode=full. Для просмотра всей цепочки применяйте:

curl -vkL --max-redirs 5 http://example.com/path

Ключ -L разрешает переходы, а --max-redirs 5 ограничивает их число. Если команда завершается после нескольких повторений, проверяйте цикл между балансировщиком, Nginx и приложением.

Проверка HTTPS и backend-порта

Сначала проверьте TLS и публичный server block:

curl -vkI https://example.com/path

Затем проверьте backend напрямую с узла Nginx:

curl -v http://127.0.0.1:8080/health

Для внешнего нестандартного TLS-порта используйте:

curl -vkI https://example.com:8443

Если DNS еще не переключен, можно проверить конкретный IP через --resolve:

curl -vkI --resolve example.com:443:192.0.2.10 https://example.com/

Такой запрос сохраняет имя example.com для TLS и заголовка Host, но подключается к указанному IP.

Диагностика по статусам и логам

РезультатВероятная причинаЧто проверить
301 или 302Редирект работаетLocation, схему, домен, порт и путь
200 на HTTPЗапрос попал в другой server blockserver_name, порядок блоков и default_server
404Неверный URI или locationЗавершающий слэш в proxy_pass и маршрут приложения
500Ошибка самого приложенияЛоги backend и переменные окружения
502Nginx не получил ответ от upstreamАдрес, порт, bind, маршрут, firewall и доступность backend
504Истекло время ожиданияСостояние приложения, сетевую задержку и proxy_read_timeout

Для детализации используйте журналы:

tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
journalctl -u nginx -f

В access log смотрите фактический URI, статус и время ответа. В error log Nginx обычно указывает причину 502, например отказ соединения, тайм-аут или ошибку DNS.

Типовые ошибки, защита backend-порта и итоговый чек-лист

Как ограничить прямой доступ к сервисному порту

Если приложение нужно только Nginx, привяжите его к loopback:

127.0.0.1:8080

Для Docker ограничьте публикацию:

ports:
  - '127.0.0.1:18080:8080'

Такой bind разрешает доступ к опубликованному порту только с Docker-хоста. Если backend должен принимать запросы от отдельного Nginx-сервера, используйте внутренний IP и правило firewall, которое разрешает соединения только от адреса Nginx.

Проверьте, что сервис не слушает 0.0.0.0 без необходимости. С внешнего узла протестируйте публичные и сервисные порты отдельно. Закрытый порт на одном IP не доказывает недоступность сервиса через другой IP, Docker-хост или LAN-маршрут.

Почему вместо редиректа приходит 200, 404 или 502

  • 200 на HTTP. Запрос обслуживает другой server block. Проверьте server_name, директивы listen и наличие default_server.
  • 404 после proxy_pass. Проверьте URI и завершающий слэш. При location /app/ варианты с proxy_pass http://backend; и proxy_pass http://backend/; передают разные пути.
  • 502 Bad Gateway. Проверьте, слушает ли backend нужный адрес, доступен ли порт с Nginx, не блокирует ли соединение firewall и совпадает ли сетевой namespace.
  • 500 Internal Server Error. Ищите причину в логах приложения. Nginx может корректно передать запрос и вернуть полученный от backend статус.
  • Редирект не работает после изменения файла. Выполните nginx -t, посмотрите вывод nginx -T и примените systemctl reload nginx.

Почему редирект зацикливается

Проверьте цепочку HTTP - HTTPS - HTTP:

  1. определите компонент, который завершает TLS;
  2. проверьте значение $scheme на Nginx;
  3. проверьте заголовок X-Forwarded-Proto от доверенного балансировщика;
  4. проверьте настройки trusted proxy в приложении;
  5. убедитесь, что приложение не отправляет собственный повторный редирект;
  6. посмотрите всю цепочку через curl -vkL --max-redirs 5.

Канонический редирект должен находиться в одном понятном месте. Если HTTPS принимает внешний балансировщик, чаще всего переход HTTP на HTTPS настраивают там, а до Nginx передают уже подтвержденную схему запроса.

Финальный чек-лист перед применением

  1. Определен публичный URL и нужная схема, HTTP или HTTPS.
  2. Выбран механизм: 301/302 для нового адреса, proxy_pass для передачи запроса backend.
  3. На этапе тестирования используется 302, а не 301.
  4. На 443 настроены listen 443 ssl, server_name, ssl_certificate и ssl_certificate_key.
  5. Backend отвечает с узла, где работает Nginx.
  6. Проверены bind-адрес, Docker network, опубликованные порты и сетевой маршрут.
  7. Сервисный порт закрыт для внешних клиентов, если он не должен быть публичным.
  8. Проверены правила Docker и firewalld после reload.
  9. Версия Docker Engine проверена командой docker version --format '{{.Server.Version}}'.
  10. Выполнены nginx -t и systemctl reload nginx.
  11. Проверены запросы к 80, 443 и нужному нестандартному порту через curl.
  12. Просмотрены access log, error log и журналы приложения.

Правило выбора короткое: новый URL для клиента требует HTTP-редиректа 301 или 302. Сохранение публичного URL и передача запроса на сервисный порт требуют proxy_pass. Порты 80, 443 и 8443 в этом случае описывают разные точки входа, а не один и тот же механизм.

Поделиться:
Сохранить гайд? В закладки браузера