Выберите продукт

ERR_TOO_MANY_REDIRECTS в Nginx и Apache за reverse proxy на Debian/Ubuntu: где искать цикл редиректов

Если сайт уходит в ERR_TOO_MANY_REDIRECTS, причина обычно в конфликте редиректов между Nginx, Apache, приложением, CDN или reverse proxy. Разберём, как быстро найти источник цикла на Debian/Ubuntu, проверить X-Forwarded-Proto и исправить конфиг без хаотичных правок.
ERR_TOO_MANY_REDIRECTS в Nginx и Apache за reverse proxy на Debian/Ubuntu: где искать цикл редиректов

Ошибка ERR_TOO_MANY_REDIRECTS почти всегда означает одно: в цепочке запроса несколько компонентов одновременно пытаются навязать «правильный» URL. Один слой переводит трафик на HTTPS, второй меняет хост, третий повторяет то же самое, но уже по своим условиям. В результате браузер получает бесконечную последовательность 301 или 302 и останавливается.

Чаще всего проблема всплывает в связках, где Nginx или Apache работают не напрямую, а за reverse proxy, CDN, балансировщиком или отдельным SSL-терминатором. Backend видит локальный HTTP и не понимает, что клиент снаружи уже пришёл по HTTPS. Если к этому добавить старые правила в .htaccess, логику CMS или CDN в неподходящем режиме, цикл редиректов почти гарантирован.

На Debian и Ubuntu это встречается в очень разных стеках: Nginx перед Apache, Apache за Nginx, PHP-FPM, Node.js, Python-приложения, WordPress, панели управления, контейнеры. Симптомы похожи: сайт открывается только в инкогнито, после включения сертификата всё сломалось, через curl виден 301 по кругу, а в браузере ошибка появляется не на всех URL.

Главная ошибка при диагностике — править всё подряд. Отключают HSTS, меняют DNS, переписывают правила CMS, трогают CDN, перезапускают сервисы и только запутывают схему. Намного быстрее пройтись по цепочке запроса и установить, кто именно создаёт редирект и на основании какого признака.

Практическое правило простое: редирект на HTTPS и канонизацию хоста лучше держать в одном понятном месте. Как только это решение одновременно принимают два-три слоя, вероятность получить too many redirects резко растёт.

Как обычно выглядит цикл редиректов

Самый частый сценарий такой: пользователь открывает https://example.com, внешний прокси завершает TLS и отправляет запрос на backend по HTTP. Backend не знает о внешнем HTTPS, видит обычный порт 80 и отвечает редиректом на HTTPS. Прокси снова принимает HTTPS от клиента, снова шлёт HTTP внутрь, backend снова отвечает редиректом. Получается бесконечный круг.

Второй популярный сценарий — конфликт канонического хоста. Например, Nginx переводит www.example.com на домен без www, а приложение или Apache делает обратное. С технической точки зрения это тот же redirect loop, хотя внешне кажется, что проблема не в схеме, а в имени хоста.

Отдельная категория — CDN и внешние прокси. Если внешний слой по-своему трактует схему, а origin делает жёсткий redirect без учёта заголовков прокси, конфликт становится системным. Особенно часто такое происходит после «быстрых» настроек SSL, когда часть логики уже перенесли наружу, а старые правила на backend остались.

Если пока неясно, кто именно делает 301 или 302, не начинайте с правок конфигов. Сначала докажите источник редиректа по заголовкам ответа и журналам.

С чего начинать диагностику на Debian/Ubuntu

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

curl -I http://example.com
curl -I https://example.com
curl -IL http://example.com
curl -IL https://example.com

Если вы видите повтор одной и той же схемы или прыжки между http и https, это уже хороший маркер. Например, http://example.com уходит на https://example.com, а затем снова появляется редирект на тот же адрес. Это обычно означает, что backend заново выполняет уже сделанное перенаправление.

Второй шаг — понять, какой компонент отвечает первым. Смотрите на заголовки ответа, но не полагайтесь только на Server. Намного полезнее параллельно открыть логи Nginx и Apache и повторить запрос.

sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log
sudo tail -f /var/log/apache2/access.log /var/log/apache2/error.log

Если запрос виден в Nginx, но не доходит до Apache, редирект создаётся на стороне Nginx или ещё выше. Если Apache отвечает 301, а Nginx только проксирует наружу, искать нужно в Apache, .htaccess или приложении. Если в локальных логах пусто, а клиент уже получает редирект, значит проблема часто находится на CDN или внешнем балансировщике.

Третий шаг — описать цепочку запроса буквально на бумаге:

  • где завершается TLS;
  • какой протокол идёт между прокси и backend;
  • какие заголовки прокси передаёт дальше;
  • кто отвечает за редирект HTTP на HTTPS;
  • кто отвечает за канонический хост.

Если на любой из этих вопросов ответ звучит как «кажется, это настроено в нескольких местах», источник проблемы уже почти найден.

Схема цикла редиректов между браузером, reverse proxy и backend

Почему критичен X-Forwarded-Proto

Когда reverse proxy принимает HTTPS, а backend получает обычный HTTP, серверу нужен признак исходной схемы. Обычно для этого используется заголовок X-Forwarded-Proto. Если прокси передаёт значение https, backend может понять, что повторный редирект не нужен.

Но важен не только сам заголовок. Backend, Apache-модуль, Nginx-конфиг или приложение должны ещё и доверять ему. Если сервер ориентируется только на локальное соединение, он продолжит считать запрос HTTP, даже если перед ним уже был внешний защищённый слой.

Ещё одна частая ошибка — заголовок передаётся не во всех местах. Для основного домена всё работает, а у поддомена забыли добавить нужные proxy_set_header. Или часть правил Apache смотрит на %{HTTPS}, а часть — на X-Forwarded-Proto, из-за чего поведение зависит от конкретного URL.

Именно поэтому при любой диагностике циклов полезно отдельно проверить, что backend отвечает без заголовка и что меняется, если передать его вручную. Это быстро показывает, проблема в схеме или в чём-то другом.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Проверяем Nginx как frontend reverse proxy

Если Nginx стоит перед Apache, PHP-приложением или другим backend, его базовая задача — не только проксировать запрос, но и передавать корректный набор заголовков. В минимальном наборе обычно нужны Host, X-Real-IP, X-Forwarded-For и X-Forwarded-Proto.

location / {
    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_pass http://127.0.0.1:8080;
}

Переменная $scheme передаёт backend ту схему, с которой пришёл клиент именно на этот виртуальный хост Nginx. Если запрос пришёл на HTTPS-сервер, backend увидит https. Если это порт 80, увидит http.

Проблема начинается, когда Nginx сам находится за ещё одним прокси или CDN. Тогда локально он может видеть только HTTP, даже если пользователь пришёл по HTTPS на внешний edge-слой. В такой схеме важно либо доверять заголовкам внешнего прокси, либо выстраивать передачу схемы дальше по цепочке без потерь.

Опасный шаблон — жёсткий redirect на HTTPS на внутреннем backend-сервере:

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

Если этот Nginx не является внешней точкой входа, а принимает HTTP от прокси, такой конфиг почти гарантированно создаст цикл. Для внутреннего сервера этого уровня редирект без учёта прокси-заголовков чаще вреден, чем полезен.

Если вы размещаете сайты на VDS, удобно заранее зафиксировать простую схему: внешний слой делает redirect, внутренний только понимает, что запрос уже был HTTPS. Это же облегчает перенос конфигов между окружениями и снижает риск поломок после обновлений.

Проверяем Apache за reverse proxy

С Apache ситуация похожая, но источников путаницы обычно больше: VirtualHost, mod_rewrite, файлы сайта, include-конфиги, .htaccess и правила самого приложения. Поэтому циклы в Apache часто появляются не из-за одной ошибки, а из-за накопления нескольких старых настроек.

Типовой пример — правило «если HTTPS выключен, отправить на HTTPS»:

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Для прямого подключения к Apache это нормальная логика. Но за reverse proxy такая проверка часто неверна: локально Apache видит HTTP и честно пытается «исправить» схему, хотя клиент уже находится на HTTPS у внешнего прокси.

В рабочей конфигурации Apache должен учитывать не только собственный TLS, но и информацию от доверенного фронта. Реализация может отличаться, но суть одинакова: если запрос пришёл с корректным признаком внешнего HTTPS, backend не должен заново инициировать редирект.

Где искать лишние редиректы в Apache

  • в файлах сайтов в /etc/apache2/sites-enabled/;
  • в conf-enabled и общих include-конфигах;
  • в .htaccess, если он разрешён;
  • в bootstrap-коде приложения и CMS-плагинах;
  • в правилах канонизации хоста, слэшей и базового URL.

Для быстрой инвентаризации полезно собрать все упоминания redirect и rewrite-логики:

sudo grep -Rni "RewriteRule|RewriteCond|Redirect|X-Forwarded-Proto|HTTPS" /etc/apache2
sudo grep -Rni "RewriteRule|RewriteCond|Redirect|HTTPS" /var/www

Даже если итоговая логика выглядит правильной, дубликаты обычно мешают. Один слой может переводить на https://example.com, другой — на https://www.example.com, а третий возвращать обратно. Внешне это одна ошибка, но внутри уже несколько конфликтующих правил.

Если у вас на сервере уже настроены SSL-сертификаты, особенно важно не размазывать HTTPS-логику по нескольким слоям. Сертификат сам по себе не вызывает цикл, но после его установки часто включают дублирующие правила сразу везде.

Проверка логов Nginx и Apache и цепочки редиректов через curl

Cloudflare Flexible: частая причина бесконечных переадресаций

Режим Cloudflare Flexible — одна из самых частых причин ERR_TOO_MANY_REDIRECTS. Пользователь подключается к CDN по HTTPS, а от CDN к origin трафик идёт по HTTP. Для origin это выглядит как обычный незашифрованный запрос.

Если origin при этом жёстко отправляет всех на HTTPS, он начинает отвечать CDN редиректом. CDN снова приходит к origin по HTTP, потому что Flexible не использует HTTPS до backend. Origin снова отвечает 301. Цикл замыкается.

На практике правильный выход обычно один: перевести схему так, чтобы HTTPS использовался не только между браузером и CDN, но и между CDN и origin. Иначе у разных участников цепочки будут разные представления о том, какая схема считается корректной.

Если сайт работает через CDN и цикл редиректов появился сразу после включения проксирования, первым делом проверяйте именно режим соединения между CDN и origin.

Как найти источник редиректа по заголовкам и логам

Когда схема сложная, отлаживайте её послойно. Сначала обращайтесь к внешнему адресу, затем напрямую к backend по локальному IP или порту, а после этого повторяйте запрос с подставленным заголовком Host и, при необходимости, X-Forwarded-Proto.

curl -I -H 'Host: example.com' http://127.0.0.1:8080
curl -I -H 'Host: example.com' -H 'X-Forwarded-Proto: https' http://127.0.0.1:8080

Если без X-Forwarded-Proto backend отвечает 301, а с ним — 200 или нормальным ответом приложения, это почти прямое доказательство, что причина именно в схеме и в отсутствии доверия к прокси-заголовкам.

На этом этапе полезно временно расширить логирование и посмотреть, что сервер реально получает по входящим заголовкам. Особенно это помогает, если проблема проявляется только на одном поддомене, в админке, в авторизации или на callback-URL.

Для смежной настройки может пригодиться материал про security headers в Nginx и Apache: часто после правок HTTPS-логики администраторы заодно приводят в порядок HSTS и связанные заголовки, и лучше делать это осознанно.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Частые сценарии поломки

Nginx редиректит на HTTPS, хотя находится не на edge

Внешний балансировщик завершает TLS, передаёт HTTP на внутренний Nginx, а тот безусловно возвращает 301 на HTTPS. Для edge-сервера это нормально, для внутреннего — нет. Исправление простое: редирект должен жить на внешнем слое либо строиться только с учётом доверенной схемы.

Apache и .htaccess спорят с Nginx

Nginx уже перевёл запрос с HTTP на HTTPS, но в .htaccess сохранилось старое правило по %{HTTPS}. Apache видит локальный HTTP и пытается повторить уже выполненный redirect. В результате пользователь получает петлю, хотя каждый отдельный слой по-своему «прав».

Приложение не доверяет proxy

Заголовки передаются корректно, Nginx и Apache настроены аккуратно, но само приложение не знает, что работает за reverse proxy. Это типично для CMS и фреймворков, где отдельно задаются trusted proxies, secure headers или базовый URL.

Конфликт хоста и схемы

Один слой делает example.com в www.example.com, другой — обратно, а третий ещё и меняет схему. Пользователь видит общую ошибку редиректов, хотя внутри происходят сразу два конфликта: по хосту и по протоколу.

Практичный порядок исправления

  1. Зафиксируйте, где именно завершается TLS.
  2. Определите единственное место, которое отвечает за редирект HTTP на HTTPS.
  3. Проверьте передачу X-Forwarded-Proto и Host.
  4. Настройте backend так, чтобы он доверял этим заголовкам только от вашего proxy.
  5. Уберите дублирующие правила из Nginx, Apache, .htaccess и приложения.
  6. Отдельно проверьте канонический хост: с www и без него.
  7. Протестируйте основные URL через curl -IL.

Такой порядок важен: если сразу редактировать всё подряд, можно случайно получить временно рабочую схему, которая снова сломается после обновления CMS, смены прокси или включения нового поддомена.

Безопасная логика конфигурации

Лучший подход — сделать архитектуру предсказуемой. Если TLS завершается на внешнем Nginx, именно он выполняет redirect с HTTP на HTTPS. Внутренний Apache или приложение не принимают это решение повторно, а корректно используют информацию о схеме из доверенного заголовка.

На Debian и Ubuntu это удобно ещё и потому, что конфиги обычно разложены по понятным каталогам. Для Nginx проверяйте /etc/nginx/sites-enabled/ и snippets, для Apache — /etc/apache2/sites-enabled/, conf-enabled и все включаемые файлы.

После любого изменения обязательно валидируйте конфигурацию до перезапуска:

sudo nginx -t
sudo apachectl configtest
sudo systemctl reload nginx
sudo systemctl reload apache2

Если вы сравниваете поведение двух веб-серверов или планируете упростить схему, может пригодиться и разбор когда выбирать Nginx, а когда Apache. Иногда цикл редиректов — это не разовая ошибка, а симптом перегруженной конфигурации.

Что делать, если проблема проявляется только в браузере

Если curl уже показывает корректную цепочку, а браузер всё ещё пишет ERR_TOO_MANY_REDIRECTS, проверьте кэш, сохранённые 301, cookies и влияние HSTS. Но не списывайте всё сразу на браузер: обычно он просто дольше хранит старое состояние, а первопричина всё равно была на сервере.

Также учитывайте, что разные поддомены и разделы сайта могут вести себя по-разному из-за отдельных cookie, настроек приложения или виртуальных хостов. Поэтому тестируйте не только главную страницу, но и проблемный URL: админку, вход, API, callback или checkout.

Короткий чек-лист перед вводом в продакшен

  • один слой отвечает за редирект HTTP на HTTPS;
  • один слой отвечает за канонический хост;
  • X-Forwarded-Proto передаётся и учитывается корректно;
  • backend доверяет заголовкам только от вашего proxy;
  • режим CDN не конфликтует с логикой origin;
  • в .htaccess и include-конфигах нет старых дублей;
  • цепочка curl -IL содержит только ожидаемые переходы.

Итог

ERR_TOO_MANY_REDIRECTS — это не случайная ошибка браузера, а вполне конкретный симптом несогласованной логики между reverse proxy, веб-сервером и приложением. В связках Nginx, Apache, CDN и backend почти всё упирается в три вопроса: где завершается TLS, кто делает редирект на HTTPS и как обрабатывается X-Forwarded-Proto.

Если разложить цепочку по уровням, посмотреть реальные 301 и 302 через curl, а затем убрать дублирующие правила, проблема обычно решается быстро. Самое полезное правило здесь простое: не заставляйте несколько компонентов одновременно решать, какой URL считать правильным.

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

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: nginx bind() to 0.0.0.0:80 failed (98: Address already in use) — как найти и устранить конфликт порта OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: nginx bind() to 0.0.0.0:80 failed (98: Address already in use) — как найти и устранить конфликт порта

Ошибка nginx bind() to 0.0.0.0:80 failed (98: Address already in use) в Debian/Ubuntu почти всегда означает конфликт за 80 или 443 ...
Debian/Ubuntu: как исправить Nginx no live upstreams while connecting to upstream OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Nginx no live upstreams while connecting to upstream

Ошибка Nginx no live upstreams while connecting to upstream означает, что веб-сервер не видит доступных backend-процессов. Ниже — ...
Debian/Ubuntu: Too many levels of symbolic links — как найти и исправить зацикленный symlink OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: Too many levels of symbolic links — как найти и исправить зацикленный symlink

Ошибка Too many levels of symbolic links в Debian/Ubuntu почти всегда означает цикл в символьных ссылках или ошибку в структуре de ...