Cómo evitar ejecutar comandos en el servidor equivocado

Haz que producción sea imposible de confundir: pon un prompt rojo en PS1 en cada servidor de producción y colorea también la barra de estado de tmux y la terminal. Después crea hábitos que detecten el descuido: haz primero un simulacro (dry run), lista un patrón glob antes de borrarlo, escribe "${DIR:?}" en los scripts y deja activado el pegado entre corchetes (bracketed paste). Esto reduce los errores. Nada de aquí los hace imposibles, así que las copias de seguridad siguen importando.

Actualizada el . El prompt, las protecciones de rm, los simulacros, los colores de la barra de tmux y el bracketed paste se ejecutaron en Debian 13 en un contenedor desechable (bash 5.2, GNU coreutils 9.7, tmux 3.5), por SSH desde macOS.

Un prompt rojo en producción

La mayoría de los errores de servidor equivocado ocurren porque dos terminales se ven iguales. El prompt es lo que lees justo antes de pulsar Intro, así que cámbialo ahí. Añade esto al final de ~/.bashrc en el servidor. Tiene que ir al final, porque el .bashrc de la distribución define PS1 antes y lo sobrescribiría:

PS1='\[\e[1;37;41m\] PRODUCTION \[\e[0m\] \u@\h:\w\$ '

Esto muestra PRODUCTION en blanco sobre rojo y después el usuario, el host y la carpeta habituales. Los \[ y \] indican a bash que los códigos de color no ocupan ancho, de modo que los comandos largos siguen ajustándose bien.

Añade la misma línea a /root/.bashrc: en nuestra prueba sudo -i mostró la etiqueta roja solo porque ese archivo también la tenía. Para staging, usa amarillo con \e[1;30;43m. Solo funciona en bash interactivo, así que otros shells necesitan su propio ajuste.

Terminal de iPhone con una etiqueta Production en el título, que muestra un diálogo que pregunta Run this on production? antes de un borrado recursivo forzado, con los botones Cancel y Run itTerminal de iPhone con una etiqueta Production en el título, que muestra un diálogo que pregunta Run this on production? antes de un borrado recursivo forzado, con los botones Cancel y Run it

Colorea la barra de tmux y la terminal

Si usas tmux en el servidor, colorea su barra de estado, en el ~/.tmux.conf de allí:

set -g status-style bg=red,fg=white,bold
set -g status-left " PRODUCTION "

Comprueba que se cargó con tmux show -g status-style.

En tu propia máquina, la mayoría de las aplicaciones de terminal pueden abrir un host con un perfil aparte. Dale a producción una ventana con fondo rojo oscuro. También puedes dejar que tu configuración de SSH ponga el color, en terminales que admiten la secuencia OSC 11:

Host prod-*
    PermitLocalCommand yes
    LocalCommand printf '\033]11;#400000\007'

El color no vuelve solo al original al cerrar sesión, y la compatibilidad varía, así que pruébalo primero en tu terminal.

Con muchos servidores, nombres claros y grupos ayudan tanto como los colores: consulta cómo gestionar muchos servidores SSH.

Borrar archivos con seguridad

rm de GNU ya rechaza el peor caso:

$ rm -rf /
rm: it is dangerous to operate recursively on '/'
rm: use --no-preserve-root to override this failsafe

Esto protege solo la / literal. En rm -rf /* el shell expande primero el asterisco, así que rm recibe /bin, /etc y el resto, y la comprobación no se aplica. Un espacio suelto en rm -rf /var/app /* lo provoca por accidente. Estos hábitos ayudan más:

  • Mira antes de borrar. Pon echo delante para ver en qué se expande un glob: echo rm -rf /tmp/app/*. Después quita el echo.
  • Une con &&, no con ;. Con cd /var/app/tmp && rm -rf ./*, si el cd falla, todo se detiene ahí. Con ; el borrado se ejecuta en la carpeta en la que estés.
  • Protege las variables en los scripts. rm -rf "${DIR:?}/" se detiene con un error cuando DIR está vacía, mientras que un simple "$DIR/" se convertiría en /. set -u al principio de un script también se detiene ante variables sin definir.
  • Mueve primero, borra después. Un mv a una carpeta de espera se puede deshacer. Un rm no.
  • Usa rm -I. Pregunta una vez antes de borrar más de tres archivos o de borrar de forma recursiva. Si no respondes nada, no se borra nada, como en nuestra prueba.
  • Usa --preserve-root=all. También rechaza una carpeta que esté en un sistema de archivos distinto del de su padre, así que rechazaría un disco montado: rm: skipping '/dev/shm', since it's on a different device.

Los dos últimos pueden ir en un alias en el servidor, alias rm='rm -I --preserve-root=all'. Los alias se aplican solo a shells interactivos, no a scripts ni a sudo rm, y estas opciones son exclusivas de GNU.

Simulacro primero

ComandoVista previa
rsyncrsync -an --delete --itemize-changes src/ dst/
findfind . -name '*.tmp' -print primero, y luego cambia -print por -delete
git cleangit clean -n
apt-getapt-get -s remove package

Con SQL, ejecuta primero BEGIN;, luego la sentencia, comprueba el número de filas y termina con COMMIT; o ROLLBACK;. Esto no cubre las sentencias que tu base de datos confirma por sí misma. MySQL lo hace con los cambios de tablas, por ejemplo.

Pegar varias líneas

En una terminal, un salto de línea en el texto pegado actúa como Intro, así que un pegado puede ejecutar comandos antes de que los leas. El bracketed paste lo soluciona. La terminal marca el texto pegado y el shell lo inserta sin ejecutar nada. Pegamos dos líneas echo en bash a través de tmux:

  • Con él activado, las dos líneas quedaron en el prompt y no se ejecutó nada hasta pulsar Intro.
  • Con él desactivado, la primera línea se ejecutó en cuanto se pegó.

Viene activado por defecto en el bash actual. Compruébalo con este comando en un shell interactivo:

bind -v | grep bracketed-paste

Si dice off, añade set enable-bracketed-paste on a ~/.inputrc. Solo ayuda donde el programa lo solicita. Si pegas en un programa que no lo hace, o en un shell antiguo, se ejecuta línea por línea.

Lo que esto no puede hacer

El color del prompt solo ayuda si lo miras. No protege un script, una tarea de cron ni un comando ejecutado con ssh server 'command', que nunca muestra un prompt. Los alias se pueden esquivar, y nada de esto detiene un error en los argumentos de un comando que querías ejecutar.

Así que mantén las protecciones mayores: copias de seguridad probadas, cuentas y claves separadas para producción, y el mínimo de sudo que necesite cada persona. Consulta sudo por SSH para reglas estrechas.

Preguntas

¿Cómo pongo en rojo el prompt de bash en un servidor de producción?

Define PS1 con un código de color de fondo rojo al final de ~/.bashrc en ese servidor, y en /root/.bashrc para sudo -i. Al final, para que el PS1 de la distribución no lo sobrescriba.

¿Sigue funcionando rm -rf / en Linux?

El rm de GNU rechaza la / literal salvo que añadas --no-preserve-root. No protege rm -rf /*, porque la shell expande antes el asterisco en todas las carpetas de primer nivel.

¿Cómo veo qué borrará un comando antes de ejecutarlo?

Pon echo delante para ver en qué se expande un patrón, o usa la opción de prueba: rsync -n, git clean -n, o find con -print antes de -delete.

Fuentes

Más en Proteger un servidor

Todas las guías