Важливі файли журналів Linux, за якими ви маєте стежити в RHEL 9 і 10
Практичний посібник з файлів журналів, які мають значення в Red Hat Enterprise Linux 9 і 10 та сумісних системах (Oracle Linux, AlmaLinux, Rocky Linux): де лежить кожен, що він вам каже, якими командами його читати і як його зберігати й централізувати.

Кожна проблема на сервері Linux залишає десь слід: невдалий вхід, служба, яка не запустилася, оновлення пакета, що змінило бібліотеку, диск, який почав видавати помилки. Знати, який журнал зберігає який слід, і є різницею між п'ятихвилинною діагностикою та пообіддям здогадок. Цей посібник охоплює журнали, які мають значення в Red Hat Enterprise Linux 9 і 10 та в сумісних системах, таких як Oracle Linux, AlmaLinux і Rocky Linux, з командами, якими ми їх читаємо.
Два місця, де живуть журнали в RHEL: journal і /var/log
У RHEL 9 і 10 майже все спершу збирає systemd-journald. Journal є структурованим індексованим сховищем, яке ви читаєте через journalctl. У стандартній інсталяції rsyslog потім читає journal і пише звичні текстові файли в /var/log: messages, secure, cron, maillog і boot.log. Деякі служби все одно ведуть власні файли, зокрема демон аудиту, веб-сервери, бази даних і dnf.
Перевірте, що rsyslog присутній і працює, перш ніж покладатися на текстові файли. Мінімальні й контейнерні образи можуть його не містити:
rpm -q rsyslog
systemctl status rsyslog
# if it is missing:
dnf install rsyslog
systemctl enable --now rsyslog
Більшість файлів у /var/log читати може лише root, тож виконуйте наведені нижче команди від root або через sudo.
Journal systemd
Journal є першим місцем, куди варто дивитися, бо він зберігає вивід кожного юніта systemd, ядра та всього, що логує через syslog, з точними часовими мітками й метаданими, за якими можна фільтрувати.
Команди, які варто запам'ятати
# everything from one service, newest last
journalctl -u nginx
# follow a service live, like tail -f
journalctl -u sshd -f
# only errors and worse, from the current boot
journalctl -p err -b
# warnings and worse from the previous boot (useful after a crash)
journalctl -p warning -b -1
# a time window
journalctl --since "1 hour ago"
journalctl -u php-fpm --since "2026-10-22 08:00" --until "2026-10-22 09:00"
# kernel messages only (the replacement for reading a dmesg file)
journalctl -k -b
# search message text
journalctl -u sshd -g "Failed password"
# list the boots the journal knows about
journalctl --list-boots
Кілька опцій -u можна поєднувати, що зручно, коли запит проходить через більш ніж одну службу: journalctl -u nginx -u php-fpm --since "10 min ago".
Зробіть journal постійним
У типовій інсталяції RHEL journal зберігається в /run/log/journal, у пам'яті, і зникає після перезавантаження. А це саме та мить, коли він потрібен найбільше. Щоб зберігати його на диску, створіть drop-in і перезапустіть journald:
mkdir -p /etc/systemd/journald.conf.d
vi /etc/systemd/journald.conf.d/persistent.conf
[Journal]
Storage=persistent
SystemMaxUse=2G
systemctl restart systemd-journald
journalctl --flush
ls -ld /var/log/journal
journalctl --disk-usage
SystemMaxUse обмежує простір, який може зайняти journal; оберіть значення, що пасує вашому диску. Після наступного перезавантаження journalctl --list-boots покаже більш ніж один запис, а journalctl -b -1 запрацює.
/var/log/messages: загальний системний журнал
Це файл «усе підряд»: запуски та зупинки служб, повідомлення ядра, попередження обладнання та драйверів, зміни мережі та все інше рівня info і вище, що не належить до категорій пошти, автентифікації чи cron. Він є текстовим відповідником великої частини journal і зручний для grep та для інструментів, які очікують звичайних файлів.
tail -f /var/log/messages
grep -iE "error|fail|oom" /var/log/messages | tail -50
grep -i "out of memory" /var/log/messages
Рядок на кшталт Out of memory: Killed process означає, що ядро завершило процес, бо серверу забракло RAM. Відповідь: дати навантаженню більше пам'яті або зменшити її споживання (менше воркерів PHP-FPM чи бази даних, кеш, виправлення витоку), а не ховати симптом.
/var/log/secure: журнал безпеки Linux для автентифікації та привілеїв
Кожен вхід по SSH, кожен невдалий пароль, кожен sudo і su, а також повідомлення PAM потрапляють сюди. У RHEL, Oracle Linux, AlmaLinux і Rocky Linux це файл, за яким слід стежити щодо доступу до сервера.
# failed SSH passwords and the addresses they came from
grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
# successful logins
grep "Accepted" /var/log/secure
# who used sudo, and for what
grep "COMMAND=" /var/log/secure
Картину доповнюють два пов'язані інструменти. last перелічує успішні входи з /var/log/wtmp, а lastb перелічує невдалі з /var/log/btmp. Якщо облікові записи блокуються після невдалих спроб, faillock --user alice показує спроби, а faillock --user alice --reset їх скидає.
/var/log/audit/audit.log: слід аудиту
Система аудиту Linux записує значущі для безпеки події на рівні ядра: входи, зміни привілеїв, рішення SELinux і будь-який файл чи системний виклик, за яким ви вирішите стежити. Його пише auditd, а читають ausearch і aureport, а не grep, бо ці інструменти розуміють його формат.
# summary of everything in the log
aureport --summary
# failed logins
aureport --login --failed
# authentication attempts
aureport -au
# today's events, with numeric IDs turned into names
ausearch -ts today -i
# failed login events only
ausearch -m USER_LOGIN -sv no -i
Стежте за файлами, які мають значення
Правила аудиту дають змогу записувати кожну зміну чутливого файлу. Покладіть їх у файл у /etc/audit/rules.d/, наприклад /etc/audit/rules.d/50-watch.rules:
-w /etc/ssh/sshd_config -p wa -k sshd_config
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
augenrules --load
auditctl -l
ausearch -k sshd_config -i
Остання команда показує, хто змінив конфігурацію SSH, коли і якою програмою.
Відмови SELinux
RHEL працює із SELinux у режимі enforcing, і так має залишатися. Коли SELinux щось блокує, відмова записується як запис AVC у журнал аудиту. Подивіться туди, перш ніж змінювати щось інше:
getenforce
ausearch -m AVC,USER_AVC -ts recent -i
ausearch -m AVC -ts today | audit2why
Для пояснення простою мовою з пропонованими виправленнями встановіть setroubleshoot і запустіть sealert на журнал:
dnf install setroubleshoot-server
sealert -a /var/log/audit/audit.log
Більшість відмов мають просту причину: файл з неправильною міткою (виправляється через restorecon -Rv <path>), вміст у нестандартному каталозі (позначте його через semanage fcontext) або функція, якій потрібно увімкнути boolean (getsebool -a | grep httpd, потім setsebool -P). Пройдіть ці варіанти, перш ніж думати про власний модуль політики.
/var/log/cron: заплановані завдання
Кожне завдання, запущене crond і anacron, логується сюди з користувачем і командою. Коли backup або звіт «не виконався», цей файл каже, чи його взагалі було запущено.
grep CROND /var/log/cron | tail -20
grep "(root) CMD" /var/log/cron | tail -20
Багато службових завдань RHEL тепер працюють як таймери systemd замість завдань cron. Перелічіть їх через systemctl list-timers і читайте їхній вивід через journalctl -u <name>.service, наприклад journalctl -u logrotate.service.
/var/log/maillog: доставлення пошти
Postfix та інше поштове програмне забезпечення логують сюди кожне повідомлення, яке приймають, пересилають, відкладають або повертають. Якщо веб-застосунок каже, що надіслав лист, а ніхто його не отримав, відповідь зазвичай у цьому файлі.
# the full path of one message, by recipient
grep "user@example.org" /var/log/maillog
# bounces and deferrals
grep -E "status=(bounced|deferred)" /var/log/maillog | tail -20
# what is still waiting in the queue
postqueue -p
Кожне повідомлення Postfix має ідентифікатор черги (наприклад 4F2A81C0B3E). Шукайте цей ідентифікатор через grep, щоб побачити кожен крок його доставлення, зокрема відповідь сервера-отримувача.
/var/log/dnf.log і dnf history: що змінилося
Коли щось ламається після обслуговування, перше запитання: що змінилося. У RHEL 9 і 10 операціями з пакетами керує dnf, який пише /var/log/dnf.log (сам запуск dnf), /var/log/dnf.rpm.log (кожен встановлений, оновлений чи видалений пакет) і /var/log/dnf.librepo.log (завантаження з репозиторіїв). Найшвидший огляд дає база історії:
# every transaction, newest first
dnf history
# exactly what one transaction did
dnf history info last
dnf history info 42
# every transaction that touched a package
dnf history list nginx
# packages changed recently, from the log file
grep -E "Install|Upgrade|Erase" /var/log/dnf.rpm.log | tail -30
# does anything need a restart after updates (dnf-plugins-core)
dnf needs-restarting -r
Якщо оновлення треба відкотити, dnf history undo <id> відкочує одну транзакцію, за умови що старіші пакети ще доступні в репозиторіях.
/var/log/boot.log і journal завантаження
/var/log/boot.log зберігає повідомлення стану запуску, які ви бачили б на консолі. Він корисний для швидкого погляду, але повний запис завантаження лежить у journal:
cat /var/log/boot.log
journalctl -b -p err
journalctl -b -1 -p err # previous boot, needs the persistent journal
systemctl --failed # units that did not start
systemd-analyze blame | head # what took longest
Журнали веб-сервера та PHP
Кожен веб-сервер веде власні журнали доступу та помилок:
- nginx:
/var/log/nginx/access.logі/var/log/nginx/error.log, плюс будь-які файли для окремих сайтів, які ви визначаєте черезaccess_logіerror_log. - Apache httpd:
/var/log/httpd/access_log,/var/log/httpd/error_log, а такожssl_access_logіssl_error_log, коли встановлено mod_ssl. - PHP-FPM:
/var/log/php-fpm/error.logдля майстер-процесу FPM і/var/log/php-fpm/www-error.logдля помилок PHP з типового пулу. Пул також може писати slow log зі стеком викликів кожного повільного запиту, щойно заданоrequest_slowlog_timeout.
# top client addresses (default nginx log format)
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# count of server errors (5xx) by URL
awk '$9 ~ /^5/ {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# the latest errors
tail -50 /var/log/nginx/error.log
tail -50 /var/log/php-fpm/www-error.log
Сплеск відповідей 502 або 504 в access log, якому відповідають «upstream timed out» або «connect() failed» у error log nginx, вказує на PHP-FPM: або всі воркери були зайняті, або скрипт виконувався надто довго.
Журнали баз даних
- MariaDB (база даних у репозиторіях RHEL):
/var/log/mariadb/mariadb.log, задається черезlog-errorу/etc/my.cnf.d/mariadb-server.cnf. - MySQL з репозиторіїв RHEL:
/var/log/mysql/mysqld.log. - PostgreSQL:
/var/lib/pgsql/data/log/, типово по одному файлу на день тижня.
Error log показує проблеми запуску, збої, пошкоджені таблиці та помилки реплікації. Для продуктивності увімкніть slow query log. Для MariaDB додайте в секцію [mysqld] файлу /etc/my.cnf.d/mariadb-server.cnf і перезапустіть:
slow_query_log = 1
slow_query_log_file = /var/log/mariadb/mariadb-slow.log
long_query_time = 1
Потім підсумуйте його через mysqldumpslow -s t /var/log/mariadb/mariadb-slow.log | head -40, щоб побачити, які запити коштують найбільше сумарного часу.
Тримаємо журнали під контролем за допомогою logrotate
RHEL ротує файли журналів через logrotate, який раз на день запускає таймер systemd (logrotate.timer). Глобальні типові налаштування містяться в /etc/logrotate.conf (щотижня, чотири ротації, імена файлів з датою на кшталт messages-20261018), а кожен пакет додає власні правила в /etc/logrotate.d/. Системні файли (messages, secure, cron, maillog) охоплює /etc/logrotate.d/rsyslog.
systemctl list-timers logrotate.timer
cat /etc/logrotate.d/nginx
# dry run: show what would happen, change nothing
logrotate -d /etc/logrotate.d/nginx
# force a rotation now, verbosely
logrotate -vf /etc/logrotate.d/nginx
Для власного застосунку додайте файл на кшталт /etc/logrotate.d/myapp:
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 myapp myapp
postrotate
/usr/bin/systemctl reload myapp.service >/dev/null 2>&1 || true
endscript
}
Тримайте журнали застосунків у /var/log: файли там отримують мітку SELinux, якою logrotate має право керувати. Якщо в каталог журналів може писати користувач, відмінний від root, додайте рядок su myapp myapp, щоб logrotate міг безпечно його ротувати.
Journal ротує себе сам у межах ліміту SystemMaxUse. Щоб підрізати його вручну, використайте journalctl --vacuum-time=30d або journalctl --vacuum-size=1G.
Централізація журналів через rsyslog
Журнали, які живуть лише на сервері, який вони описують, мають дві слабкості: щоб їх прочитати, треба заходити на кожну машину, а зловмисник, який отримає root, може їх відредагувати. Пересилання журналів кожного сервера на центральний колектор вирішує обидві та дає змогу під час інциденту шукати в одному місці. Колектором може бути інший сервер RHEL з rsyslog або платформа журналів на кшталт Graylog.
На колекторі
Створіть /etc/rsyslog.d/10-collector.conf. Він слухає TCP-порт 20514, який політика SELinux уже позначає як порт syslog (перевірте через semanage port -l | grep syslogd), і пише по одному файлу на хост і програму:
module(load="imtcp")
template(name="RemotePerHost" type="string"
string="/var/log/remote/%HOSTNAME:::secpath-replace%/%PROGRAMNAME:::secpath-replace%.log")
ruleset(name="remote") {
action(type="omfile" dynaFile="RemotePerHost")
}
input(type="imtcp" port="20514" ruleset="remote")
Відкрийте порт лише для своїх серверів, тут через зону firewalld internal, потім перевірте конфігурацію й перезапустіть:
firewall-cmd --permanent --zone=internal --add-source=10.0.10.0/24
firewall-cmd --permanent --zone=internal --add-port=20514/tcp
firewall-cmd --reload
rsyslogd -N1
systemctl restart rsyslog
ss -tlnp | grep 20514
Якщо ви обираєте порт, який ще не позначений, спершу додайте його через semanage port -a -t syslogd_port_t -p tcp <port>, на колекторі та на відправниках. Додайте правило logrotate для /var/log/remote//.log, як показано вище.
На кожному сервері
Створіть /etc/rsyslog.d/90-central.conf. TCP з дисковою чергою означає, що перезапуск колектора або перерва в мережі затримує повідомлення замість втрачати їх:
*.* action(type="omfwd" target="logs.example.net" port="20514" protocol="tcp"
template="RSYSLOG_SyslogProtocol23Format"
queue.type="LinkedList" queue.filename="fwd_central"
queue.maxDiskSpace="1g" queue.saveOnShutdown="on"
action.resumeRetryCount="-1")
rsyslogd -N1
systemctl restart rsyslog
Щоб пересилати й події аудиту, задайте active = yes у /etc/audit/plugins.d/syslog.conf і перезапустіть auditd через service auditd restart (auditd не приймає перезапуск через systemctl).
Доведіть, що воно доходить
Надішліть тестове повідомлення і знайдіть його на колекторі:
# on the server
logger -t logtest "central logging test from $(hostname)"
# on the collector
tail /var/log/remote/*/logtest.log
Повторюйте тест після кожної зміни колектора чи firewall і сповіщайте про тишу: сервер, який перестав надсилати журнали, легко пропустити, бо ніщо в журналах вам про це не скаже.
Короткий щоденний чекліст
journalctl -p err -b: щось нове рівня error з моменту завантаження?aureport --login --failedіlastb | head: незвичні невдалі входи?ausearch -m AVC -ts today: якісь відмови SELinux?dnf history: змінилося щось, чого ви не планували?tail /var/log/nginx/error.logі error log бази даних: проблеми в застосунку?journalctl --disk-usageіdf -h /var/log: є місце, щоб логувати далі?
Читання цього займає кілька хвилин. Автоматизація, через центральний колектор і сповіщення про важливі патерни, і є тим, що перетворює журнали з архіву на систему раннього попередження.
Інженери EuroVPS будують, ведуть і наглядають за такими конвеєрами журналів для клієнтів на наших managed-серверах.
З архіву блогу EuroVPS, уперше опубліковано 19 квітня 2020 р..
Усі нотатки з практики