Ir al contenido
EuroVPSEuroVPS

Los archivos de registro de Linux que debe vigilar en RHEL 9 y 10

Una guía práctica de los archivos de registro que importan en Red Hat Enterprise Linux 9 y 10 y en sistemas compatibles (Oracle Linux, AlmaLinux, Rocky Linux): dónde está cada uno, qué le dice, los comandos para leerlo, y cómo conservarlo y centralizarlo.

Por EuroVPS Engineering

Actualizado el 22 de octubre de 202611 min de lectura
Imagen de portada: archivos de registro de Linux

Todo problema en un servidor Linux deja un rastro en algún sitio: un inicio de sesión fallido, un servicio que no arrancó, una actualización de paquete que cambió una biblioteca, un disco que empezó a dar errores. Saber qué archivo de registro guarda qué rastro es la diferencia entre un diagnóstico de cinco minutos y una tarde de conjeturas. Esta guía cubre los registros que importan en Red Hat Enterprise Linux 9 y 10, y en sistemas compatibles como Oracle Linux, AlmaLinux y Rocky Linux, con los comandos que usamos para leerlos.

Dos lugares donde viven los logs en RHEL: el journal y /var/log

En RHEL 9 y 10 casi todo lo recoge primero systemd-journald. El journal es un almacén estructurado e indexado que se lee con journalctl. En una instalación estándar, rsyslog lee después el journal y escribe los conocidos archivos de texto en /var/log: messages, secure, cron, maillog y boot.log. Algunos servicios mantienen sus propios archivos de todos modos, en especial el demonio de auditoría, los servidores web, las bases de datos y dnf.

Compruebe que rsyslog está instalado y en marcha antes de confiar en los archivos de texto. Las imágenes mínimas y de contenedor pueden no incluirlo:

rpm -q rsyslog systemctl status rsyslog # if it is missing: dnf install rsyslog systemctl enable --now rsyslog

La mayoría de los archivos de /var/log solo los puede leer root, así que ejecute los comandos siguientes como root o con sudo.

El journal de systemd

El journal es el primer sitio donde mirar, porque guarda la salida de cada unidad de systemd, del kernel y de todo lo que registra a través de syslog, todo con marcas de tiempo precisas y metadatos por los que puede filtrar.

Comandos que merece la pena memorizar

# 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

Varias opciones -u pueden combinarse, lo que resulta útil cuando una petición pasa por más de un servicio: journalctl -u nginx -u php-fpm --since "10 min ago".

Haga el journal persistente

En una instalación RHEL por defecto el journal se guarda en /run/log/journal, en memoria, y desaparece tras un reinicio. Ese es exactamente el momento en que más lo quiere. Para conservarlo en disco, cree un drop-in y reinicie 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 limita el espacio que el journal puede usar. Elija un valor que convenga al disco. Tras el siguiente reinicio, journalctl --list-boots muestra más de una entrada y journalctl -b -1 funciona.

/var/log/messages: el registro general del sistema

Este es el archivo que lo recoge todo: arranques y paradas de servicios, mensajes del kernel, avisos de hardware y controladores, cambios de red y cualquier otra cosa registrada a nivel info o superior que no pertenezca a las categorías de correo, autenticación o cron. Es el equivalente en texto de buena parte del journal, y resulta cómodo para grep y para herramientas que esperan archivos planos.

tail -f /var/log/messages grep -iE "error|fail|oom" /var/log/messages | tail -50 grep -i "out of memory" /var/log/messages

Una línea como Out of memory: Killed process significa que el kernel terminó un proceso porque el servidor se quedó sin RAM. La respuesta es dar más memoria a la carga de trabajo o reducir la que usa (menos workers de PHP-FPM o de base de datos, una cache, corregir una fuga), no esconder el síntoma.

/var/log/secure: el registro de seguridad de Linux para autenticación y privilegios

Cada inicio de sesión SSH, cada contraseña fallida, cada sudo y su, y los mensajes de PAM acaban aquí. En RHEL, Oracle Linux, AlmaLinux y Rocky Linux este es el archivo que vigilar para el acceso al servidor.

# 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

Dos herramientas relacionadas completan la imagen. last lista los inicios de sesión correctos a partir de /var/log/wtmp, y lastb los fallidos a partir de /var/log/btmp. Si las cuentas se bloquean tras intentos fallidos, faillock --user alice muestra los intentos y faillock --user alice --reset los limpia.

/var/log/audit/audit.log: la pista de auditoría

El sistema de auditoría de Linux registra eventos relevantes para la seguridad a nivel de kernel: inicios de sesión, cambios de privilegios, decisiones de SELinux y cualquier archivo o llamada al sistema que decida vigilar. Lo escribe auditd y se lee con ausearch y aureport en lugar de grep, porque esas herramientas entienden su formato.

# 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

Vigile los archivos que importan

Las reglas de auditoría le permiten registrar cada cambio en un archivo sensible. Póngalas en un archivo bajo /etc/audit/rules.d/, por ejemplo /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

El último comando muestra quién cambió la configuración de SSH, cuándo y con qué programa.

Denegaciones de SELinux

RHEL funciona con SELinux en enforcing, y así debe seguir. Cuando SELinux bloquea algo, la denegación se registra como un registro AVC en el archivo de auditoría. Mire ahí antes de cambiar nada más:

getenforce ausearch -m AVC,USER_AVC -ts recent -i ausearch -m AVC -ts today | audit2why

Para una explicación en lenguaje llano con soluciones sugeridas, instale setroubleshoot y ejecute sealert sobre el archivo:

dnf install setroubleshoot-server sealert -a /var/log/audit/audit.log

La mayoría de las denegaciones tienen una causa simple: un archivo con la etiqueta equivocada (se corrige con restorecon -Rv <path>), contenido colocado en un directorio no estándar (etiquételo con semanage fcontext), o una función que necesita un boolean activado (getsebool -a | grep httpd, después setsebool -P). Agote esas opciones antes de considerar un módulo de política a medida.

/var/log/cron: tareas programadas

Cada tarea iniciada por crond y anacron se registra aquí, con el usuario y el comando. Cuando un backup o un informe «no se ejecutó», este archivo le dice si llegó a arrancar.

grep CROND /var/log/cron | tail -20 grep "(root) CMD" /var/log/cron | tail -20

Muchas tareas de mantenimiento de RHEL se ejecutan ahora como systemd timers en lugar de cron jobs. Lístelos con systemctl list-timers y lea su salida con journalctl -u <name>.service, por ejemplo journalctl -u logrotate.service.

/var/log/maillog: entrega de correo

Postfix y otro software de correo registran aquí cada mensaje que aceptan, reenvían, aplazan o devuelven. Si una aplicación web dice que envió un email y nadie lo recibió, la respuesta suele estar en este archivo.

# 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

Cada mensaje de Postfix tiene un queue ID (por ejemplo 4F2A81C0B3E). Haga grep de ese ID para ver cada paso de su entrega, incluida la respuesta del servidor receptor.

/var/log/dnf.log y dnf history: qué cambió

Cuando algo se rompe tras un mantenimiento, la primera pregunta es qué cambió. En RHEL 9 y 10 las operaciones de paquetes las gestiona dnf, que escribe /var/log/dnf.log (la propia ejecución de dnf), /var/log/dnf.rpm.log (cada paquete instalado, actualizado o eliminado) y /var/log/dnf.librepo.log (descargas de repositorios). La vista más rápida es la base de datos de historial:

# 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

Si una actualización debe revertirse, dnf history undo <id> deshace una sola transacción, siempre que los paquetes antiguos sigan disponibles en los repositorios.

/var/log/boot.log y el journal del arranque

/var/log/boot.log guarda los mensajes de estado del arranque que vería en la consola. Es útil para un vistazo rápido, pero el registro completo de un arranque está en el 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

Logs del servidor web y de PHP

Cada servidor web mantiene sus propios access y error logs:

  • nginx: /var/log/nginx/access.log y /var/log/nginx/error.log, más los archivos por sitio que defina con access_log y error_log.
  • Apache httpd: /var/log/httpd/access_log, /var/log/httpd/error_log, y ssl_access_log y ssl_error_log cuando mod_ssl está instalado.
  • PHP-FPM: /var/log/php-fpm/error.log para el master de FPM y /var/log/php-fpm/www-error.log para los errores PHP del pool por defecto. El pool también puede escribir un slow log con un stack trace de cada petición lenta una vez establecido 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

Una ráfaga de respuestas 502 o 504 en el access log, acompañada de «upstream timed out» o «connect() failed» en el error log de nginx, señala a PHP-FPM: o todos los workers estaban ocupados o un script se ejecutó demasiado tiempo.

Logs de bases de datos

  • MariaDB (la base de datos de los repositorios RHEL): /var/log/mariadb/mariadb.log, definido con log-error en /etc/my.cnf.d/mariadb-server.cnf.
  • MySQL de los repositorios RHEL: /var/log/mysql/mysqld.log.
  • PostgreSQL: /var/lib/pgsql/data/log/, un archivo por día de la semana por defecto.

El error log muestra problemas de arranque, caídas, tablas corruptas y errores de replicación. Para el rendimiento, active el slow query log. Para MariaDB, añada en la sección [mysqld] de /etc/my.cnf.d/mariadb-server.cnf y reinicie:

slow_query_log = 1 slow_query_log_file = /var/log/mariadb/mariadb-slow.log long_query_time = 1

Después resúmalo con mysqldumpslow -s t /var/log/mariadb/mariadb-slow.log | head -40 para ver qué consultas cuestan más tiempo total.

Mantener los logs bajo control con logrotate

RHEL rota los archivos de registro con logrotate, que se ejecuta una vez al día desde un systemd timer (logrotate.timer). Los valores globales por defecto están en /etc/logrotate.conf (semanal, cuatro rotaciones, nombres de archivo con fecha como messages-20261018), y cada paquete añade sus propias reglas bajo /etc/logrotate.d/. Los archivos del sistema (messages, secure, cron, maillog) los cubre /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

Para su propia aplicación, añada un archivo como /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 }

Mantenga los logs de las aplicaciones bajo /var/log: los archivos allí reciben la etiqueta SELinux que logrotate tiene permitido gestionar. Si el directorio de logs es escribible por un usuario distinto de root, añada una línea su myapp myapp para que logrotate pueda rotarlo con seguridad.

El journal se rota solo dentro del límite SystemMaxUse. Para recortarlo a mano, use journalctl --vacuum-time=30d o journalctl --vacuum-size=1G.

Centralizar los logs con rsyslog

Los logs que viven solo en el servidor que describen tienen dos debilidades: hay que iniciar sesión en cada máquina para leerlos, y un atacante que consiga root puede editarlos. Reenviar los logs de cada servidor a un colector central resuelve ambas, y le permite buscar en un solo sitio durante un incidente. El colector puede ser otro servidor RHEL con rsyslog, o una plataforma de logs como Graylog.

En el colector

Cree /etc/rsyslog.d/10-collector.conf. Escucha en el puerto TCP 20514, que la política SELinux ya etiqueta como puerto de syslog (compruébelo con semanage port -l | grep syslogd), y escribe un archivo por host y programa:

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")

Abra el puerto solo a sus servidores, aquí a través de la zona internal de firewalld, y después valide y reinicie:

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

Si elige un puerto que aún no está etiquetado, añádalo primero con semanage port -a -t syslogd_port_t -p tcp <port>, en el colector y en los emisores. Añada una regla de logrotate para /var/log/remote//.log como se mostró arriba.

En cada servidor

Cree /etc/rsyslog.d/90-central.conf. TCP con una cola asistida por disco significa que un reinicio del colector o una interrupción de red retrasa los mensajes en lugar de perderlos:

*.* 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

Para enviar también los eventos de auditoría, establezca active = yes en /etc/audit/plugins.d/syslog.conf y reinicie auditd con service auditd restart (auditd no acepta un reinicio a través de systemctl).

Demuestre que llega

Envíe un mensaje de prueba y encuéntrelo en el colector:

# on the server logger -t logtest "central logging test from $(hostname)" # on the collector tail /var/log/remote/*/logtest.log

Repita la prueba tras cada cambio en el colector o en el firewall, y alerte ante el silencio: un servidor que ha dejado de enviar logs es fácil de pasar por alto, porque nada en los logs se lo dice.

Una lista rápida de comprobación diaria

  • journalctl -p err -b: ¿algo nuevo a nivel de error desde el arranque?
  • aureport --login --failed y lastb | head: ¿inicios de sesión fallidos inusuales?
  • ausearch -m AVC -ts today: ¿denegaciones de SELinux?
  • dnf history: ¿cambió algo que no había planificado?
  • tail /var/log/nginx/error.log y el error log de la base de datos: ¿problemas de aplicación?
  • journalctl --disk-usage y df -h /var/log: ¿espacio para seguir registrando?

Leer esto lleva unos minutos. Automatizarlo, mediante un colector central y alertas sobre los patrones que importan, es lo que convierte los logs de un archivo histórico en una alerta temprana.

Los ingenieros de EuroVPS construyen, operan y vigilan cadenas de logs como esta para clientes en nuestros managed servers.

Del archivo del blog de EuroVPS, publicado por primera vez el 19 de abril de 2020.

Todas las notas de campo