Pequeños hábitos de Linux que evitan grandes problemas en producción

La experiencia administrando Linux no se mide únicamente por cuántos comandos se conocen. En servidores reales suele importar más el orden en el que se utilizan, qué se comprueba antes de modificar algo y qué evidencias se conservan cuando aparece una incidencia. Hábitos de apenas unos segundos pueden separar un diagnóstico rápido de una hora de pruebas a ciegas, y también evitar que una intervención apresurada destruya precisamente las pistas necesarias para encontrar la causa.

Las claves de los buenos hábitos Linux en 30 segundos

  • Antes de reiniciar un servicio conviene capturar su estado, logs, sockets y recursos disponibles.
  • journalctl resulta mucho más útil cuando se filtra por servicio, arranque, prioridad o intervalo temporal.
  • Para almacenamiento, findmnt y lsblk suelen aportar más contexto que limitarse a mirar df.
  • En scripts no basta con set -e: conviene entender los códigos de salida, las tuberías y pipefail.
  • Comparar cambios recientes, guardar evidencias e introducir comprobaciones previas reduce muchos errores operativos.

No hay nada especialmente sofisticado en estas prácticas. Precisamente por eso funcionan. No obligan a cambiar de distribución, instalar una plataforma de observabilidad ni aprender otro lenguaje. Se incorporan a comandos que un administrador ya ejecuta todos los días.

El cambio está en pasar de una terminal reactiva, donde se prueba algo hasta que parece funcionar, a una forma de trabajar en la que primero se observa, acota, verifica y solo después se modifica.

1. Leer el sistema antes de tocarlo

Ante un servicio caído, uno de los primeros impulsos sigue siendo:

systemctl restart nginx

Puede resolver el síntoma.

También puede borrar parte del estado que explicaba el problema, crear nuevos mensajes de log y cambiar completamente la escena antes de haberla observado.

Un orden más útil sería:

systemctl status nginx
journalctl -u nginx --since "-15 min"
ss -lntp
df -h
free -hLenguaje del código: JavaScript (javascript)

systemctl status muestra el estado actual de la unidad y las últimas entradas relevantes del journal. journalctl permite después ampliar el intervalo exacto que interesa. ss confirma qué sockets están realmente escuchando.

Solo entonces tiene sentido decidir si reiniciar.

El principio parece trivial, pero evita una cantidad considerable de diagnósticos perdidos: capturar primero, intervenir después.

2. Preguntar siempre qué cambió

Muchos incidentes aparentemente misteriosos tienen una causa bastante poco misteriosa:

  • una actualización;
  • un despliegue;
  • una modificación de configuración;
  • un nuevo certificado;
  • un cambio DNS;
  • una regla de firewall;
  • un kernel nuevo;
  • un filesystem que se remontó de otra manera.

Por eso una de las primeras preguntas debería ser:

¿Qué ha cambiado desde la última vez que esto funcionaba?

Si la configuración está versionada:

git status
git diff
git log --since="2 days ago" --onelineLenguaje del código: JavaScript (javascript)

En Debian y Ubuntu pueden revisarse paquetes recientes mediante los logs de APT y dpkg; en distribuciones RPM existen historiales equivalentes en sus gestores de paquetes.

En sistemas administrados con automatización, el historial de Ansible, CI/CD o la plataforma de despliegue puede ser todavía más valioso.

Investigar el cambio reduce mucho el espacio de búsqueda. Es más eficiente que empezar por una teoría compleja sobre memoria, red o kernel sin ninguna evidencia que la sostenga.

3. Aprender a filtrar journalctl, no solo a ejecutarlo

Ejecutar:

journalctl -xe

puede generar tanta información que el problema quede enterrado dentro del ruido.

El journal de systemd permite realizar consultas bastante más concretas.

Solo un servicio:

journalctl -u nginx

Durante los últimos 20 minutos:

journalctl -u nginx --since "-20 min"Lenguaje del código: JavaScript (javascript)

Solo el arranque actual:

journalctl -b

El arranque anterior:

journalctl -b -1

Mensajes de error o más graves:

journalctl -p err -b

Solo kernel:

journalctl -k -b

Buscar un patrón:

journalctl -u nginx -g "timeout"Lenguaje del código: JavaScript (javascript)

La posibilidad de consultar el arranque anterior es especialmente útil cuando una máquina acaba de reiniciarse. En vez de perder el rastro del incidente, puede revisarse qué estaba ocurriendo inmediatamente antes.

La costumbre importante no es «mirar los logs». Es mirar los logs correctos para la ventana temporal correcta.

4. Mirar los servicios fallidos como parte de cualquier revisión

Un comando pequeño que merece ejecutarse mucho más es:

systemctl --failed

Permite comprobar rápidamente si existen unidades que han terminado en estado failed.

Puede revelar problemas que todavía no han provocado una alarma evidente: un montaje que no llegó a levantarse, una tarea auxiliar rota o un servicio que falló durante el arranque pero cuya ausencia todavía no ha sido detectada por los usuarios.

Además, systemd conserva el estado fallido para permitir su inspección hasta que la unidad se reinicia, se detiene o se limpia explícitamente.

Por eso tampoco conviene ejecutar automáticamente:

systemctl reset-failed

antes de investigar.

Limpiar el estado sin haberlo observado es otra forma de borrar una pista.

5. No confiar únicamente en df -h para investigar discos

df -h responde muy bien a una pregunta: cuánto espacio está utilizado en los sistemas de archivos montados.

Pero un problema de almacenamiento puede estar en otra capa.

Conviene incorporar:

lsblk

para entender dispositivos de bloque, particiones y relaciones entre ellos, y:

findmnt

para inspeccionar los sistemas de archivos montados.

Cuando interesa saber qué filesystem contiene una ruta concreta:

findmnt --target /var/lib/dockerLenguaje del código: JavaScript (javascript)

Esto resulta mucho más preciso que intentar deducirlo visualmente entre decenas de montajes.

En máquinas con LVM, múltiples discos, bind mounts, contenedores, NFS o volúmenes cloud, distinguir dispositivo, filesystem y punto de montaje evita bastantes errores.

También merece la pena recordar que los nombres /dev/sda, /dev/sdb y similares pueden variar con cambios de hardware. Para configuraciones persistentes suele ser preferible trabajar con UUID o LABEL cuando corresponde.

6. Confirmar qué está escuchando realmente

Cuando una aplicación afirma que «el puerto está abierto», la terminal puede comprobarlo.

Un comando particularmente útil es:

ss -lntp

Permite ver sockets TCP en escucha y, cuando existen permisos suficientes, los procesos asociados.

Para UDP:

ss -lunp

Y para revisar conexiones TCP activas:

ss -tnp

Es una comprobación más fiable que asumir que una aplicación escucha simplemente porque su configuración dice que debería hacerlo.

Si nginx debería estar en :443 pero ss no encuentra nada, el problema está antes de la red externa.

Si está escuchando únicamente en:

127.0.0.1:443Lenguaje del código: CSS (css)

cuando debía hacerlo sobre una dirección externa, ya aparece una pista bastante concreta.

Una buena costumbre de sysadmin consiste precisamente en verificar estado efectivo, no solo configuración declarada.

7. Diferenciar una foto de una tendencia

top, free y df enseñan qué está ocurriendo en ese instante.

Los problemas de rendimiento no siempre respetan ese instante.

Para observar comportamiento durante varios segundos:

vmstat 1

Puede mostrar procesos ejecutables, memoria, swap, actividad de bloques y utilización de CPU a intervalos regulares.

Para I/O, si está disponible sysstat:

iostat -xz 1

Y sar resulta especialmente útil cuando el sistema ya está recogiendo históricos.

El matiz con vmstat es importante: su primera línea refleja promedios acumulados desde el arranque; las posteriores corresponden al intervalo indicado.

No interpretar esa diferencia puede llevar a conclusiones erróneas.

Un valor de CPU del 95 % durante un segundo no describe necesariamente un problema. Un patrón de saturación que reaparece cada cinco minutos sí merece otra atención.

8. Comprobar el kernel cuando el problema parece inexplicable

No todos los fallos de una aplicación nacen en la aplicación.

Si aparecen:

  • errores de I/O;
  • dispositivos que desaparecen;
  • interfaces de red que reinician;
  • procesos terminados inesperadamente;
  • problemas con filesystem;
  • presión de memoria;

conviene mirar los mensajes del kernel.

Una forma actual y cómoda es:

journalctl -k -b

También puede filtrarse:

journalctl -k -b -p warning

Un servicio que simplemente figura como «killed» puede esconder detrás una intervención del OOM killer. Un disco que parece lento puede estar generando errores de dispositivo. Una interfaz puede estar renegociando el enlace.

Los logs de aplicación explican lo que sabe la aplicación.

El kernel puede explicar lo que le ocurrió a la aplicación desde fuera.

9. Leer el código de salida antes de declarar que algo funcionó

En Bash, un código de salida 0 representa éxito y uno distinto de cero indica algún tipo de fallo.

El último código queda disponible en:

echo $?Lenguaje del código: PHP (php)

Pero en scripts suele ser mejor comprobar directamente la operación:

if rsync -a /data/ /backup/data/; then
    echo "Backup completed"
else
    echo "Backup failed" >&2
    exit 1
fiLenguaje del código: PHP (php)

Esto resulta más claro que ejecutar otro comando y consultar $? después.

También conviene recordar algunos códigos habituales de Bash: 127 suele indicar que el comando no se encontró y 126 que se encontró pero no pudo ejecutarse.

La lección es sencilla: una automatización que termina no es necesariamente una automatización que terminó correctamente.

10. set -e ayuda, pero no es un sistema de manejo de errores

Es habitual encontrar este consejo:

set -eLenguaje del código: JavaScript (javascript)

La intención es buena: detener el script si un comando falla.

El problema es que Bash tiene excepciones. -e no actúa igual dentro de condiciones, listas && y ||, determinadas tuberías y otros contextos.

Para scripts pequeños suele encontrarse:

set -Eeuo pipefailLenguaje del código: JavaScript (javascript)

-u ayuda a detectar variables no definidas y pipefail evita que una tubería se considere correcta simplemente porque su último comando terminó bien.

Por ejemplo:

grep "important" missing-file | sortLenguaje del código: JavaScript (javascript)

sin pipefail puede devolver el estado de sort, aunque grep haya fallado.

Con:

set -o pipefailLenguaje del código: JavaScript (javascript)

el fallo de la tubería puede propagarse correctamente.

Aun así, estas opciones no sustituyen comprobaciones explícitas cuando un error requiere una respuesta concreta.

Un script de backup debería saber distinguir entre un fallo recuperable, un destino sin montar y una copia incompleta. Abandonar simplemente ante cualquier código distinto de cero puede no ser suficiente.

11. No dar por hecho el entorno de cron o systemd

El clásico «en mi terminal funciona» aparece mucho en automatización.

Una sesión interactiva puede tener:

  • un PATH personalizado;
  • variables de entorno;
  • claves cargadas;
  • un directorio de trabajo concreto;
  • aliases;
  • funciones de shell;
  • credenciales disponibles.

Cron o una unidad systemd pueden no tener nada de eso.

Utilizar rutas absolutas puede ayudar:

/usr/bin/python3 /opt/scripts/backup.py

pero una práctica todavía mejor es definir explícitamente el entorno que necesita el proceso.

Por ejemplo, en un script:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export PATHLenguaje del código: JavaScript (javascript)

Y nunca depender de que se ejecute desde un directorio determinado:

cd /opt/myapp || exit 1Lenguaje del código: PHP (php)

o utilizar directamente rutas completas.

La reproducibilidad importa más que la comodidad del shell interactivo.

12. Antes de una operación destructiva, ejecutar una versión que no destruya nada

Un hábito especialmente útil consiste en separar selección y acción.

Antes de:

find /backup -type f -mtime +30 -deleteLenguaje del código: JavaScript (javascript)

puede probarse:

find /backup -type f -mtime +30 -printLenguaje del código: PHP (php)

Primero se comprueba exactamente qué archivos coinciden.

Después se añade -delete.

Con rsync, antes de una sincronización con borrados:

rsync -a --delete --dry-run /source/ /destination/Lenguaje del código: JavaScript (javascript)

Y únicamente después:

rsync -a --delete /source/ /destination/Lenguaje del código: JavaScript (javascript)

Esta costumbre es especialmente valiosa porque muchos errores peligrosos no están en el comando destructivo.

Están en haber seleccionado los objetos equivocados.

La previsualización permite comprobar esa selección.

13. Guardar el estado antes de cambiar una configuración

Antes de editar una configuración crítica merece la pena conservar una copia o, mejor todavía, versionarla.

Por ejemplo:

cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.pre-change

Pero para servicios que incluyen validadores propios hay un hábito todavía mejor: probar la configuración antes de recargar.

En nginx:

nginx -t

Si es válida:

systemctl reload nginx

Cuando un servicio soporta reload, puede evitar la interrupción que provoca un restart.

El patrón general sería:

editar
→ validar
→ comparar
→ recargar
→ comprobar

y no:

editar
→ reiniciar
→ esperar

Un cambio pequeño en el procedimiento reduce bastante el riesgo.

14. Diferenciar reload de restart

No todos los cambios necesitan matar el proceso.

En servicios que implementan correctamente una recarga de configuración:

systemctl reload nginx

puede resultar preferible a:

systemctl restart nginx

restart detiene y vuelve a iniciar la unidad. reload pide al servicio que recargue su configuración sin necesariamente abandonar el proceso principal.

No todos los servicios soportan reload, y su semántica depende de cada daemon, por lo que hay que comprobarlo.

Pero convertir restart en respuesta automática para cualquier cambio aumenta interrupciones innecesarias.

El hábito útil es preguntar primero:

¿Realmente necesito reiniciar el proceso?

15. Inspeccionar procesos antes de matarlos

Otro reflejo peligroso:

kill -9 PID

SIGKILL no permite que el proceso capture la señal ni limpie recursos antes de morir.

Normalmente es mejor empezar por una terminación convencional:

kill PID

que envía SIGTERM.

Antes incluso de eso:

ps -fp PID

y, según el caso:

cat /proc/PID/status

permiten comprobar qué proceso se está observando.

Hay ocasiones en las que SIGKILL es necesario. No debería ser el primer intento simplemente porque es el que «siempre funciona».

La administración madura de Linux tiene bastante que ver con esto: utilizar la mínima intervención necesaria.

16. Utilizar systemd-analyze cuando el problema está en el arranque

Cuando un servidor tarda demasiado en arrancar, mirar top después no explica lo sucedido.

systemd dispone de herramientas específicas:

systemd-analyze time

para ver los tiempos globales.

Después:

systemd-analyze blame

muestra unidades ordenadas por el tiempo que estuvieron inicializándose.

Y:

systemd-analyze critical-chain

permite observar la cadena crítica de dependencias.

Hay una advertencia importante: blame no debe interpretarse como una lista automática de culpables. Un servicio puede aparecer lento porque estaba esperando a otro recurso. La propia documentación de systemd avisa de esta limitación.

Por eso critical-chain suele completar mejor el diagnóstico.

El hábito aquí vuelve a ser el mismo: utilizar la herramienta que responde a la pregunta concreta en vez de medir cualquier cosa disponible.

17. No parsear alegremente la salida que estaba pensada para humanos

Muchos comandos Linux muestran una salida cómoda para leer, pero no garantizan que ese formato permanezca idéntico.

lsblk y findmnt, por ejemplo, advierten expresamente de que su salida predeterminada puede cambiar y recomiendan especificar columnas cuando se utilizan dentro de scripts.

En lugar de depender de posiciones visuales:

lsblk

una automatización puede solicitar exactamente lo que necesita:

lsblk -o NAME,TYPE,FSTYPE,SIZE,MOUNTPOINTS

Lo mismo ocurre con:

findmnt -o SOURCE,TARGET,FSTYPE,OPTIONS

Esto evita scripts que funcionan hasta que una actualización añade una columna, cambia un orden o modifica el formato.

Los humanos agradecen formatos bonitos.

Los scripts necesitan contratos explícitos.

18. Hacer un pequeño snapshot de diagnóstico antes de intervenir

Una práctica fácil de automatizar consiste en capturar el estado básico cuando aparece una incidencia.

Por ejemplo:

date
hostname
uptime
free -h
df -h
lsblk
systemctl --failed
ss -lntp
journalctl -p err -b --no-pager

No hace falta convertirlo en una suite de monitorización.

Un script puede guardar todo en un fichero con fecha:

/opt/tools/capture-state.sh > "/var/tmp/state-$(date +%Y%m%d-%H%M%S).log" 2>&1Lenguaje del código: JavaScript (javascript)

Así, aunque después haya que reiniciar un servicio o incluso la máquina, queda una fotografía previa.

Resulta especialmente útil durante incidencias donde varias personas realizan cambios en paralelo.

19. Automatizar la comprobación, no únicamente la reparación

Cuando se piensa en automatización se suele imaginar «arreglar algo automáticamente».

Pero una de las automatizaciones más valiosas es simplemente detectar que algo no es como debería.

Por ejemplo:

systemctl is-active --quiet nginx || echo "nginx is not active"Lenguaje del código: PHP (php)

o comprobar:

  • espacio libre;
  • certificados próximos a caducar;
  • backups recientes;
  • mounts esperados;
  • unidades fallidas;
  • listeners necesarios;
  • sincronización de hora;
  • estado de RAID.

La reparación automática puede convertir una condición inesperada en otra todavía más difícil de investigar.

Una comprobación automática, en cambio, puede avisar antes de que el problema alcance al usuario.

20. Mantener un diario de incidentes y comandos útiles

El hábito menos tecnológico puede terminar siendo uno de los más rentables.

Después de una incidencia merece la pena registrar:

  • síntoma inicial;
  • hora;
  • primera evidencia;
  • cambios recientes;
  • comandos utilizados;
  • causa raíz;
  • solución;
  • cómo detectar antes el mismo problema;
  • qué automatización evitaría repetirlo.

No hace falta construir una plataforma compleja. Un repositorio Git privado con Markdown puede ser suficiente.

Después de un año aparece algo más útil que una colección de notas: un manual de los fallos reales de esa infraestructura.

El buen administrador no depende únicamente de recordar cómo resolvió algo seis meses atrás.

Hace que el sistema lo recuerde por él.

Los comandos importan, pero el orden importa más

Dos administradores pueden conocer exactamente los mismos comandos y obtener resultados muy diferentes.

Uno ejecuta:

reiniciar
→ probar
→ cambiar
→ volver a probar

El otro trabaja así:

observar
→ delimitar
→ guardar evidencia
→ formular hipótesis
→ validar
→ cambiar lo mínimo
→ comprobar

La diferencia no está en saber más Linux.

Está en aplicar un procedimiento que reduce las posibilidades de destruir información, introducir nuevos problemas o confundir correlación con causa.

También explica por qué herramientas sencillas como journalctl, ss, findmnt, vmstat o systemctl --failed siguen siendo tan útiles incluso en infraestructuras que ya disponen de Prometheus, Grafana, OpenTelemetry y plataformas avanzadas de observabilidad.

Cuando una máquina está delante y algo no funciona, sigue siendo necesario saber interrogarla.

Los mejores hábitos terminan pareciendo aburridos: comprobar antes de borrar, validar antes de recargar, guardar antes de modificar y leer antes de reiniciar.

Precisamente por eso suelen funcionar tan bien en producción.

Preguntas frecuentes

¿Qué comandos conviene ejecutar primero ante una incidencia Linux?

Depende del síntoma, pero systemctl status, journalctl, systemctl --failed, ss, df, free, findmnt y vmstat ofrecen rápidamente información sobre servicios, logs, red, almacenamiento, memoria y carga. Lo importante es recoger evidencias antes de modificar el sistema.

¿Es recomendable utilizar set -e en scripts Bash?

Puede ser útil, pero no debe considerarse un mecanismo completo de gestión de errores. Bash aplica excepciones a -e; pipefail, comprobaciones explícitas y tratamiento específico de errores siguen siendo necesarios en scripts importantes.

¿Por qué utilizar findmnt si ya existe df?

Responden a preguntas distintas. df muestra utilización de sistemas de archivos, mientras findmnt permite identificar y consultar montajes, origen, destino, tipo y opciones de un filesystem.

¿Es mejor reiniciar o recargar un servicio?

Si el daemon soporta una recarga segura de configuración, reload puede evitar una interrupción completa. Pero depende del servicio. Antes de cualquiera de las dos operaciones conviene validar la configuración y comprobar el estado actual.

Fuentes:

  • systemd, documentación oficial de systemctl, journalctl y systemd-analyze.
  • GNU Bash Reference Manual, códigos de salida, set -e y pipefail.
  • util-linux, documentación de lsblk y findmnt.
  • iproute2, documentación de ss.
  • procps-ng, documentación de vmstat.

Suscríbete al boletín SysAdmin

Este es tu recurso para las últimas noticias y consejos sobre administración de sistemas, Linux, Windows, cloud computing, seguridad de la nube, etc. Lo enviamos 2 días a la semana.

¡Apúntate a nuestro newsletter!


– patrocinadores –

Noticias destacadas

– patrocinadores –

¡SUSCRÍBETE AL BOLETÍN
DE LOS SYSADMINS!

Scroll al inicio
×