Как узнать, почему упал сайт: читаем логи и находим причину

10 минут чтения
Средний рейтинг статьи — 4.8

Сайт редко «падает» просто так. За сообщением от пользователя «ничего не открывается» обычно стоит конкретная причина: Nginx не может достучаться до upstream, приложение ушло в panic, база исчерпала пул соединений, диск забился логами, сертификат истёк, DNS указывает не туда. Чтобы разобраться, что случилось, нужно не угадывать, а восстановить цепочку событий по логам и метрикам.

Логи — это не готовый ответ, а сырьё для расследования. Один файл покажет 502, другой — рестарт процесса, третий — OOM Killer, четвёртый — ошибку подключения к PostgreSQL. Причина становится ясна только после сопоставления: что произошло первым, что стало следствием, какие симптомы увидели пользователи.

Ниже — практический порядок действий для разработчиков и devops-инженеров: с чего начать, какие логи смотреть, какие команды запускать и как не перепутать корневую причину с побочным эффектом.

Сначала зафиксируйте симптом, а не открывайте все логи подряд

Первая ошибка при аварии — сразу заходить на сервер и листать error.log. Так легко утонуть в шуме. Сначала нужно понять, что именно сломалось снаружи.

1) Проверьте HTTP-ответ — выполните запрос к проблемному URL:

curl -I -L --max-time 10 https://example.com/

Смотрите на:

  • HTTP/1.1 500, 502, 503, 504, 429, 403;
  • время ответа;
  • редиректы;
  • заголовки CDN или балансировщика;
  • отличается ли ответ для /, /api/health, /login, /static/app.js.

Если нужно подробнее разобрать запросы, пригодится отдельный материал про curl.

2) Проверьте, проблема глобальная или локальная — сайт может не открываться только из одной сети, региона или у одного провайдера. Поэтому полезны внешние проверки доступности. Например, Statuser проверяет сайт с заданным интервалом и присылает уведомление о сбое: по времени алерта удобно определить начало инцидента и не спорить, «когда всё началось».

3) Определите слой сбоя — грубо разложите симптом:

  • домен не резолвится — смотрите DNS;
  • TCP-соединение не устанавливается — сеть, фаервол, порт, балансировщик;
  • TLS не проходит — сертификат, SNI, цепочка, прокси;
  • есть 502/503/504 — веб-сервер, upstream, приложение, пул соединений;
  • есть 500 — чаще всего код приложения или зависимость;
  • ответ есть, но медленный — база, внешние API, блокировки, saturation ресурсов.

Это экономит время: логи приложения бесполезны, если запрос вообще не дошёл до сервера.

Постройте таймлайн: время важнее количества логов

Логи без точных меток времени — просто набор разрозненных фактов. Чтобы получить из них причину, нужно восстановить последовательность событий.

1) Зафиксируйте окно инцидента — например:

  • алерт пришёл в 12:41;
  • пользователь написал в 12:44;
  • сайт восстановился в 12:53;
  • деплой был в 12:35;
  • нагрузка выросла в 12:39.

Дальше все команды запускайте с фильтром по этому окну. Не анализируйте весь день, если сбой длился 12 минут.

2) Синхронизируйте часовые пояса — частая ловушка: Nginx пишет в локальном времени, приложение — в UTC, база — в другом timezone, контейнер — как в образе. Перед расследованием проверьте:

date
timedatectl

В Kubernetes и Docker логи часто идут в UTC. Это нормально, но нужно учитывать смещение.

3) Найдите первое отклонение — корневая причина обычно ближе к началу таймлайна. Если в 12:41 появились 502, а в 12:40:58 приложение умерло по Out of memory, то 502 — симптом. Если в 12:39 база начала отвечать too many connections, а приложение упало позже из-за лавины ошибок, причина ближе к базе или пулу соединений.

4) Сопоставьте события разных слоёв — хороший минимальный набор:

  • access/error логи Nginx или другого reverse proxy;
  • логи приложения;
  • journalctl по сервису;
  • системные события: dmesg, syslog, kern.log;
  • логи базы данных;
  • события деплоя;
  • метрики CPU, RAM, disk I/O, network, latency, error rate.

Если сайт уже поднялся, расследование всё равно возможно. Подход к коротким инцидентам подробно разобран в статье как определить причину кратковременных сбоев, если к моменту расследования всё уже работает.

Где искать логи: карта типового веб-стека

В продакшене логи лежат не в одном месте. Сначала составьте карту запроса: клиент → CDN/WAF → балансировщик → Nginx → приложение → база/кэш/очередь/внешний API.

1) Nginx / Apache / Caddy — обычно первое место, где видно, что получал пользователь.

Для Nginx:

  • /var/log/nginx/access.log;
  • /var/log/nginx/error.log;
  • отдельные файлы виртуального хоста, если настроены.

Команды:

tail -f /var/log/nginx/error.log
grep ' 50[0-9] ' /var/log/nginx/access.log | tail -100

В access.log ищите всплеск 5xx, 499, 408, медленные запросы, конкретные URL. В error.logconnect() failed, upstream timed out, no live upstreams, SSL_do_handshake() failed.

2) systemd-сервисы — если приложение запущено как сервис:

journalctl -u myapp.service --since "2026-09-14 12:30" --until "2026-09-14 13:00"
journalctl -u myapp.service -p warning..alert

Подробно фильтры, grep, --since, --boot и другие приёмы разобраны в статье про анализ логов с помощью journalctl.

3) Docker — если сервис в контейнере:

docker ps -a
docker logs --since 30m --tail 300 app
docker inspect app --format '{{.State.ExitCode}} {{.State.OOMKilled}} {{.State.RestartCount}}'

Смотрите не только docker logs, но и статус контейнера: перезапуски, OOMKilled, exit code. Базовые команды собраны в шпаргалке по Docker.

4) База данных — PostgreSQL, MySQL, Redis и другие зависимости часто являются реальной причиной падения сайта. Логи могут показать:

  • too many connections;
  • deadlock detected;
  • долгие запросы;
  • отказ в подключении;
  • ошибки диска;
  • рестарт сервера БД;
  • проблемы репликации.

5) CDN, WAF, балансировщик — если перед сайтом стоит Cloudflare, HAProxy, Nginx ingress, ELB или другой прокси, его логи обязательны. Иначе можно ошибочно лечить приложение, хотя запросы режет WAF или балансировщик исключил backend из пула.

Как читать access.log: коды, latency и upstream

Access-лог reverse proxy отвечает на главный вопрос: что видел внешний мир. Для расследования падения сайта особенно важны статус, URI, время ответа и upstream.

Типичная строка Nginx может выглядеть так:

203.0.113.10 - - [14/Sep/2026:12:41:03 +0300] "GET /api/orders HTTP/1.1" 504 167 "-" "Mozilla/5.0" rt=30.001 uct=0.002 uht=30.000 urt=30.000 upstream=10.0.1.15:3000

Здесь видно: клиент ждал 30 секунд, upstream принял соединение быстро, но не отдал ответ. Это больше похоже на зависшее приложение или медленную зависимость, чем на сетевой отказ.

1) Посчитайте ошибки по кодам — быстро оценить картину можно через awk:

awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head

Если формат кастомный, поле статуса может быть другим. Для JSON-логов удобнее jq.

2) Найдите самые частые проблемные URL:

awk '$9 ~ /^5/ {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20

Если падает только /api/export, это не «упал весь сайт», а конкретный endpoint. Если 5xx на всех URL, проблема ниже: приложение, upstream, база, сеть.

3) Отделите клиентские таймауты от серверных499 в Nginx означает, что клиент закрыл соединение до ответа. Это может быть следствием медленного backend: пользователь или браузер не дождался. Но если 499 много на больших загрузках файлов или мобильных сетях, это не всегда авария.

4) Смотрите upstream-поля — полезно добавить в log_format:

  • $request_time;
  • $upstream_connect_time;
  • $upstream_header_time;
  • $upstream_response_time;
  • $upstream_status;
  • $upstream_addr;
  • $request_id.

Без этих полей трудно понять, где задержка: на Nginx, сети до backend, приложении или зависимости. По метрикам Nginx и признакам saturation есть отдельный материал: что смотреть в мониторинге Nginx.

Error.log Nginx: переводим сообщения в гипотезы

error.log часто пугает количеством сообщений, но многие из них хорошо интерпретируются.

1) connect() failed (111: Connection refused) while connecting to upstream — Nginx смог дойти до IP и порта, но там никто не слушает или соединение отклонено. Проверяйте:

ss -lntp
systemctl status myapp
docker ps

Типичные причины: приложение упало, слушает другой порт, контейнер не поднялся, неверный upstream после деплоя.

2) upstream timed out — соединение с backend есть, но ответ не пришёл вовремя. Возможные причины:

  • долгий SQL-запрос;
  • зависший внешний API;
  • блокировка event loop;
  • исчерпан пул воркеров;
  • GC-паузы;
  • очередь запросов внутри приложения;
  • слишком маленький proxy_read_timeout для легитимно долгой операции.

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

3) no live upstreams — балансировщик считает все backend недоступными. Смотрите health checks, upstream-зоны, рестарты контейнеров, сеть между proxy и приложением.

4) upstream prematurely closed connection — backend закрыл соединение до полного ответа. Это бывает при краше процесса, panic, segfault, рестарте во время запроса, лимите памяти или ошибке в runtime.

5) SSL-ошибки — если в логах SSL_do_handshake() failed, certificate verify failed, no shared cipher, проблема может быть между клиентом и Nginx или между Nginx и upstream по HTTPS. Сравните внешний TLS и внутренний TLS отдельно.

Ошибки 502, 503 и 504 часто идут рядом, но означают разные сценарии. Если нужно свериться с трактовкой, пригодятся отдельные разборы: 502 Bad Gateway, 503 Service Unavailable и 504 Gateway Timeout.

Логи приложения: ищем первую ошибку, а не последнюю

Логи приложения ближе всего к бизнес-логике, но там много вторичного шума. После падения сервис может сыпать одинаковыми ошибками сотни раз в секунду. Ваша задача — найти первую аномалию.

1) Ищите маркеры аварии — фильтруйте по словам:

grep -Ei 'error|exception|panic|fatal|timeout|refused|reset|oom|killed' app.log | tail -200

Но не ограничивайтесь только ERROR. Иногда причина логируется как WARN: например, connection pool exhausted.

2) Смотрите начало каскада — если в 12:41:20 тысячи database timeout, найдите, что было в 12:40:50. Возможно, перед этим появился migrations started, pool closed, too many clients, cache unavailable.

3) Связывайте запросы через request id — идеальный вариант: один request_id проходит через Nginx, приложение, worker, базу и внешние вызовы. Тогда можно взять проблемный запрос из access-лога и найти его путь:

grep 'req-7f3a9c' app.log

Если request id нет, добавьте. Это небольшая доработка, которая сильно ускоряет расследования.

4) Учитывайте деплой — частый ответ на вопрос «почему упал сайт» — «после выката». Проверяйте:

  • время релиза;
  • миграции;
  • изменение переменных окружения;
  • обновление зависимостей;
  • смену образа контейнера;
  • feature flags;
  • откат конфигурации.

Важно не делать вывод «после — значит из-за». Но если первые ошибки начались через минуту после деплоя, гипотеза сильная.

5) Разделяйте crash и degraded mode — сервис может не умереть, но перестать отвечать: event loop заблокирован, все worker threads заняты, пул соединений исчерпан, очередь задач разрослась. В логах это выглядит не как process exited, а как рост таймаутов, ретраев и latency.

Системные логи: OOM, диск, порты и лимиты

Если приложение и Nginx показывают симптомы, системные логи часто показывают механизм.

1) OOM Killer — одна из самых частых причин внезапного падения процесса:

dmesg -T | grep -Ei 'killed process|out of memory|oom'
journalctl -k --since "1 hour ago" | grep -Ei 'oom|killed process'

Если видите Killed process 1234 (node) или java, причина не в Nginx. Дальше нужно выяснять, почему выросла память: утечка, большой запрос, кэш, лимиты контейнера, изменение нагрузки. Подробный разбор есть в материале про OOM Killer в Linux.

2) Забитый диск — сайт может упасть из-за невозможности писать сессии, временные файлы, WAL, логи, uploads:

df -h
df -i
du -sh /var/log/* 2>/dev/null | sort -h

Проверяйте не только место, но и inode: df -i. Миллионы мелких файлов могут исчерпать inode при свободных гигабайтах.

3) Проблемы с портами и сокетами — если приложение живо, но порт не слушает:

ss -lntp
ss -s
lsof -iTCP -sTCP:LISTEN -P -n

Ищите конфликт портов, зависший старый процесс, нехватку file descriptors, переполненные очереди.

4) Лимиты systemd и контейнеров — сервис может упираться не в сервер, а в свой sandbox:

systemctl show myapp.service | grep -E 'MemoryMax|TasksMax|LimitNOFILE'
ulimit -n

В Docker смотрите лимиты памяти и рестарты. В Kubernetes — kubectl describe pod, OOMKilled, CrashLoopBackOff, readiness/liveness probes.

5) Load average и CPU steal — высокий load average не всегда означает нехватку CPU. Это могут быть процессы в ожидании диска. Проверяйте top, htop, iostat, vmstat. Если CPU свободен, но запросы стоят, смотрите I/O latency, блокировки, сеть, базу.

База данных и внешние зависимости: падение сайта не всегда в приложении

Когда сайт отвечает 500 или 504, приложение часто лишь передаёт проблему от зависимости.

1) Пул соединений — классика: база доступна, но новых соединений нет. В логах приложения:

  • too many connections;
  • remaining connection slots are reserved;
  • connection pool timeout;
  • sorry, too many clients already.

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

2) Медленные запросы — если upstream timeout стабильно около 30s или 60s, ищите SQL, который не завершился до таймаута. Включайте slow query log, смотрите pg_stat_activity, EXPLAIN, блокировки.

3) Блокировки и миграции — падение после деплоя может быть связано не с кодом, а с миграцией: ALTER TABLE заблокировал таблицу, транзакция висит, индекс строится не тем способом. В логах приложения будут таймауты, а в базе — ожидания lock.

4) Redis, очереди, S3, внешние API — если сайт зависит от кэша или очереди синхронно, отказ этой зависимости может положить пользовательский путь. Ищите ретраи, рост времени ответа, ошибки DNS, ECONNRESET, ETIMEDOUT.

5) Backpressure и ретраи — опасный сценарий: зависимость тормозит, приложение начинает ретраить, нагрузка растёт, пул забивается, сайт падает полностью. В логах это выглядит как лавина одинаковых timeout-ошибок. Лечится не только поднятием лимитов, но и circuit breaker, очередями, лимитами конкуррентности, graceful degradation.

DNS, TLS и сеть: когда логи приложения пустые

Если в логах приложения ничего нет в момент сбоя, это ценный сигнал: запросы могли не доходить до приложения.

1) DNS — проверьте, куда указывает домен:

dig example.com A +short
dig example.com AAAA +short
dig example.com NS +short

Типичные причины: неверная запись после миграции, истёк домен, разные ответы у DNS-провайдеров, сломался IPv6, кеши ещё держат старый IP.

2) TLS — если браузер показывает SSL-ошибку, а Nginx access-log пустой, рукопожатие могло ломаться до HTTP. Проверяйте:

openssl s_client -connect example.com:443 -servername example.com

Смотрите срок сертификата, цепочку, SNI, соответствие домена, протоколы.

3) Фаервол и маршрутизация — если порт закрыт или соединение висит:

ss -lntp
sudo ufw status
sudo iptables -S
mtr example.com

Проблема может быть на стороне хостинга, сетевого фильтра, security group, CDN origin rules.

4) CDN и WAF — если CDN отдаёт ошибку, origin может быть жив. Сравните запрос через CDN и напрямую на origin IP с нужным Host:

curl -I https://example.com/
curl -I --resolve example.com:443:203.0.113.20 https://example.com/

Если напрямую работает, а через CDN нет — смотрите правила CDN, firewall, origin health, TLS mode.

Как оформить вывод: корневая причина, влияние и действия

Расследование имеет смысл, только если заканчивается понятным выводом. Не «Nginx отдавал 502», а «backend-процесс был убит OOM Killer из-за роста памяти после релиза, поэтому Nginx не мог подключиться к upstream и отдавал 502 с 12:41 до 12:53».

Хороший postmortem можно собрать по простой схеме.

1) Симптом — что видели пользователи: 502 на всех страницах, таймауты API, не открывалась админка, не работала оплата.

2) Время — начало, обнаружение, восстановление. Здесь снова помогают внешние проверки: история алертов Statuser показывает точное время сбоя и восстановления, без споров о том, когда всё началось.

3) Затронутые компоненты — frontend, API, база, CDN, конкретный регион, отдельный endpoint.

4) Корневая причина — событие, без которого инцидент не произошёл бы: не «таймауты», а «миграция заблокировала таблицу»; не «502», а «контейнеры перезапускались из-за OOM».

5) Почему мониторинг не поймал раньше — не было health check, алерт сработал только на полный down, не отслеживались 5xx, не было логов upstream time, не хватало request id.

6) Что исправить — конкретные действия:

  • добавить лимиты и профилирование памяти;
  • настроить slow query log;
  • добавить request id;
  • вынести долгую операцию в очередь;
  • изменить readiness probe;
  • добавить алерт на рост 5xx;
  • настроить ротацию логов;
  • изменить стратегию деплоя;
  • добавить rollback plan.

Если нужен общий план действий во время аварии, посмотрите чеклист что делать, если упал сайт. А для предотвращения повторов полезно связывать логи с метриками: latency, traffic, errors, saturation показывают, где началась деградация, а логи объясняют почему.

FAQ

Почему сайт упал, если сервер работает?
Потому что «сервер работает» не означает, что работает весь путь запроса. Мог упасть backend-процесс, зависнуть база, сломаться DNS, закончиться пул соединений или CDN перестал доставать origin.

С каких логов начинать расследование?
Обычно с access/error логов reverse proxy: Nginx, Apache, Caddy, ingress или балансировщика. Они показывают, что видел пользователь. Потом переходите к логам приложения, systemd/Docker и базе.

Что важнее: логи или метрики?
Нужны оба источника. Метрики показывают форму инцидента: когда началось, что выросло, где saturation. Логи дают детали: конкретные ошибки, исключения, upstream, request id, сообщения ядра.

Можно ли найти причину, если сайт уже восстановился?
Да, если сохранились логи, история алертов и метрики. Главное — сузить временное окно, сопоставить события разных слоёв и искать первое отклонение, а не последние ошибки в хвосте логов.

Опубликовано 14 сентября 202610 минут чтенияАнастасия Левина
Средний рейтинг статьи — 4.8

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний