Итак, на своём сайте мы столкнулись с ошибкой 504 Gateway Time-out и не знаем, что же делать. В этом посте постараюсь описать полный алгоритм действий для решения этой проблемы, а так же поведать о причинах её возникновения. Следуйте под кат!
Так вот, продолжим. Для начала выясним, что это за HTTP код ошибки такой, а точнее, что же он означает? 504 — пятьсот четвёртая ошибка, она же Gateway Timeout, а точнее, на русском это звучит примерно так: «Время прохождения через шлюз истекло». Код означающий, что сервер при работе в качестве внешнего шлюза или прокси-сервера не получил своевременно отклик от вышестоящего бэкенда сервера, к которому он обратился, пытаясь исполнить запрос.
По этой ошибке легко можно представить внутреннюю организацию вашего web сервера. Это явно связка двух web серверов в которой один выступает в роли фронтенда (переднего сервера) и второй в качестве бэкенда (заднего сервера). И скорее всего, так бывает в 99% случаев, установлен веб сервер nginx, который выступает в качестве фронтенда и так же стоит сервер Apache в качестве бэкенда. Nginx берёт на себя роль распределяющего proxy сервера и отдаёт статику (картинки, файлы), а apache вместе с PHP обрабатывает динамику, там же и MySQL неподалёку. И ошибку 504 Gateway Time-out вы получаете именно от nginx.
В общем вернёмся к делу. Ситуация предельно ясна! За отведённое время сервер nginx просто не дожидается обратного ответа от apache и сообщает об этом вам. Т.е. прослеживаются явные перегрузки на «внутренней» стороне бэкенда. Другой вопрос в том, что именно порождает эти перегрузки от чего apache не успевает во время ответить? Это уже вопрос другой. Тут так просто не разобраться, надо смотреть логи сервера. Ну понятное дело, что кто-то перегружен. Либо скрипт долго работает, либо СУБД не успевает обработать множество запросов, что кстати бывает чаще всего ведь коннектор с СУБД это самое слабое место. В общем ваш внутренний сервер не успевает в срок выполнить скрипт, точнее он просто долго выполняет, а nginx не хочет ждать и спешит отдать вам 504 ошибку. От чего не укладывается по времени apache так же ясно, либо много запросов извне и ресурсов сервера не хватает (это можно узнать из счётчика посещаемости сайта), либо выполняемый скрипт очень тяжёлый.
В общем речь сейчас не об этом, а том как справится с ошибкой 504. Многих веб мастеров вполне устраивает, то что страница генерируется по несколько минут, может быть оно того стоит.
В общем, ближе к делу, наша задача сказать серверу nginx, что бы он ждал ответа от apache подольше и не торопился отдавать клиенту ошибку 504. С этим всё просто! Естественно нужно иметь root доступ к своему серверу, о виртуальных хостингах и даже говорить не буду. В общем заходим на свой сервер, хоть даже по протоколу ssh в терминале и идём в папку с конфигурационными файлами сервера nginx. Сразу скажу, что они меняются от версии к версии и поэтому точно сказать какой именно файл будет не могу. Плюс ко всему всё ещё зависит от того в каком режиме работает nginx и кто его вам настраивал. Грубо говоря нам нужен текущий файл настроек сервера nginx для требуемого виртуального хоста (сайта) либо же для всего сервера в целом. Возможно это даже будет nginx.conf, как в общем-то и должно быть.
Далее будут показывать на своём примере, думаю применить к себе будет не сложно, ОС Linux Ubunut.
Заходим в условный файл настроек виртуальных хостов сервера nginx, расположенному по адресу: /etc/nginx/nginx.conf
Здесь можем либо поискать уже установленные директивы (если есть) или дописать вручную. Можно дописать естественно как для всех хостов, так и для каждого конкретного, не важно. В общем пишем следующее:
proxy_send_timeout 60; # время ожидания при передаче запроса proxy_read_timeout 60; # время ожидания при чтении ответа
Эти директивы нужны для изменения времени ожидания. Лучше вставлять в контекст location. У меня получилось примерно следующим образом:
server { listen xxx.xxx.xxx.xxx:80; # ip адрес сервера и прослушиваемый порт server_name someserver.loc; # имя сервера rewrite ^(/manager/.*)$ https://$host$1 permanent; error_page 404 = @fallback; # Далее две строки, которые надо добавить proxy_send_timeout 600; # время ожидания при передаче запроса proxy_read_timeout 600; # время ожидания при чтении ответа location / { proxy_pass http://xxx.xxx.xxx.xxx:8080; # протокол и адрес проксируемого сервера, а также необязательный URI, на который должен отображаться location proxy_redirect http://sitename.loc:8080/ /; # текст, который нужно изменить в полях заголовка “Location” и “Refresh” в ответе проксируемого сервера proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; } }
Далее сохраняем файл конфигурации и перезапускаем сервер nginx. Теперь он будет ждать ответа от apache именно столько времени, сколько вы указали в добавленных директивах, а не по значению по умолчанию. Думаю понятно, что время вы сами выставляете какое хотите. Всё, теперь ошибка 504 Gateway Time-out вас беспокоить не будет. Понятное дело, что это лишь вершина айсберга и нужно будет разбираться с самой причиной долгой генерации страницы, но это уже другая тема. Возможно придётся так же поставить таймаут побольше и для PHP, а то может быть такое, что и он начнёт ругаться, мол ему дают мало времени на обработку. Для этого используем PHP директивы max_input_time
и max_execution_time
в файле настроек PHP — php.ini
или в файле локальных настроек сервера Apache — .htaccess
Дополню тем, что если вы используете сервер Apache в качестве переднего сервера (фронтенда) и получаете ошибку 504 Gateway Time-out именно от него, тогда можно попробовать поменять опцию Timeout, находится в файле конфигураций веб сервера, чаще всего это либо httpd.conf
или httpd-default.conf
. Находим следующие строки:
# # Timeout: The number of seconds before receives and sends time out. # Timeout 60
Вместо 60 пишем своё новое значение, рекомендую не мелочиться и сразу поставить на 600 секунд (Timeout 60
), т.е. 10 минут.
На этом пожалуй всё, думаю проблема 504 Gateway Time-out теперь для вас решена.