Сервер работает круглосуточно, и вы не можете наблюдать за ним каждую секунду. Логи — это глаза и уши администратора. Они фиксируют всё, что происходит: кто обратился к сайту, какие ошибки возникли, почему сервис не запустился.
Без логов невозможно:
- понять, почему пользователь видит ошибку 500;
- найти, кто сканирует сервер в поисках уязвимостей;
- выяснить, когда и почему «упал» сайт;
- оценить нагрузку — сколько запросов в час получает сервер.
Привязка к проекту. В предыдущих главах мы развернули WordPress на nginx + PHP-FPM + MariaDB. Теперь научимся анализировать логи работающего сайта — инструментами из главы 05 (grep, awk, sort, uniq, wc), но уже на реальных данных.
В главе 09 мы познакомились с journalctl и научились смотреть
логи конкретного сервиса (-u), следить в реальном времени (-f)
и фильтровать по времени (--since). Теперь расширим эти знания.
Каждое сообщение в журнале имеет приоритет — уровень важности. Можно фильтровать по нему, чтобы видеть только ошибки и не тонуть в информационных сообщениях:
journalctl -p err # только ошибки и критичнее
journalctl -p warning # предупреждения и критичнее
journalctl -p err --since today # ошибки за сегодняТаблица приоритетов (от самого серьёзного к информационному):
| Приоритет | Номер | Описание |
|---|---|---|
emerg |
0 | Система неработоспособна |
alert |
1 | Требуется немедленное вмешательство |
crit |
2 | Критическая ошибка |
err |
3 | Ошибка |
warning |
4 | Предупреждение |
notice |
5 | Важное информационное сообщение |
info |
6 | Информационное сообщение |
debug |
7 | Отладочная информация |
Флаг -p err покажет сообщения с приоритетами 0–3 (от emerg
до err). Это самый полезный фильтр для поиска проблем.
journalctl -b # логи с момента загрузки
journalctl -b -p err # ошибки с момента загрузкиЕсли сервер недавно перезагружался и что-то сломалось, -b покажет
только сообщения текущей сессии — без «хвоста» от прошлых загрузок.
Журнал systemd растёт со временем и может занять значительную часть диска. Проверим, сколько места он занимает:
journalctl --disk-usageArchived and active journals take up 120.5M in the file system.
Если журнал стал слишком большим, можно ограничить его размер или возраст:
sudo journalctl --vacuum-size=500M # оставить не более 500 МБ
sudo journalctl --vacuum-time=7d # удалить записи старше 7 днейДля постоянного ограничения размера отредактируйте файл
/etc/systemd/journald.conf и задайте параметр:
SystemMaxUse=500M
nginx ведёт свои собственные логи, отдельно от системного журнала. Это текстовые файлы, которые можно анализировать утилитами из главы 05.
| Файл | Содержание |
|---|---|
/var/log/nginx/access.log |
Каждый HTTP-запрос к серверу |
/var/log/nginx/error.log |
Ошибки nginx и PHP-FPM |
По умолчанию nginx использует формат combined. Каждая строка — один запрос:
192.168.1.50 - - [17/Mar/2026:10:15:32 +0300] "GET /wp-login.php HTTP/1.1" 200 4523 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
Разберём по полям:
| # | Поле | Пример | Значение |
|---|---|---|---|
| 1 | IP-адрес клиента | 192.168.1.50 |
Кто обратился |
| 2 | Идентификатор | - |
Обычно пустой |
| 3 | Пользователь | - |
Имя (при HTTP-авторизации) |
| 4 | Дата и время | [17/Mar/2026:10:15:32 +0300] |
Когда |
| 5 | Запрос | "GET /wp-login.php HTTP/1.1" |
Метод, URL, протокол |
| 6 | Код ответа | 200 |
Результат (200, 404, 500...) |
| 7 | Размер ответа | 4523 |
В байтах |
| 8 | Referrer | "-" |
Откуда пришёл пользователь |
| 9 | User-Agent | "Mozilla/5.0 ..." |
Браузер или бот |
Знание формата — ключ к анализу. Поля разделены пробелами, а дата, запрос, referrer и user-agent заключены в кавычки или квадратные скобки.
Ошибки выглядят иначе:
2026/03/17 10:20:45 [error] 1234#1234: *5 open() "/var/www/wordpress/favicon.ico" failed (2: No such file or directory), client: 192.168.1.50, server: _, request: "GET /favicon.ico HTTP/1.1"
Здесь видно: дату, уровень ошибки ([error]), описание проблемы
(файл не найден) и детали запроса.
Вот где пригодятся навыки из главы 05. Мы будем анализировать
реальные логи работающего WordPress, используя конвейеры
из awk, sort, uniq, grep и wc.
Все примеры работают с файлом /var/log/nginx/access.log.
Для чтения этого файла может потребоваться sudo.
sudo wc -l /var/log/nginx/access.logsudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | headРазбор конвейера:
awk '{print $1}'— извлечь первое поле (IP-адрес)sort— отсортировать (нужно дляuniq)uniq -c— подсчитать повторенияsort -rn— отсортировать по убыванию числаhead— показать первые 10
Результат:
342 192.168.1.50
128 10.0.0.5
45 192.168.1.1
Если один IP делает тысячи запросов — возможно, это бот или атака.
sudo awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rnДевятое поле ($9) — код ответа. Результат:
412 200
23 301
15 404
3 500
Много 404 — возможно, сломаны ссылки или кто-то сканирует сервер. 500 — ошибки в PHP-коде или проблемы с базой данных.
sudo awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rnЗдесь $9 == 404 фильтрует строки по коду, а $7 — URL запроса.
Вы увидите, какие несуществующие страницы запрашивают чаще всего.
sudo grep '" 500 ' /var/log/nginx/access.logКаждая строка с кодом 500 — повод разобраться. Посмотрите также error.log — там будет описание причины.
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | headsudo awk -v d="$(date -d '1 hour ago' '+%d/%b/%Y:%H')" '$4 ~ d' /var/log/nginx/access.log | wc -lЭтот конвейер формирует строку с датой часовой давности и фильтрует лог по ней. Так можно отслеживать активность по часам.
sudo grep -i 'bot\|crawl\|spider' /var/log/nginx/access.log | awk '{print $1}' | sort -uПокажет IP-адреса поисковых ботов (Googlebot, Bingbot и т.д.).
Error.log содержит ошибки nginx, PHP-FPM и связанных компонентов. Типичные проблемы:
| Ошибка | Причина |
|---|---|
No such file or directory |
Запрошенный файл не существует (404) |
Permission denied |
Нет прав на чтение файла |
upstream timed out |
PHP-FPM не ответил вовремя |
connect() failed |
PHP-FPM не запущен или сокет недоступен |
Посмотреть последние ошибки:
sudo tail -20 /var/log/nginx/error.logНайти ошибки определённого типа:
sudo grep 'Permission denied' /var/log/nginx/error.log
sudo grep 'upstream' /var/log/nginx/error.logСовет. Если сайт показывает ошибку 502 Bad Gateway, первое, что нужно проверить — работает ли PHP-FPM (
systemctl status php*-fpm) и нет ли ошибок проupstreamв error.log.
Логи растут непрерывно. Если access.log получает 10 000 записей в день, через год он будет весить несколько гигабайт. Ротация логов решает эту проблему: старый лог архивируется (сжимается), создаётся новый пустой файл, а самые старые архивы удаляются.
В Debian за это отвечает утилита logrotate, которая запускается автоматически (обычно раз в день через systemd-таймер или cron).
cat /etc/logrotate.d/nginx/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
if [ -d /etc/nginx ]; then
invoke-rc.d nginx rotate >/dev/null 2>&1
fi
endscript
}
Основные директивы:
| Директива | Значение |
|---|---|
daily |
Ротация раз в день |
rotate 14 |
Хранить 14 архивов (2 недели) |
compress |
Сжимать старые логи (gzip) |
delaycompress |
Не сжимать самый свежий архив |
notifempty |
Не ротировать пустые файлы |
create 0640 www-data adm |
Создать новый файл с указанными правами |
postrotate |
Команда после ротации (сигнал nginx перечитать файлы) |
После ротации в /var/log/nginx/ вы увидите файлы вроде:
access.log — текущий лог
access.log.1 — вчерашний (ещё не сжат)
access.log.2.gz — позавчерашний (сжат)
access.log.3.gz — три дня назад
...
Проверим, нет ли ошибок в сервисах нашего стека:
journalctl -u nginx -p err --since today
journalctl -u php*-fpm -p err --since today
journalctl -u mariadb -p err --since todayЕсли вывод пуст — ошибок нет, всё работает.
Чтобы в логах было что анализировать, сделаем несколько запросов:
curl -s http://localhost > /dev/null
curl -s http://localhost/wp-login.php > /dev/null
curl -s http://localhost/not-found-page > /dev/null
curl -s http://localhost/readme.html > /dev/null# Сколько запросов
sudo wc -l /var/log/nginx/access.log
# Топ запрашиваемых URL
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# Коды ответов
sudo awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# Есть ли 404?
sudo awk '$9 == 404 {print $7}' /var/log/nginx/access.logsudo tail -10 /var/log/nginx/error.logВы должны увидеть ошибку для /not-found-page — nginx не нашёл
файл и вернул 404.
ls -la /var/log/nginx/
cat /etc/logrotate.d/nginx| Команда | Описание |
|---|---|
journalctl -p err |
Только ошибки и критичнее |
journalctl -p warning |
Предупреждения и критичнее |
journalctl -b |
Логи с момента загрузки |
journalctl --disk-usage |
Размер журнала на диске |
sudo journalctl --vacuum-size=500M |
Ограничить размер 500 МБ |
sudo journalctl --vacuum-time=7d |
Удалить записи старше 7 дней |
| Команда | Описание |
|---|---|
sudo wc -l /var/log/nginx/access.log |
Количество запросов |
sudo awk '{print $1}' access.log | sort | uniq -c | sort -rn | head |
Топ IP-адресов |
sudo awk '{print $9}' access.log | sort | uniq -c | sort -rn |
Распределение по кодам |
sudo awk '$9 == 404 {print $7}' access.log |
Запросы с ошибкой 404 |
sudo awk '{print $7}' access.log | sort | uniq -c | sort -rn | head |
Популярные страницы |
sudo tail -20 /var/log/nginx/error.log |
Последние ошибки |
-
Выполните
journalctl -p err --since today. Есть ли ошибки в системе? Если есть — от каких сервисов? -
Проверьте размер системного журнала (
journalctl --disk-usage). Если он больше 500 МБ, выполнитеsudo journalctl --vacuum-size=500M. -
Посмотрите последние 20 строк
/var/log/nginx/access.log. Определите для каждой строки: IP клиента, запрошенный URL и код ответа. -
Подсчитайте количество запросов в access.log. Выведите топ-5 IP-адресов по количеству обращений. Есть ли подозрительно активные?
-
Выведите распределение кодов ответа. Какой процент запросов завершился кодом 200? Есть ли коды 404 или 500?
-
Найдите все запросы к
/wp-login.phpв access.log. С каких IP-адресов они приходят? (Подсказка:grep 'wp-login' access.log | awk '{print $1}' | sort | uniq -c.) -
Посмотрите error.log. Найдите ошибки типа
No such file or directory. Какие файлы запрашивают, но не находят? -
Посмотрите конфигурацию ротации логов nginx (
cat /etc/logrotate.d/nginx). Сколько архивов хранится? Как часто происходит ротация? Есть ли уже ротированные файлы в/var/log/nginx/?
В этой главе вы:
- расширили знания о
journalctl: приоритеты сообщений, фильтрация ошибок, управление размером журнала; - разобрали формат логов nginx (access.log и error.log);
- научились анализировать access.log с помощью coreutils: находить самые активные IP, популярные страницы, коды ошибок;
- освоили диагностику по error.log: поиск ошибок прав доступа, отсутствующих файлов и проблем с PHP-FPM;
- познакомились с ротацией логов (logrotate).
Часть II завершена. Вы прошли путь от установки пакетов до полноценного веб-сервера с мониторингом. В следующей части мы перейдём к основам DevOps — начнём с Git (контроль версий), а затем освоим Docker, Docker Compose и базовый CI/CD.