Monitorización sencilla de un servidor con las herramientas del sistema

Publicado el 21 min de lectura

Un script de comprobación, un timer de systemd y una vía de notificación probada bastan para un solo servidor root. Esta guía muestra qué hay que vigilar, cómo comprobar cada paso y a partir de cuándo compensa la caja de herramientas grande.

Un servidor no avisa por su cuenta cuando algo va mal. Sigue funcionando hasta que deja de funcionar, y el primer aviso te llega de un cliente o de ti mismo, cuando por casualidad te fijas. Esta guía monta la vigilancia más pequeña que acaba con eso: un script de comprobación, un timer de systemd y una vía de notificación. Sin base de datos de series temporales, sin dashboard y sin ningún puerto abierto de más.

Los sistemas de referencia son Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS y Ubuntu 22.04 LTS. Donde los cuatro se diferencian, se indica de forma expresa. Todos los comandos están escritos para ejecutarse como root; si trabajas como usuario normal, antepón sudo a cada comando. Esta guía profundiza en el paso 8 de la checklist para un servidor root nuevo.

Qué deberías vigilar realmente

El error más frecuente en una primera monitorización no es medir poco, sino medir demasiado. Quien recoge 40 métricas no mira ninguna. Solo tiene sentido aquello que puede tumbar el servicio y ante lo que puedes reaccionar. Quedan siete puntos.

MétricaPor qué está en la listaDe dónde sale el valorUmbral razonable
Espacio en discoLa causa de caída más habitual y la que nadie ve venirdf --output=pcent,targeta partir del 85 por ciento
InodosEl disco parece libre y aun así aparece "No space left on device"df --output=ipcent,targeta partir del 85 por ciento
RAM disponibleEl OOM killer rara vez elige el proceso que tú sacrificaríasMemAvailable en /proc/meminfopor debajo de 200 MB
Carga del sistemaDelata el atasco, tanto si la causa es la CPU como el discotercer campo de /proc/loadavgmedia de 15 minutos por encima del doble de núcleos
Servicios fallidosUn servicio que muere de noche sigue muerto hasta la mañanasystemctl is-system-runningcualquier cosa que no sea running
Caducidad del certificadoDeja fuera de golpe a todos los visitantes, no solo a una parteopenssl x509 -checkendmenos de 21 días de validez restante
Accesibilidad desde fueraEs la única comprobación que responde si el servidor sigue ahísegundo host, curldos fallos seguidos

En la lista no está el uso de CPU en porcentaje: un servidor que consume el 100 por ciento porque está codificando vídeo trabaja exactamente como debe. El rendimiento de red y el número de procesos faltan por el mismo motivo. Ambos ayudan a buscar la causa, pero no sirven como alarma, porque no hay ningún valor a partir del cual estés obligado a intervenir.

La vía de retorno, antes de crear el primer archivo

Vigilar es una operación de solo lectura y, en condiciones normales, no puede romper nada. Aun así, hay tres cosas que sí pueden.

Un script que repara en lugar de avisar. La idea es tentadora: si nginx está muerto, que el script lo reinicie y listo. De ahí sale un servicio que arranca cada diez minutos, dura medio segundo y tapa la causa real. Y un script que borra por su cuenta cuando el disco se llena acaba borrando algo que hacía falta. La primera versión solo lee y no llama ni a systemctl restart ni a rm ni a kill.

Interfaces de red abiertas. Los exportadores de métricas que escuchan en todas las direcciones son una de las publicaciones de datos involuntarias más frecuentes en servidores individuales. El método de esta guía no abre ningún puerto y no necesita ninguna regla de firewall.

La propia vía de aviso. Una vigilancia cuya notificación no se ha probado nunca no es una vigilancia, es una sensación agradable. La prueba está más abajo y no es opcional.

Cómo entrar en el servidor sin SSH

Los servidores root KVM y los servidores dedicados no tienen ni IPMI ni iDRAC. Cuando SSH deja de responder, la vía de acceso es la consola VNC del área de cliente. No depende del stack de red del sistema huésped, así que ni una regla de firewall ni un servicio SSH saturado pueden bloquearla. Inicia sesión ahí una vez antes de empezar y asegúrate de conocer la contraseña de root.

El interruptor de apagado

Si la propia vigilancia se convierte en el problema, por ejemplo porque manda avisos cada minuto, necesitas dos comandos. Apréndetelos antes de empezar:

systemctl disable --now kh-monitor.timer
systemctl mask kh-monitor.service

El primero detiene el timer de inmediato e impide que vuelva en el siguiente arranque. El segundo es el freno de emergencia: un servicio enmascarado tampoco se puede arrancar a mano por descuido, y se revierte con systemctl unmask kh-monitor.service. El método tiene poco riesgo sobre todo porque solo se crean archivos nuevos; deshacerlo consiste en borrar esos archivos. Aun así, mantén una segunda sesión SSH abierta mientras trabajas en el sistema.

Comprobar las métricas primero a mano

Antes de que un script evalúe nada, conviene que hayas visto cada valor con tus propios ojos. Si no, más adelante no sabrás si un aviso está justificado o si tu umbral es un disparate.

Espacio en disco e inodos

df -h
df --output=pcent,target -x tmpfs -x devtmpfs -x squashfs -x overlay
df -i

Las exclusiones son necesarias. En Ubuntu 22.04 y 24.04, snap monta sus paquetes como imágenes squashfs de solo lectura, y esas están por naturaleza permanentemente al 100 por ciento. Sin -x squashfs, tu vigilancia avisará de un disco lleno desde la primera ejecución, todos los días, para siempre. Con los puntos de montaje overlay de Docker pasa lo mismo.

Hay dos particularidades que conviene conocer. df no acepta -P y --output a la vez y aborta con un mensaje sobre opciones mutuamente excluyentes. Y en ext4 viene reservado de fábrica un cinco por ciento para root, por lo que df ya indica el 100 por ciento mientras root todavía puede escribir. Lo que toca hacer después del aviso está en Disco lleno en Linux.

La comprobación de inodos no es un tema marginal. Un directorio con millones de archivos diminutos de sesión o de caché puede consumir todos los inodos mientras df -h muestra espacio libre de sobra. Las escrituras fallan entonces con No space left on device, y la explicación evidente es justo la equivocada.

Memoria RAM

free -m
awk '/^MemAvailable:/ { printf "%d MB\n", $2 / 1024 }' /proc/meminfo

En un sistema Linux sano, la columna free es casi siempre pequeña, porque el kernel aprovecha la memoria sin usar como caché de archivos. El único dato fiable es available, es decir MemAvailable: la cantidad de memoria que puede recibir una aplicación nueva sin que nada acabe en swap. Genera el aviso sobre ese valor, nunca sobre free.

Si la cosa ya estuvo apurada antes, lo delata el log del kernel:

journalctl -k -b --grep "Out of memory"

Cada coincidencia es un proceso que el kernel terminó porque se agotó la memoria. Cómo reaccionar sin crear swap a ciegas se explica en Out of Memory y cómo configurar swap correctamente.

Carga del sistema

nproc
cat /proc/loadavg
uptime

Los tres primeros campos de /proc/loadavg son las medias de uno, cinco y quince minutos. Hay dos cosas que se malinterpretan una y otra vez. La primera: en Linux, la carga no es una magnitud puramente de CPU, porque los procesos que esperan accesos a disco también cuentan. Una carga de 20 con cuatro núcleos puede significar que la CPU está ardiendo o que un soporte de almacenamiento se ha atascado. La segunda: el valor de un minuto no sirve para avisos, porque cualquier tarea de backup lo dispara un momento. Usa la media de 15 minutos y fija el umbral en relación con el número de núcleos.

Si tu kernel trae las estadísticas de presión, resultan más expresivas, porque separan CPU, entrada y salida y memoria. No están disponibles en todas partes:

test -d /proc/pressure && cat /proc/pressure/io || echo "sin estadísticas de presión en este kernel"

Servicios

systemctl is-system-running
systemctl --failed --no-pager
systemctl is-active nginx

systemctl is-system-running es la comprobación global más corta que sirve para algo. Devuelve running cuando no hay ni una sola unidad en estado de fallo, y degraded en cuanto hay una. El código de retorno es, en consecuencia, 0 o distinto de 0.

Dos trampas. El estado degraded se mantiene hasta que lo restableces tras la reparación con systemctl reset-failed; si no, una única tarea fallida mantiene vivo el aviso durante semanas. Y al comprobar servicios sueltos, los sistemas de referencia se diferencian: en Ubuntu 24.04, SSH arranca por activación de socket, y ahí ssh.service figura como inactive en reposo aunque SSH sea perfectamente accesible. Quien vigile ahí ssh.service tendrá una falsa alarma permanente. En Ubuntu 24.04 hay que vigilar ssh.socket, mientras que en Debian 12, Debian 13 y Ubuntu 22.04 vale ssh.service.

Caducidad del certificado

openssl x509 -enddate -noout -in /etc/letsencrypt/live/example.com/fullchain.pem
openssl x509 -checkend 1814400 -noout -in /etc/letsencrypt/live/example.com/fullchain.pem

El segundo comando es el interesante. -checkend espera un número de segundos, y 1814400 son 21 días. Si el certificado caduca dentro de ese plazo, el comando muestra Certificate will expire y devuelve el código de retorno 1; en caso contrario, Certificate will not expire y 0. /etc/letsencrypt/live y /etc/letsencrypt/archive solo son legibles por root.

La comprobación tiene un hueco que muchas guías se callan: examina el archivo del disco, no el certificado que entrega tu servidor web. Si la renovación se ejecuta pero falla el reload del servidor web, el archivo es nuevo y la clave entregada es la vieja. La comprobación del archivo no dice nada mientras los visitantes ya ven un aviso de certificado. Solo la mirada desde fuera atrapa este caso:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate

-servername no es opcional en cuanto hay varios certificados sobre una misma dirección IP. Sin ese añadido recibes el certificado por defecto del servidor y compruebas el dominio equivocado.

El script de comprobación

Todas las comprobaciones juntas dan un script que no hace más que leer, comparar y avisar cuando algo falla. Necesita curl y, para la vía del webhook, jq. En instalaciones mínimas de Debian faltan los dos:

apt update
apt install -y curl jq
cat > /usr/local/sbin/kh-monitor <<'EOF'
#!/bin/bash
set -u

DISK_WARN="${DISK_WARN:-85}"
INODE_WARN="${INODE_WARN:-85}"
MEM_MIN_MB="${MEM_MIN_MB:-200}"
LOAD_FACTOR="${LOAD_FACTOR:-2}"
CERT_DAYS="${CERT_DAYS:-21}"
UNITS="${UNITS:-ssh nginx}"
STATE_DIR="${STATE_DIRECTORY:-/var/lib/kh-monitor}"

problems=""
add() { problems+="- ${1}"$'\n'; }

notify() {
  printf '%s | %s\n' "$1" "$(printf '%s' "$2" | tr '\n' ' ')"
  if [ -n "${WEBHOOK_URL:-}" ]; then
    printf '%s\n%s' "$1" "$2" | jq -Rs '{text: .}' \
      | curl -fsS -m 10 -o /dev/null -H 'Content-Type: application/json' \
             --data-binary @- "$WEBHOOK_URL"
  fi
  if [ -n "${MAILTO:-}" ]; then
    printf '%s\n' "$2" | mail -s "$1" "$MAILTO"
  fi
}

while read -r pcent target; do
  pcent="${pcent%\%}"
  case "$pcent" in ''|*[!0-9]*) continue ;; esac
  [ "$pcent" -ge "$DISK_WARN" ] && add "Disco ${target} al ${pcent} por ciento de uso"
done < <(df --output=pcent,target -x tmpfs -x devtmpfs -x squashfs -x overlay | tail -n +2)

while read -r ipcent target; do
  ipcent="${ipcent%\%}"
  case "$ipcent" in ''|*[!0-9]*) continue ;; esac
  [ "$ipcent" -ge "$INODE_WARN" ] && add "Inodos en ${target} al ${ipcent} por ciento de uso"
done < <(df --output=ipcent,target -x tmpfs -x devtmpfs -x squashfs -x overlay | tail -n +2)

mem_avail=$(awk '/^MemAvailable:/ { printf "%d", $2 / 1024 }' /proc/meminfo)
[ "${mem_avail:-0}" -lt "$MEM_MIN_MB" ] && add "solo ${mem_avail} MB de RAM disponible"

cores=$(nproc)
load15=$(awk '{ print $3 }' /proc/loadavg)
awk -v l="$load15" -v c="$cores" -v f="$LOAD_FACTOR" 'BEGIN { exit !(l > c * f) }' \
  && add "Carga media de 15 minutos ${load15} con ${cores} núcleos"

sysstate=$(systemctl is-system-running)
[ "$sysstate" = "running" ] || add "systemd informa del estado ${sysstate}"

for unit in $UNITS; do
  systemctl is-active --quiet "$unit" || add "El servicio ${unit} está $(systemctl is-active "$unit")"
done

for cert in /etc/letsencrypt/live/*/fullchain.pem; do
  [ -r "$cert" ] || continue
  openssl x509 -checkend $(( CERT_DAYS * 86400 )) -noout -in "$cert" >/dev/null 2>&1 \
    || add "El certificado ${cert} caduca en menos de ${CERT_DAYS} días"
done

mkdir -p "$STATE_DIR"
now=$(printf '%s' "$problems" | sha256sum | cut -d' ' -f1)
before=$(cat "${STATE_DIR}/last" 2>/dev/null || true)
printf '%s' "$now" > "${STATE_DIR}/last"

if [ -z "$problems" ]; then
  [ -n "${HEARTBEAT_URL:-}" ] && curl -fsS -m 10 -o /dev/null "$HEARTBEAT_URL"
  [ -n "$before" ] && [ "$now" != "$before" ] \
    && notify "Todo en orden $(hostname -s)" "Todas las comprobaciones vuelven a estar correctas."
  exit 0
fi

[ "$now" = "$before" ] && exit 0
notify "Aviso $(hostname -s)" "$problems"
EOF

Hay cuatro puntos que merecen explicación.

  • Los bucles leen de < <( ... ), no de una pipe. Una pipe traslada el bucle a una subshell, y los mensajes recogidos allí habrían desaparecido después del done. El fallo es traicionero, porque el script se ejecuta sin errores y simplemente no avisa nunca de nada.
  • Los umbrales se leen del entorno. Puedes sobrescribir cada límite para una sola llamada. En eso se basa la prueba de aviso que viene más abajo.
  • El estado se guarda como suma de comprobación. Solo se avisa cuando la lista de problemas ha cambiado. Si no, un disco lleno te manda el mismo mensaje cada diez minutos y acabas apagando la vigilancia a los dos días.
  • El bucle de certificados se queda vacío cuando no existe ningún directorio de Let's Encrypt. El patrón queda sin expandir, [ -r "$cert" ] falla y la iteración se salta.

Comprueba ahora, antes de que systemd entre en juego:

chmod 700 /usr/local/sbin/kh-monitor
bash -n /usr/local/sbin/kh-monitor && echo "sintaxis correcta"
/usr/local/sbin/kh-monitor; echo "Código de salida $?"

En un servidor sano, el tercer comando no muestra nada aparte de Código de salida 0. Si ves un mensaje, o bien hay algo que no va bien, o bien un umbral no encaja, por ejemplo porque en UNITS figura un servicio que aquí no existe.

El timer de systemd

Un cron job también valdría. Pero un timer tiene cuatro ventajas concretas: no arranca una segunda instancia mientras la primera sigue corriendo, recupera una ejecución perdida tras un reinicio, su salida acaba en el journal y se apaga con un solo comando. La unidad de servicio no necesita sección [Install], porque no la activa el arranque del sistema, sino el timer.

cat > /etc/systemd/system/kh-monitor.service <<'EOF'
[Unit]
Description=Comprobación breve del estado del servidor
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/kh-monitor
EnvironmentFile=-/etc/default/kh-monitor
StateDirectory=kh-monitor
SyslogIdentifier=kh-monitor
Nice=10
IOSchedulingClass=idle
EOF
cat > /etc/systemd/system/kh-monitor.timer <<'EOF'
[Unit]
Description=Ejecuta kh-monitor de forma periódica

[Timer]
OnCalendar=*:0/10
RandomizedDelaySec=60
Persistent=true

[Install]
WantedBy=timers.target
EOF

StateDirectory=kh-monitor crea /var/lib/kh-monitor con los permisos adecuados y define la variable STATE_DIRECTORY, de la que tira el script. El signo menos delante en EnvironmentFile=-/etc/default/kh-monitor significa que un archivo ausente no es un error. RandomizedDelaySec=60 reparte el momento de arranque y Persistent=true recupera al encender una ejecución perdida durante un apagado.

El timer activa por sí solo el servicio del mismo nombre, así que no hace falta una línea Unit=:

systemd-analyze verify /etc/systemd/system/kh-monitor.service
systemd-analyze calendar '*:0/10'
systemctl daemon-reload
systemctl start kh-monitor.service
systemctl enable --now kh-monitor.timer

Control del resultado:

systemctl list-timers kh-monitor.timer --no-pager
journalctl -u kh-monitor.service -n 20 --no-pager

La lista tiene que mostrar una línea con el próximo momento de ejecución. Si queda vacía, el timer no está activo. systemd-analyze calendar encuentra las erratas en la expresión temporal: la convierte a una forma normalizada e indica la próxima cita. Los detalles sobre archivos de unidad y sus fallos típicos están en Crear un servicio systemd.

La vía de notificación

Aquí es donde fracasan casi todas las vigilancias caseras. El emisor corre en el servidor que vigila, así que cae con él. Con eso avisa de todo de forma fiable menos del único caso que de verdad cuenta.

La respuesta se llama interruptor de hombre muerto: el servidor da señal de vida a un punto externo después de cada ejecución correcta y, si la señal no llega, es ese punto externo el que da la alarma. El script de arriba lo hace cuando HEARTBEAT_URL está definida. Una caída de red, un sistema de archivos colgado y un sistema reventado tienen el mismo aspecto desde fuera, y de los tres casos quieres enterarte.

Las credenciales van en un archivo propio, no en el script. Una dirección de webhook es un secreto: quien la tenga puede mandar mensajes en tu nombre:

cat > /etc/default/kh-monitor <<'EOF'
WEBHOOK_URL=https://ejemplo.example/hooks/xxxxxxxx
HEARTBEAT_URL=https://ejemplo.example/heartbeat/xxxxxxxx
UNITS="ssh nginx"
EOF
chmod 600 /etc/default/kh-monitor

Las comillas alrededor de UNITS importan: systemd se apañaría también sin ellas, pero en la prueba de más abajo el archivo lo lee la shell, y ahí nginx sin comillas se interpretaría como un comando. Anota solo unidades que existan en este sistema, es decir ssh.socket en lugar de ssh en Ubuntu 24.04.

Quien prefiera el correo necesita una vía de envío. Un servidor de correo completo queda sobredimensionado, basta con un simple reenviador:

apt install -y msmtp msmtp-mta bsd-mailx

Eso se configura en /etc/msmtprc con las credenciales de un buzón existente. El archivo contiene una contraseña y le corresponde un chmod 600; si no, msmtp se niega a funcionar con un aviso sobre los permisos del archivo. Dos limitaciones honestas: el correo enviado desde una dirección IP de servidor recién asignada acaba a menudo en la carpeta de spam o es rechazado, y un mensaje que solo ves la próxima vez que abras el buzón llega demasiado tarde en una caída. Para los avisos, la entrega push es la opción más práctica.

Disparar el aviso una vez

Este paso no es opcional. Fuerza un mensaje poniendo un umbral absurdo para una sola llamada:

set -a; . /etc/default/kh-monitor; set +a
DISK_WARN=0 /usr/local/sbin/kh-monitor
rm -f /var/lib/kh-monitor/last

El mensaje tiene que llegarte ahora de verdad, no quedarse solo en el journal. La tercera línea borra el estado guardado para que el aviso de prueba no silencie la siguiente ejecución real. Hay un efecto secundario buscado: si la entrega falla, kh-monitor.service termina con error y aparece en systemctl --failed. Una vía de notificación silenciosa sería el peor fallo imaginable en una vigilancia.

La vista desde fuera

El interruptor de hombre muerto te dice que el servidor vive. No te dice que tu web responda. Para eso hace falta una comprobación desde otra ubicación, con el mismo patrón de script y timer, solo que en un segundo host:

curl -fsS -m 10 -o /dev/null -w '%{http_code} %{time_total}\n' https://example.com/

Cuatro puntos deciden el valor de esta comprobación. Primero: comprueba el servicio real, no solo ICMP. Un servidor que responde al ping mientras el servidor web está colgado en un bucle infinito pasa por sano en una comprobación de ping. Segundo: -f hace que curl falle con los códigos de error HTTP, y sin ese modificador hasta una página de error cuenta como éxito. Tercero: avisa solo después de dos fallos seguidos, o cualquier microcorte de red te anunciará una caída. Cuarto: una llamada cada minuto desde la misma dirección puede acabar en un rate limit o ser tomada por un ataque por parte de un software de bloqueo, así que registra la dirección del host que comprueba como excepción.

Sin un segundo servidor queda la opción de un servicio de comprobación alojado. Las ofertas gratuitas suelen comprobar cada cinco minutos, así que te enteras de una caída con el retraso correspondiente. Para un servidor individual es suficiente, y es mejor que la alternativa, que es no enterarte en absoluto.

Errores frecuentes y soluciones

Failed to start kh-monitor.service: Unit kh-monitor.service not found.: después de crear o modificar una unidad falta systemctl daemon-reload. La segunda causa más habitual es un directorio equivocado; las unidades propias van en /etc/systemd/system/.

The unit files have no installation config: has llamado a systemctl enable kh-monitor.service en lugar de kh-monitor.timer. El servicio no tiene sección [Install] a propósito, lo que se activa es el timer.

code=exited, status=203/EXEC: systemd no ha podido ejecutar el archivo. O la ruta de ExecStart no es correcta, o falta el chmod 700, o el archivo se editó en Windows y lleva finales de línea con retorno de carro. Contra eso ayuda sed -i 's/\r$//' /usr/local/sbin/kh-monitor.

Syntax error: redirection unexpected: el script se ha arrancado con sh en lugar de bash. En Debian y Ubuntu, /bin/sh es la shell dash, y esa no conoce ni < <( ... ) ni += con cadenas. La primera línea tiene que ser #!/bin/bash.

bash: mail: command not found: no hay ningún programa de correo instalado. El comando mail viene, según el sistema, de bsd-mailx o de mailutils, y los dos se diferencian en sus modificadores. Quédate con -s para el asunto.

curl: (22) The requested URL returned error: 404: la dirección del webhook es incorrecta o se ha borrado en el punto externo. Sin -f, curl se habría tragado el fallo en silencio.

curl: (60) SSL certificate problem: certificate has expired: en la comprobación desde fuera no es un fallo de la herramienta, sino justo el hallazgo que buscabas. Contra tu propio webhook, ese mismo mensaje apunta a una hora incorrecta en el servidor que comprueba.

Certificate will expire: salida normal de openssl x509 -checkend con código de retorno 1. Comprueba si la renovación sigue en marcha y si el servidor web se recarga después.

Failed to parse calendar specification: la expresión detrás de OnCalendar= no es válida. Pruébala por separado con systemd-analyze calendar antes de que acabe en la unidad.

Warning: Stopping kh-monitor.service, but it can still be activated by: kh-monitor.timer: has parado el servicio en lugar del timer. El servicio solo corre unos segundos de todos modos; lo que hay que apagar es el timer.

Aviso en cada ejecución aunque no haya cambiado nada: el estado no se está guardando. Comprueba si StateDirectory=kh-monitor figura en la unidad y si /var/lib/kh-monitor/last existe y se puede escribir.

Ningún aviso aunque algo esté claramente roto: dispara el mensaje forzado de más arriba. Si ese tampoco llega, el problema está en la vía de entrega, no en las comprobaciones.

Diferencias entre los cuatro sistemas

SistemaUnidad SSH que hay que vigilarPuntos de montaje squashfsDónde acaban los mensajes
Debian 13 (trixie)ssh.service, algunas imágenes usan ssh.socketpor lo general ningunosolo el journal, rsyslog falta en las instalaciones mínimas
Debian 12 (bookworm)ssh.servicepor lo general ningunojournal, rsyslog según la variante de instalación
Ubuntu 24.04 LTSssh.socketcasi siempre presentes, hay que excluirlosjournal y rsyslog
Ubuntu 22.04 LTSssh.servicecasi siempre presentes, hay que excluirlosjournal y rsyslog

En los cuatro sistemas coincide lo siguiente: systemd-analyze, StateDirectory= y RandomizedDelaySec= están disponibles, y el script y los archivos de unidad funcionan sin cambios.

Cuándo compensa la caja de herramientas grande

Lo que acabas de montar tiene límites claros. No guarda histórico, así que no puedes mirar si el consumo de memoria lleva tres semanas subiendo. No conoce la correlación entre varios hosts. Y no tiene ni escalado ni reglas de guardia ni forma de silenciar un aviso conocido durante dos horas.

Justo esos puntos responden a la pregunta de cuándo dar el salto. Montar métricas y dashboard compensa en cuanto se cumple uno de ellos:

  • Gestionas más de un puñado de servidores y quieres verlos unos junto a otros.
  • Necesitas histórico y tendencias, por ejemplo para planificar capacidad o para responder con cifras a una queja por lentitud.
  • Varias personas se reparten la guardia, así que hacen falta niveles de escalado y silenciado.
  • Tienes que demostrar la disponibilidad ante terceros.

Si no se cumple ninguno, para un servidor individual el montaje suele ser un mal negocio. El recolector, la base de datos, el dashboard y los exportadores ocupan juntos varios cientos de megabytes de RAM en la misma máquina cuya memoria libre deben vigilar. A eso se suman otro puerto abierto y un segundo software que hay que actualizar. El punto decisivo no cambia: si el recolector corre en el mismo servidor, no avisa de la caída de esa máquina más que un script. Al dar el paso, el recolector va a otro host, y el exportador se ata a 127.0.0.1 o queda limitado por firewall a la dirección de aquel.

El camino intermedio funciona bien: el timer y el script se quedan, porque cubren el caso de alarma, y el montaje de métricas se añade cuando necesites histórico. Las dos cosas no se excluyen.

Desmontaje

Si quieres quitarte el método de encima, son cinco líneas:

systemctl disable --now kh-monitor.timer
rm -f /etc/systemd/system/kh-monitor.timer /etc/systemd/system/kh-monitor.service
rm -f /usr/local/sbin/kh-monitor /etc/default/kh-monitor
rm -rf /var/lib/kh-monitor
systemctl daemon-reload

La comprobación final

Seis comprobaciones que muestran el estado real y no el deseado:

  1. systemctl list-timers kh-monitor.timer --no-pager indica un próximo momento de ejecución.
  2. journalctl -u kh-monitor.service --since "1 hour ago" --no-pager muestra ejecuciones al intervalo esperado.
  3. Un aviso forzado mediante DISK_WARN=0 te llega a ti, no solo al journal.
  4. Después de un reboot, el timer sigue funcionando sin que tengas que hacer nada.
  5. El interruptor de hombre muerto salta: para el timer y espera a ver si el punto externo da la alarma.
  6. systemctl --failed --no-pager no lista nada, y en particular no kh-monitor.service.

El punto cinco es el más incómodo y el más importante. Una vigilancia cuyo caso de alarma no se ha dado nunca es una suposición. Solo cuando has provocado la caída a propósito y has recibido el mensaje queda demostrado que la cadena que va del servidor a tu teléfono está completa.

Preguntas frecuentes

¿Necesito de verdad un servidor de métricas con dashboard para un solo servidor root?
En la mayoría de los casos, no. El recolector, la base de datos, el dashboard y los exportadores ocupan juntos con facilidad varios cientos de megabytes de RAM en la misma máquina cuya memoria libre deben vigilar, y traen consigo otro puerto abierto y un segundo software que hay que actualizar. Un script de comprobación con timer de systemd cubre por completo el caso de alarma. El montaje grande tiene sentido en cuanto quieras ver varios servidores unos junto a otros, necesites histórico para planificar capacidad, varias personas se repartan la guardia o tengas que demostrar la disponibilidad ante terceros.
¿Por qué un timer de systemd y no un cron job?
Las dos cosas funcionan. El timer tiene cuatro ventajas prácticas: no arranca una segunda instancia mientras la primera sigue corriendo, con Persistent=true recupera al encender una ejecución perdida durante un apagado, su salida acaba automáticamente en el journal gracias a SyslogIdentifier y se apaga con un solo comando, systemctl disable --now kh-monitor.timer. Lo que se activa siempre es el timer, no el servicio: la unidad de servicio no tiene sección [Install] a propósito.
Mi vigilancia avisa sin parar de un disco lleno aunque queda espacio de sobra, ¿a qué se debe?
Casi siempre a los puntos de montaje de snap. En Ubuntu 22.04 y 24.04, los paquetes snap se montan como imágenes squashfs de solo lectura, y esas están por naturaleza permanentemente al 100 por ciento. Exclúyelos, es decir df --output=pcent,target -x tmpfs -x devtmpfs -x squashfs -x overlay. Lo mismo vale para los puntos de montaje overlay de Docker. Segunda causa posible: en ext4 viene reservado de fábrica un cinco por ciento para root, por lo que df puede indicar ya el 100 por ciento mientras root todavía puede escribir.
¿Cómo me entero de que el servidor se ha caído del todo?
No a través de un script en ese mismo servidor, porque cae con él. Para eso hay dos caminos que se complementan. El interruptor de hombre muerto: el servidor da señal de vida a un punto externo después de cada ejecución correcta y, si la señal no llega, es ese punto externo el que da la alarma. Y la comprobación desde fuera: un segundo host o un servicio de comprobación alojado que consulte el servicio real, no solo ICMP. Los servicios de comprobación gratuitos suelen trabajar en intervalos de cinco minutos, así que te enteras de una caída con el retraso correspondiente.
¿Qué unidad SSH tengo que vigilar?
Eso cambia según la distribución. En Ubuntu 24.04, SSH arranca por activación de socket, y ahí ssh.service figura como inactive en reposo aunque SSH sea perfectamente accesible. Quien vigile ahí ssh.service tendrá una falsa alarma permanente; lo que hay que vigilar es ssh.socket. En Debian 12, Debian 13 y Ubuntu 22.04 pasa al revés, ahí vale ssh.service. Algunas imágenes concretas de Debian 13 llevan también ssh.socket activo, así que compruébalo con systemctl is-enabled ssh.socket.
¿Cómo evito recibir el mismo aviso cada diez minutos?
Con un archivo de estado. El script forma una suma de comprobación a partir de la lista de problemas encontrados, la guarda en /var/lib/kh-monitor/last y solo avisa cuando esa suma ha cambiado respecto a la ejecución anterior. Si un problema desaparece, llega una vez el mensaje de que todo vuelve a estar en orden. Si aun así recibes un mensaje en cada ejecución, es que falta en la unidad la línea StateDirectory=kh-monitor, o el archivo no se puede escribir.
El certificado del disco es válido y aun así los visitantes ven un aviso, ¿cómo puede ser?
Porque la comprobación del archivo y el certificado entregado son dos cosas distintas. Si la renovación automática se ejecuta pero falla el reload del servidor web, el archivo es nuevo y la clave entregada es la vieja. openssl x509 -checkend no dice nada entonces. Por eso comprueba además desde fuera con openssl s_client -connect example.com:443 -servername example.com. El añadido -servername no es opcional en cuanto hay varios certificados sobre una misma dirección IP.
¿Cómo apago rápido la vigilancia si me molesta?
Con systemctl disable --now kh-monitor.timer, que detiene el timer de inmediato e impide que vuelva en el siguiente arranque. Como freno de emergencia, systemctl mask kh-monitor.service impide además cualquier arranque a mano, y se revierte con systemctl unmask. El método se quita del todo borrando los dos archivos de unidad, el script de /usr/local/sbin/, el archivo /etc/default/kh-monitor y el directorio /var/lib/kh-monitor, seguido de systemctl daemon-reload. La configuración existente no se toca, porque solo se han creado archivos nuevos.

Monitorización systemd Linux Debian Ubuntu Servidor root Supervisión de servidores Bash