
Ошибка 504 (504 Gateway Time-out) означает, что промежуточный сервер — nginx, балансировщик или CDN — не дождался ответа от сервера приложения за отведённое время и прекратил ожидание. Сайт при этом обычно жив, но отвечает слишком медленно. Посетителю стоит обновить страницу через минуту, владельцу — искать медленный запрос в логах.
В отличие от 502 (upstream ответил невалидно или оборвал соединение), 504 — это ожидание, которое истекло. Ниже: перевод и смысл кода, что делать посетителю, где искать причину в логах nginx, Apache и PHP-FPM, как правильно настроить таймауты и как оптимизировать медленные запросы, вместо того чтобы просто прятать их за увеличенным таймаутом.
Что значит код 504 и как переводится Gateway Time-out
Согласно RFC 9110 §15.6.5, код 504 означает, что сервер, действуя как шлюз (gateway) или прокси, не получил своевременный ответ от вышестоящего сервера (upstream), к которому обратился, чтобы выполнить запрос. Ключевое слово — «своевременный»: сколько ждать, решает не стандарт, а таймаут в конфигурации прокси.
Цепочка обычно выглядит так: браузер → CDN или балансировщик → nginx → PHP-FPM, Node.js, Python или Java-приложение → база данных и внешние API. Код 504 выдаёт то звено, у которого кончилось терпение, а виновато, как правило, звено дальше по цепочке. Поэтому страница с надписью «nginx» под заголовком ещё не значит, что проблема в nginx — он лишь сообщил, что приложение за ним не ответило вовремя.
Перевод Gateway Time-out
Gateway Time-out дословно переводится как «тайм-аут шлюза», по смыслу — «шлюз не дождался ответа». Шлюзом здесь называют любой сервер-посредник, который принимает запрос от браузера и передаёт его дальше. Поэтому в русскоязычных сообщениях эту ошибку называют ещё «ошибка шлюза 504» или «504 тайм-аут шлюза». Написание Time-out через дефис встречается на стандартной странице nginx, Timeout слитно — в тексте RFC и в большинстве фреймворков; это один и тот же код.
Как выглядит ошибка на экране
| Текст на экране | Кто его показывает | Комментарий |
|---|---|---|
504 Gateway Time-out и строка nginx внизу | nginx перед приложением | Самый частый вариант на VPS и хостингах |
Gateway Timeout / The gateway did not receive a timely response from the upstream server or application | Apache с mod_proxy | Истёк ProxyTimeout или Timeout |
HTTP Error 504, HTTP 504 | Браузер, клиентская библиотека, мобильное приложение | Код пришёл от сервера, браузер лишь его отобразил |
Error 524: A timeout occurred | Cloudflare | Это не 504: Cloudflare так сообщает о собственном таймауте ожидания origin |
502.3 - Bad Gateway: The operation timed out | IIS с модулем ARR | Таймаут прокси в IIS оформлен как 502.3, а не 504 |
Если код 504 выдаёт бортовой компьютер автомобиля или игровой клиент — это другие ошибки с совпадающим номером, к HTTP-статусу сайта они отношения не имеют.
Ошибка 504 на сайте: что делать посетителю
Исправить 504 со стороны браузера нельзя — ошибка возникает между серверами сайта. Но можно быстро понять, у кого проблема.
- Подождите минуту и обновите страницу (
F5, на macOS —Cmd+R). Часто 504 — следствие кратковременного всплеска нагрузки. - Не отправляйте форму повторно вслепую. Если 504 появилась после оплаты или оформления заказа, запрос мог быть выполнен — прокси просто не дождался ответа. Сначала проверьте почту или личный кабинет.
- Откройте другой сайт. Если 504 везде, ошибку отдаёт прокси-сервер между вами и интернетом: корпоративный прокси, фильтр антивируса или роутер провайдера. Проверьте настройки прокси в системе: Windows — «Параметры → Сеть и Интернет → Прокси-сервер», macOS — «Системные настройки → Сеть → Подробнее → Прокси».
- Проверьте сайт снаружи через проверку HTTP-заголовков Enterno.io: если внешний запрос тоже получает 504 или долго висит, проблема на стороне сайта, а не у вас.
- Сообщите владельцу сайта — время, адрес страницы и действие, после которого появилась ошибка. Это сильно сокращает поиск в логах.
Очистка кэша браузера и cookies при 504 почти никогда не помогает: браузер не участвует в ожидании между прокси и приложением.
Почему сайт выдаёт 504: 7 частых причин
- Медленный SQL-запрос без индекса или транзакция, ждущая блокировку.
- Медленный внешний API — платёжный шлюз, склад, CRM, от которого зависит ответ страницы.
- Неоптимальный код — N+1 query, не-батчированные операции, обход больших массивов в цикле.
- Ресурсоёмкие задачи в request/response цикле (генерация PDF, импорт каталога, отправка email).
- Все воркеры заняты. У PHP-FPM закончился
pm.max_childrenили у приложения исчерпан пул соединений к БД: новые запросы стоят в очереди, и прокси не дожидается даже начала обработки. - Низкий timeout в nginx/Cloudflare для реально долгих операций (выгрузки, отчёты).
- Upstream недоступен по сети или заблокирован — deadlock в БД, зависший поток, упавший контейнер, файрвол молча отбрасывает пакеты к бэкенду.
Первые четыре причины — это медленный код, пятая — нехватка мощности, шестая — неверная настройка, седьмая — авария. Лечатся они по-разному, поэтому сначала диагностика, потом правка конфигов.
504 Gateway Time-out в nginx: где искать причину
nginx записывает каждый таймаут в error.log с указанием этапа, на котором кончилось ожидание. По этому тексту видно, куда смотреть дальше:
# Последние таймауты upstream
grep "upstream timed out" /var/log/nginx/error.log | tail -20
# Пример строк:
# upstream timed out (110: Connection timed out) while reading response header from upstream
# upstream timed out (110: Connection timed out) while connecting to upstream| Фраза в error.log | Что произошло | Какая директива сработала |
|---|---|---|
while connecting to upstream | Бэкенд не принял соединение: остановлен, перегружен, недоступен по сети | proxy_connect_timeout / fastcgi_connect_timeout |
while reading response header from upstream | Соединение есть, но приложение не начало отвечать — медленный код, запрос к БД или внешнему API | proxy_read_timeout / fastcgi_read_timeout |
while reading upstream | Ответ начал приходить, но между порциями данных возникла пауза длиннее таймаута | proxy_read_timeout / fastcgi_read_timeout |
while sending request to upstream | nginx не смог передать тело запроса бэкенду, например большой upload | proxy_send_timeout / fastcgi_send_timeout |
Важно: proxy_read_timeout — это не лимит на весь ответ, а максимальная пауза между двумя операциями чтения. По умолчанию для proxy_* и fastcgi_* это 60 секунд. Подробнее о том, где лежат журналы и как их читать, — в статье про логи nginx.
Какие запросы медленные: время ответа в access.log
Стандартный формат combined не пишет время выполнения запроса, поэтому сначала добавьте его в лог, а затем отфильтруйте долгие запросы:
# /etc/nginx/nginx.conf, блок http
log_format timing '$remote_addr [$time_local] "$request" $status '
'$request_time $upstream_response_time';
access_log /var/log/nginx/timing.log timing;
# Проверить и применить
nginx -t && systemctl reload nginx
# Запросы, где upstream отвечал дольше 5 секунд
awk '$NF+0 > 5' /var/log/nginx/timing.log | tail -20
# Какие URL чаще всего получают 504
awk '$7 == 504 {print $5}' /var/log/nginx/timing.log | sort | uniq -c | sort -rn | headТак вы увидите не «сайт тормозит», а конкретные адреса: например, /export или поиск по каталогу. Именно их и нужно оптимизировать.
Проверка в обход nginx
Чтобы понять, медленное ли само приложение, отправьте запрос напрямую на бэкенд с сервера и замерьте время:
# Linux/macOS: время до первого байта и общее время
curl -o /dev/null -s -w 'code=%{http_code} connect=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total}\n' https://example.ru/export
# Напрямую к приложению на порту 8080, минуя nginx
curl -o /dev/null -s -w '%{http_code} %{time_total}\n' -H 'Host: example.ru' http://127.0.0.1:8080/export
# Windows PowerShell (curl.exe есть в Windows 10 и новее)
curl.exe -o NUL -s -w "code=%{http_code} total=%{time_total}\n" https://example.ru/exportЕсли напрямую запрос выполняется 90 секунд, а таймаут nginx — 60, причина найдена: медленное приложение, а не прокси.
Диагностика медленных запросов в БД и PHP
# MySQL slow log
mysqldumpslow -t 10 /var/log/mysql/slow.log
# PHP-FPM slow log
# /etc/php/8.4/fpm/pool.d/www.conf:
# slowlog = /var/log/php/www-slow.log
# request_slowlog_timeout = 5s
tail -100 /var/log/php/www-slow.log
# Закончились ли воркеры PHP-FPM
grep "max_children" /var/log/php8.4-fpm.log
# WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
# Node.js: event loop lag
// npm install clinic
// clinic doctor -- node app.jsSlow log PHP-FPM особенно полезен: для каждого запроса дольше request_slowlog_timeout он записывает стек вызовов, и видно, на какой функции скрипт стоял — на PDOStatement->execute(), curl_exec() или в собственном цикле. Путь к основному логу PHP-FPM зависит от дистрибутива, его задаёт директива error_log в php-fpm.conf.
Проверьте внешнее время ответа через PageSpeed Check от Enterno.io — получите TTFB, метрики Web Vitals и узкие места.
Как исправить ошибку 504: правильная настройка timeout в nginx
http {
# Соединение с upstream
proxy_connect_timeout 10s;
# Отправка запроса upstream'у
proxy_send_timeout 30s;
# Чтение ответа от upstream
proxy_read_timeout 60s;
# Для FastCGI (PHP-FPM)
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 30s;
fastcgi_read_timeout 60s;
}
# Long-polling эндпоинт — отдельный location
location /api/long-poll {
proxy_read_timeout 300s; # 5 минут
proxy_pass http://backend;
}Несколько правил, которые избавляют от повторных 504:
- Увеличивайте таймаут точечно — в
locationдолгого эндпоинта, а не на весь сайт. Глобальные 300 секунд превращают каждый зависший запрос в занятый на 5 минут воркер. - Для PHP-FPM нужна директива
fastcgi_read_timeout, а неproxy_read_timeout: если сайт работает черезfastcgi_pass,proxy_*на него не действуют. Это самая частая причина, почему «увеличил таймаут, а 504 осталась». proxy_connect_timeoutдержите коротким. По документации nginx он обычно не может превышать 75 секунд, а долгое ожидание соединения лишь маскирует упавший бэкенд.- Учитывайте повторы. По умолчанию
proxy_next_upstream error timeout: при нескольких серверах вupstreamnginx после таймаута отправит запрос на следующий, и пользователь прождёт дольше одного таймаута. Неидемпотентные запросы (POST) nginx по умолчанию на другой сервер не повторяет. - Цепочка таймаутов должна сужаться к клиенту: таймаут приложения меньше таймаута nginx, таймаут nginx меньше таймаута CDN или балансировщика. Тогда ошибку сформирует ближайшее к причине звено, и в логах будет видно, что произошло.
После правки — nginx -t и systemctl reload nginx. Описание всех директив — в документации модуля ngx_http_proxy_module. На виртуальном хостинге доступа к конфигу nginx обычно нет — таймаут меняет поддержка хостинга, а в панели управления, как правило, можно изменить только параметры PHP.
Apache: ProxyTimeout
# Глобально для mod_proxy (если не задан — берётся Timeout, по умолчанию 60 секунд)
ProxyTimeout 120
# Или только для конкретного бэкенда
ProxyPass "/export/" "http://127.0.0.1:8080/export/" timeout=300
# Проверка и перезапуск
apachectl configtest && systemctl reload apache2В журнале ошибок Apache таймаут прокси обычно сопровождается строкой (70007)The timeout specified has expired.
PHP-FPM: max_execution_time
# php.ini
max_execution_time = 30
max_input_time = 60
# Для экспорта больших данных:
# Установите per-request через ini_set()
ini_set('max_execution_time', 300); # 5 минут
set_time_limit(300);
# Но лучше вынести в очередь!Два нюанса. Во-первых, на Linux max_execution_time не учитывает время, проведённое вне скрипта — в запросах к БД, сетевых вызовах, sleep() (документация PHP). Скрипт может ждать ответа внешнего API пять минут, не нарушив лимит в 30 секунд, — и nginx отдаст 504 раньше. Во-вторых, жёсткий предел на стороне пула задаёт request_terminate_timeout в pool.d/www.conf: когда он срабатывает, воркер убивается, и nginx обычно получает оборванное соединение — то есть 502, а не 504. Держите его чуть больше fastcgi_read_timeout, чтобы ошибки были однозначными.
Node.js: server timeout
const server = app.listen(3000);
server.setTimeout(60000); // 60 секунд
server.keepAliveTimeout = 61000;
server.headersTimeout = 65000; // должен быть > keepAliveTimeout
// Для Fastify
const app = Fastify({
connectionTimeout: 60000,
keepAliveTimeout: 61000,
});keepAliveTimeout приложения держите больше, чем keepalive-таймаут прокси или балансировщика перед ним: иначе Node закроет простаивающее соединение в тот момент, когда прокси пошлёт в него новый запрос, и это даст эпизодические 502.
Правильное решение: вынос в background
Увеличивать timeout до бесконечности — антипаттерн. Правильное решение — вынести долгие операции в очередь.
// Плохо: блокируем request
app.post('/generate-report', async (req, res) => {
const pdf = await generateBigPDF(req.body); // 3 минуты
await sendEmail(pdf);
res.json({ok: true});
});
// Хорошо: очередь + уведомление
app.post('/generate-report', async (req, res) => {
const jobId = await queue.add('generate-report', req.body);
res.status(202).json({jobId, status: 'queued'});
});
// Worker обрабатывает в фоне
queue.process('generate-report', async (job) => {
const pdf = await generateBigPDF(job.data);
await sendEmail(pdf);
});Клиент получает 202 Accepted + jobId, опрашивает статус через /jobs/:id или получает уведомление через WebSocket/webhook.
Оптимизация медленных запросов БД
-- Ищите long queries
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;
-- EXPLAIN плана запроса
EXPLAIN SELECT * FROM orders WHERE user_id = 1 ORDER BY created_at DESC LIMIT 10;
-- Добавьте индекс если нужен
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC);
-- Проверьте размеры таблиц
SELECT table_name, ROUND(data_length/1024/1024) AS mb
FROM information_schema.tables
WHERE table_schema = 'your_db'
ORDER BY data_length DESC LIMIT 10;Если в SHOW FULL PROCESSLIST много запросов в состоянии ожидания блокировки, проблема не в индексе, а в долгой транзакции, которая держит строки: найдите её и сократите.
504 и Cloudflare 524: в чём разница
Cloudflare ждёт ответа от вашего сервера по умолчанию 100 секунд. Когда время выходит, он возвращает не 504, а собственный код 524 A timeout occurred. Если же посетитель видит 504 на сайте за Cloudflare, чаще всего её сформировал ваш nginx или балансировщик, а Cloudflare лишь передал ответ дальше, — ищите причину в логах origin. Разбор 524 и соседних кодов — в статье про ошибки Cloudflare 520, 521 и 524. Варианты для реально долгих запросов:
- Использовать Enterprise plan (до 6000 сек).
- Перевести долгие эндпоинты на Origin bypass через отдельный поддомен без CF proxy.
- Оптимизировать код до <100 сек (правильный подход).
Чем отличаются ошибки 502, 503, 504 и 524
| Код | Название | Что произошло | С чего начать |
|---|---|---|---|
| 502 | Bad Gateway | Upstream ответил невалидно, оборвал соединение или не запущен (connection refused) | Запущен ли PHP-FPM или приложение, совпадает ли сокет или порт |
| 503 | Service Unavailable | Сервер сознательно не обслуживает запрос: перегрузка, лимит, режим обслуживания | Лимиты запросов, maintenance-режим, заголовок Retry-After |
| 504 | Gateway Timeout | Прокси не дождался ответа upstream за отведённое время | Error.log прокси, slow log приложения и БД, таймауты в цепочке |
| 524 | A timeout occurred (Cloudflare) | Cloudflare установил соединение с origin, но не получил ответ вовремя | Долгие запросы на origin, вынос тяжёлых операций в фон |
Подробные разборы соседних кодов: 502 Bad Gateway и 503 Service Unavailable. Полный справочник статусов — в статье про коды ответа сервера.
Похожая ситуация бывает в 1С: при работе через веб-клиент, опубликованный на Apache или IIS, 504 появляется, когда длительная операция не укладывается в таймаут веб-сервера или прокси перед ним. Лечится так же — таймаутом для конкретной публикации или переносом операции в фоновое задание.
Как проверить сайт на 504
- Проверка HTTP-заголовков — покажет код ответа и время ответа сайта снаружи, из другой сети. Если внешний запрос висит десятки секунд, 504 вызвана медленным приложением.
- Traceroute — пригодится, если 504 выдаёт ваш балансировщик или CDN, а бэкенд расположен в другом дата-центре: покажет, доходят ли пакеты до сервера и где растут задержки.
- PageSpeed Check — время до первого байта (TTFB): если оно стабильно близко к таймауту прокси, 504 будут повторяться при любом всплеске нагрузки.
Итог
504 — не баг timeout'а, а симптом медленного кода, нехватки воркеров или внешнего API. Порядок действий: найти в error.log этап, на котором кончилось ожидание, по access.log определить медленные URL, по slow log — конкретную функцию или запрос. Мониторьте slow log, оптимизируйте запросы, выносите долгие задачи в очередь. Timeout'ы настраивайте с запасом, но не бесконечно. Подключите Enterno.io для автоматической фиксации 504 по регионам.
Частые вопросы
Чем 504 отличается от 502?
504 — upstream не ответил в срок. 502 — upstream ответил невалидно, закрыл соединение или вообще не запущен.
Какой timeout адекватен?
Web-запросы: 30–60 сек. API: 10–30 сек. Long-polling: 300+ сек. Долгие задачи: выносим в очередь.
Я увеличил proxy_read_timeout, а 504 осталась. Почему?
Сайт на PHP-FPM работает через fastcgi_pass, и на него действует fastcgi_read_timeout. Кроме того, перед nginx может стоять CDN или балансировщик со своим, более коротким таймаутом, — проверьте всю цепочку.
Можно ли исправить ошибку 504 на стороне пользователя?
Нет. Можно лишь подождать и обновить страницу, а если 504 показывают все сайты подряд — проверить системный или корпоративный прокси.
Как поймать 504 автоматически?
Enterno.io Monitors с коротким timeout триггерят алерт. Также встройте APM (Sentry, New Relic).
Влияет ли 504 на SEO?
Да. Если робот Яндекса или Google регулярно получает 5xx, он снижает частоту обхода, а страницы, долго отвечающие ошибкой, со временем выпадают из индекса. Единичные 504 на пару минут опасности не несут.