Seguridad en un servidor Linux: las medidas por orden de impacto
Si solo vas a hacer tres cosas, haz estas: llaves SSH con contraseñas deshabilitadas, firewall restrictivo y actualizaciones de seguridad automáticas. Cubren la enorme mayoría de compromisos reales, que no son ataques dirigidos sino automatización buscando credenciales débiles y software sin parchear.
| # | Medida | Impacto | Esfuerzo | Prioridad |
|---|---|---|---|---|
| 1 | Autenticación por llave SSH, sin contraseñas | Muy alto | Bajo | Imprescindible |
| 2 | Firewall con política de denegar por defecto | Muy alto | Bajo | Imprescindible |
| 3 | Actualizaciones de seguridad automáticas | Muy alto | Muy bajo | Imprescindible |
| 4 | Deshabilitar el login directo de root | Alto | Muy bajo | Imprescindible |
| 5 | Backups automatizados y probados | Muy alto | Medio | Imprescindible |
| 6 | Fail2Ban | Medio | Bajo | Muy recomendable |
| 7 | Cerrar servicios que escuchan sin necesidad | Alto | Bajo | Muy recomendable |
| 8 | Restringir SSH a IPs conocidas | Alto | Bajo | Si tienes IP fija |
| 9 | Cambiar el puerto de SSH | Bajo (menos ruido) | Muy bajo | Opcional |
| 10 | Auditoría con auditd | Medio | Medio | Con datos sensibles |
| 11 | Detección de rootkits (RKHunter) | Bajo | Bajo | Complementario |
| 12 | Antivirus (ClamAV) | Bajo salvo casos | Medio | Solo si recibes archivos |
1. Mantén el sistema actualizado, y automatízalo
La mayoría de compromisos exitosos explotan vulnerabilidades ya conocidas y con parche disponible. Actualizar es la medida con mejor relación esfuerzo-beneficio que existe, y automatizarla elimina el factor humano de olvidarse.
En Debian y Ubuntu:
sudo apt update && sudo apt upgrade -y En AlmaLinux, Rocky Linux o RHEL 9 y 10, el gestor es dnf (yum sigue funcionando como alias, pero pertenece a CentOS 7, que llegó a fin de vida el 30 de junio de 2024):
sudo dnf upgrade -y Para automatizar solo las actualizaciones de seguridad en Debian y Ubuntu:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades Verifica que el servicio está funcionando de verdad, porque instalarlo no basta:
sudo unattended-upgrade --dry-run --debug
cat /var/log/unattended-upgrades/unattended-upgrades.log En las distribuciones Red Hat, el equivalente es dnf-automatic:
sudo dnf install dnf-automatic -y
sudo systemctl enable --now dnf-automatic.timer Una advertencia honesta: las actualizaciones automáticas pueden reiniciar servicios y, en configuraciones frágiles, romper algo a las tres de la mañana. Por eso conviene limitarlas a los repositorios de seguridad —que es el comportamiento por defecto de unattended-upgrades— y no activar el reinicio automático del servidor salvo que tengas monitoreo que te avise.
2. Endurece el acceso SSH
SSH es la puerta principal del servidor y el objetivo número uno de los ataques automatizados. Las tres medidas de esta sección, aplicadas juntas, hacen que la fuerza bruta deje de ser un vector viable.
2.1 Usa autenticación por llave SSH en lugar de contraseñas
Una llave SSH es inmune a la fuerza bruta: no hay contraseña que adivinar, y el espacio de claves es computacionalmente imposible de recorrer. Esta es la medida individual más importante de toda la guía.
Genera el par de llaves en tu máquina local, no en el servidor. El tipo recomendado en 2026 es Ed25519:
ssh-keygen -t ed25519 -C "[email protected]" Ed25519 ofrece una seguridad equivalente a RSA de 3072 bits o superior en una llave mucho más corta, se verifica más rápido y está diseñada para resistir ataques de canal lateral. RSA de 4096 bits (ssh-keygen -t rsa -b 4096) solo tiene sentido si necesitas compatibilidad con sistemas anteriores a 2014, cuando OpenSSH 6.5 incorporó Ed25519.
Cuando el asistente pida una frase de contraseña, pon una: protege la llave privada si alguien accede a tu equipo.
Copia la clave pública al servidor:
ssh-copy-id -i ~/.ssh/id_ed25519.pub usuario@ip_del_servidor Comprueba que puedes entrar con la llave en una segunda terminal antes de continuar. Solo entonces deshabilita las contraseñas:
sudo nano /etc/ssh/sshd_config PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes KbdInteractiveAuthentication no importa: sin él, algunas configuraciones siguen aceptando contraseñas por una vía alternativa aunque hayas desactivado PasswordAuthentication.
sudo systemctl restart ssh 2.2 Deshabilita el login directo de root
Bloquear el acceso directo de root obliga al atacante a acertar además el nombre de usuario, y deja rastro en los logs de sudo de todo lo que se ejecuta con privilegios. Crea primero tu usuario administrativo, o te quedarás fuera.
sudo adduser nombre_usuario
sudo usermod -aG sudo nombre_usuario # en Debian/Ubuntu
sudo usermod -aG wheel nombre_usuario # en AlmaLinux/Rocky Copia tu llave SSH a ese usuario, comprueba que entras con él, y solo después:
sudo nano /etc/ssh/sshd_config PermitRootLogin no sudo systemctl restart ssh 2.3 Cambia el puerto de SSH (opcional)
Mover SSH del puerto 22 no aporta seguridad real —un escaneo lo encuentra en segundos— pero elimina la mayor parte del ruido de bots en los logs. Trátalo como higiene operativa, nunca como sustituto de las llaves.
sudo nano /etc/ssh/sshd_config Port 2222 Abre el puerto nuevo en el firewall antes de reiniciar el servicio, o perderás el acceso:
sudo ufw allow 2222/tcp
sudo systemctl restart ssh Un detalle específico de Ubuntu 22.10 y posteriores, incluida la 24.04: SSH usa activación por socket, así que al cambiar la directiva Port hay que recargar systemd y reiniciar el socket, no solo el servicio:
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket Sin esos dos comandos, el archivo de configuración dice 2222 y el servidor sigue escuchando en el 22, lo que genera una confusión notable.
3. Configura un firewall
Un firewall con política de denegar por defecto reduce la superficie de ataque a exactamente los servicios que decidiste exponer. Todo lo que no abras explícitamente queda inaccesible, incluidos los servicios que instalarás sin darte cuenta el mes que viene.
3.1 UFW en Debian y Ubuntu
Permite SSH antes de activar el firewall. Siempre. UFW deniega todo el tráfico entrante por defecto, así que el orden inverso te deja fuera del servidor de inmediato.
sudo ufw allow 2222/tcp # o 'OpenSSH' si no cambiaste el puerto
sudo ufw allow http
sudo ufw allow https
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable
sudo ufw status numbered Tras activarlo, abre una segunda sesión SSH sin cerrar la primera para confirmar que sigues teniendo acceso.
3.2 Firewalld en AlmaLinux y Rocky Linux
Firewalld requiere --permanent para que las reglas sobrevivan a un reinicio, y --reload para aplicarlas. Olvidar cualquiera de las dos es el error más común con esta herramienta.
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-all Ampliamos ambas herramientas, incluido cómo recuperarte si te bloqueas, en la guía para configurar firewalls en Linux.
3.3 Restringe el acceso SSH a IPs concretas
Si administras siempre desde la misma IP fija, limitar SSH a ese origen elimina el 100% de los intentos de acceso desde internet. Es la medida de mayor impacto de esta sección, y también la que te deja fuera si tu IP cambia.
sudo ufw delete allow 2222/tcp
sudo ufw allow from 190.0.0.0/24 to any port 2222 proto tcp Antes de aplicarlo, confirma que tu IP es realmente fija con curl -4 ifconfig.me y comprueba días después si sigue igual. La mayoría de conexiones domésticas en Ecuador son dinámicas. Si la tuya lo es, deja SSH abierto con ufw limit y Fail2Ban, o monta una VPN.
3.4 Cierra los servicios que escuchan sin necesidad
Un puerto cerrado en el firewall sigue siendo un servicio accesible desde dentro del servidor; lo ideal es que ni siquiera escuche. Revisa qué hay realmente en marcha:
sudo ss -tulpn Presta atención a la columna de dirección local: 0.0.0.0:3306 significa que MySQL acepta conexiones desde cualquier red, mientras que 127.0.0.1:3306 significa que solo escucha localmente. Para bases de datos que solo usa la aplicación del mismo servidor, corrige el propio servicio en lugar de confiar en el firewall:
# En /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 127.0.0.1 4. Detección y bloqueo de ataques
Además de cerrar puertas, conviene tener algo que reaccione al comportamiento hostil que llega a las que siguen abiertas.
4.1 Fail2Ban: bloqueo automático de fuerza bruta
Fail2Ban lee los registros del sistema y bloquea con el firewall a las IPs que acumulan intentos fallidos. En Debian 12, Ubuntu 24.04 y posteriores requiere un ajuste que rompe la mayoría de configuraciones copiadas de tutoriales antiguos.
sudo apt install fail2ban python3-systemd -y Crea la configuración local, nunca edites jail.conf (se sobrescribe al actualizar):
sudo nano /etc/fail2ban/jail.local [DEFAULT]
bantime = 1h
bantime.increment = true
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 190.0.0.0/24
[sshd]
enabled = true
port = 2222
backend = systemd La línea clave es backend = systemd. Las guías antiguas indican logpath = /var/log/auth.log, pero ese archivo ya no existe en las distribuciones actuales: la actividad se registra en el journal de systemd. Con el logpath obsoleto, Fail2Ban no arranca o no bloquea nada mientras aparenta funcionar. El paquete python3-systemd es necesario para que ese backend pueda leer el journal.
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd La última orden debe mostrar el jail activo y el número de IPs bloqueadas. Si el conteo lleva días en cero en un servidor expuesto, algo está mal configurado. Tratamos la herramienta en profundidad, incluidos filtros personalizados, en la guía de Fail2Ban.
Un matiz de honestidad: si ya deshabilitaste la autenticación por contraseña, Fail2Ban aporta bastante menos, porque la fuerza bruta contra llaves no puede prosperar. Lo que sigue aportando es reducir el ruido en los logs y proteger otros servicios expuestos como el correo o los formularios de login de tus aplicaciones.
4.2 Mitigación básica de DDoS
Un script en el servidor no detiene un ataque DDoS volumétrico: cuando los paquetes llegan a tu servidor, ya consumieron tu ancho de banda. La mitigación real se hace aguas arriba, en la red del proveedor. Dicho esto, para floods pequeños de conexiones sí sirve limitar conexiones simultáneas por IP.
Con herramientas ya presentes en el sistema, sin instalar nada:
# Ver cuántas conexiones establecidas hay por IP
ss -tn state established | awk '{print $4}' | cut -d: -f1 | sort | uniq -c | sort -rn | head
# Limitar conexiones simultáneas al puerto 80 por IP con UFW
sudo ufw limit 80/tcp Existen scripts como DDoS Deflate, que automatizan ese conteo y bloqueo. Son útiles como red de seguridad, pero conviene saber que actúan después de que el tráfico ya llegó, y que un umbral mal ajustado bloquea proxies corporativos y buscadores. Si tu servicio necesita disponibilidad frente a ataques reales, la respuesta es protección DDoS a nivel de red, no un script local.
4.3 Detección de rootkits y malware
RKHunter y ClamAV cubren escenarios distintos y ninguno de los dos sustituye a las medidas anteriores. Instálalos si aportan a tu caso, no por completar una lista.
RKHunter compara archivos y configuraciones del sistema contra firmas conocidas de rootkits y backdoors:
sudo apt install rkhunter -y
sudo rkhunter --update
sudo rkhunter --propupd # línea base tras una instalación limpia
sudo rkhunter --checkall --skip-keypress --propupd es importante: registra el estado actual de los archivos como referencia. Sin esa línea base, el primer escaneo devuelve decenas de advertencias que no distinguen entre un cambio legítimo y una intrusión. Ejecútalo solo sobre un sistema recién instalado y del que te fíes.
ClamAV es un antivirus útil sobre todo si tu servidor recibe archivos de usuarios o gestiona correo, ya que detecta malware dirigido a Windows que solo está de paso por tu servidor:
sudo apt install clamav clamav-daemon -y
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam
sudo clamscan -r --infected /var/www Hay que detener el servicio freshclam antes de ejecutarlo a mano porque ambos compiten por el mismo archivo de bloqueo. Y ten presente el consumo: ClamAV carga sus firmas en memoria y necesita del orden de 1 GB de RAM disponible, lo que en un VPS pequeño es una porción considerable.
5. Monitoreo y auditoría
Sin visibilidad no hay seguridad: un servidor comprometido puede funcionar con normalidad durante semanas. El objetivo de esta capa es que un cambio anómalo deje rastro y alguien lo vea.
5.1 Logwatch: informes diarios por correo
Logwatch resume los logs del día en un correo legible, con intentos de acceso, errores y paquetes instalados. Es la forma más barata de enterarte de que algo cambió.
sudo apt install logwatch -y
sudo logwatch --output stdout --detail high --range today Para recibirlo a diario, edita /etc/cron.daily/00logwatch:
/usr/sbin/logwatch --output mail --mailto [email protected] --detail high Esto requiere que el servidor pueda enviar correo. Si no tienes un MTA configurado, el informe se genera y nadie lo lee, que es peor que no tenerlo: da falsa sensación de cobertura.
5.2 Auditd: registro de cambios en archivos críticos
Auditd registra a nivel de kernel quién tocó qué archivo y con qué proceso, lo que permite reconstruir lo ocurrido tras un incidente. Las reglas van en /etc/audit/rules.d/, no en audit.rules.
sudo apt install auditd audispd-plugins -y
sudo nano /etc/audit/rules.d/hardening.rules -w /etc/passwd -p wa -k identidad
-w /etc/shadow -p wa -k identidad
-w /etc/ssh/sshd_config -p wa -k config_ssh
-w /etc/sudoers -p wa -k escalada
-w /var/www -p wa -k contenido_web Dos correcciones frecuentes en las guías sobre auditd. La primera: editar directamente /etc/audit/audit.rules no sirve, porque ese archivo se regenera a partir de todo lo que haya en /etc/audit/rules.d/ y tus cambios se pierden. La segunda: systemctl restart auditd falla con el mensaje «Operation refused, unit auditd.service may be requested by dependency only», porque la unidad está protegida contra manipulación manual. Las formas correctas de aplicar las reglas son:
sudo augenrules --load
sudo auditctl -l # verificar que las reglas están cargadas Y para consultar el rastro de una clave concreta:
sudo ausearch -k config_ssh -i 6. Backups: la última línea de defensa
Ninguna medida de seguridad es infalible, y un backup reciente y probado es lo que separa un incidente de una pérdida total. El criterio de referencia es la regla 3-2-1: tres copias de los datos, en dos tipos de soporte distintos, con una de ellas fuera del servidor.
6.1 Backups automatizados con rsync y cron
Copiar a otra máquina evita el escenario en el que el servidor se pierde con sus backups dentro. Un backup en el mismo disco no protege contra el fallo de ese disco ni contra un ransomware que cifre todo el sistema de archivos.
rsync -avz --delete /var/www/ usuario@servidor-backup:/backups/web/ Programado a diario:
crontab -e 0 2 * * * rsync -avz --delete /var/www/ usuario@servidor-backup:/backups/web/ >> /var/log/backup.log 2>&1
15 2 * * * mysqldump -u root -p'clave' --single-transaction --all-databases | gzip > /backups/mysql_$(date +\%F).sql.gz Cuidado con --delete: replica también los borrados, así que si algo se elimina por error en el origen, desaparece del destino en la siguiente ejecución. Para protegerte de eso hacen falta copias con retención de varios días, no una única copia espejo. Y en cron, los signos de porcentaje deben ir escapados como \% o la línea se corta ahí.
6.2 Snapshots con LVM
Un snapshot de LVM congela el estado del volumen en un instante y permite volver atrás tras un cambio arriesgado. Es un punto de restauración local, no un backup: vive en el mismo disco y desaparece con él.
sudo lvcreate --size 5G --snapshot --name antes_de_actualizar /dev/vg0/root Reserva espacio suficiente: si el snapshot se llena con los cambios acumulados, se invalida solo y sin aviso.
6.3 Prueba la restauración
Un backup que nunca se ha restaurado es una suposición. Los fallos habituales —volcados SQL truncados, permisos perdidos, directorios excluidos sin querer— solo aparecen al intentar recuperar, normalmente en el peor momento.
# Verificar que un volcado comprimido no está corrupto
gunzip -t /backups/mysql_2026-08-30.sql.gz && echo "Archivo integro"
# Restaurar en una base de pruebas, nunca sobre la de producción
zcat /backups/mysql_2026-08-30.sql.gz | mysql -u root -p base_de_pruebas Hazlo al menos cada trimestre, en un servidor distinto del original, y anota cuánto tarda el proceso completo. Ese número es tu tiempo real de recuperación.
Checklist de las 12 medidas
| # | Medida | Comando de verificación | |
|---|---|---|---|
| 1 | Llaves SSH, contraseñas deshabilitadas | `sudo sshd -T \ | grep -i passwordauth` |
| 2 | Firewall activo con denegar por defecto | sudo ufw status verbose | |
| 3 | Actualizaciones automáticas funcionando | cat /var/log/unattended-upgrades/*.log | |
| 4 | Login de root deshabilitado | `sudo sshd -T \ | grep -i permitrootlogin` |
| 5 | Backups automatizados y restaurados | ls -lh /backups/ y prueba trimestral | |
| 6 | Fail2Ban activo con backend systemd | sudo fail2ban-client status sshd | |
| 7 | Sin servicios escuchando de más | sudo ss -tulpn | |
| 8 | SSH restringido a IPs conocidas | sudo ufw status numbered | |
| 9 | Puerto de SSH personalizado | `sudo ss -tulpn \ | grep sshd` |
| 10 | Auditoría de archivos críticos | sudo auditctl -l | |
| 11 | Línea base de RKHunter establecida | sudo rkhunter --checkall | |
| 12 | Antivirus, solo si recibes archivos | sudo systemctl status clamav-freshclam |
La seguridad de un servidor Linux no es una lista que se completa una vez, sino un proceso de mantenimiento y revisión. Si tuvieras que quedarte con cinco medidas de toda esta guía, serían: autenticación por llave SSH con contraseñas deshabilitadas, firewall con política de denegar por defecto, actualizaciones de seguridad automáticas y verificadas, login de root cerrado, y backups fuera del servidor que hayas restaurado al menos una vez. Todo lo demás refina esa base, y varias de las herramientas de las secciones finales solo tienen sentido si alguien va a leer lo que reportan: una alerta que nadie mira no es seguridad, es ruido. Revisa la checklist cada trimestre y presta atención especial a los tres puntos que más silenciosamente fallan: Fail2Ban configurado con el logpath obsoleto, actualizaciones automáticas instaladas pero inactivas, y backups que nunca se han probado. Si administras un VPS o un servidor dedicado y tienes dudas durante la implementación, nuestro equipo de soporte técnico está disponible 24/7 para ayudarte.
Hosting con LiteSpeed, NVMe y soporte 24/7 desde $3/mes.