Saltar al contenido
Infrastructure 2024-12-28 18 min de lectura

Guía Completa para Implementar Seguridad en un Servidor Linux

Un servidor Linux recién desplegado, con su configuración por defecto, empieza a recibir escaneos automatizados en cuestión de minutos: bots que prueban credenciales contra SSH, buscan paneles de administración expuestos y sondean puertos abiertos las 24 horas. Implementar seguridad en un servidor Linux no requiere ser especialista en ciberseguridad; requiere aplicar, en el orden correcto, un conjunto acotado de medidas que reducen drásticamente la superficie de ataque. Esta guía las cubre todas —acceso SSH, firewall, detección de intrusos, auditoría y backups— con comandos verificados sobre Ubuntu 24.04 y las distribuciones Red Hat actuales, y señala explícitamente qué medidas rinden mucho y cuáles solo tienen sentido en escenarios concretos.

Guía Completa para Implementar Seguridad en un Servidor Linux
#Infrastructure#Linux#Seguridad#VPS
T
Equipo Terranode
Editorial

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.

#MedidaImpactoEsfuerzoPrioridad
1Autenticación por llave SSH, sin contraseñasMuy altoBajoImprescindible
2Firewall con política de denegar por defectoMuy altoBajoImprescindible
3Actualizaciones de seguridad automáticasMuy altoMuy bajoImprescindible
4Deshabilitar el login directo de rootAltoMuy bajoImprescindible
5Backups automatizados y probadosMuy altoMedioImprescindible
6Fail2BanMedioBajoMuy recomendable
7Cerrar servicios que escuchan sin necesidadAltoBajoMuy recomendable
8Restringir SSH a IPs conocidasAltoBajoSi tienes IP fija
9Cambiar el puerto de SSHBajo (menos ruido)Muy bajoOpcional
10Auditoría con auditdMedioMedioCon datos sensibles
11Detección de rootkits (RKHunter)BajoBajoComplementario
12Antivirus (ClamAV)Bajo salvo casosMedioSolo 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:

bash
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):

bash
sudo dnf upgrade -y

Para automatizar solo las actualizaciones de seguridad en Debian y Ubuntu:

bash
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:

bash
sudo unattended-upgrade --dry-run --debug
cat /var/log/unattended-upgrades/unattended-upgrades.log

En las distribuciones Red Hat, el equivalente es dnf-automatic:

bash
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:

bash
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:

bash
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:

bash
sudo nano /etc/ssh/sshd_config
text
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.

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

bash
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:

bash
sudo nano /etc/ssh/sshd_config
text
PermitRootLogin no
bash
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.

bash
sudo nano /etc/ssh/sshd_config
text
Port 2222

Abre el puerto nuevo en el firewall antes de reiniciar el servicio, o perderás el acceso:

bash
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:

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

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

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

bash
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:

bash
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:

ini
# 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.

bash
sudo apt install fail2ban python3-systemd -y

Crea la configuración local, nunca edites jail.conf (se sobrescribe al actualizar):

bash
sudo nano /etc/fail2ban/jail.local
ini
[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.

bash
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:

bash
# 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:

bash
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:

bash
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ó.

bash
sudo apt install logwatch -y
sudo logwatch --output stdout --detail high --range today

Para recibirlo a diario, edita /etc/cron.daily/00logwatch:

bash
/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.

bash
sudo apt install auditd audispd-plugins -y
sudo nano /etc/audit/rules.d/hardening.rules
text
-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:

bash
sudo augenrules --load
sudo auditctl -l          # verificar que las reglas están cargadas

Y para consultar el rastro de una clave concreta:

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

bash
rsync -avz --delete /var/www/ usuario@servidor-backup:/backups/web/

Programado a diario:

bash
crontab -e
text
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.

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

bash
# 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

#MedidaComando de verificación
1Llaves SSH, contraseñas deshabilitadas`sudo sshd -T \grep -i passwordauth`
2Firewall activo con denegar por defectosudo ufw status verbose
3Actualizaciones automáticas funcionandocat /var/log/unattended-upgrades/*.log
4Login de root deshabilitado`sudo sshd -T \grep -i permitrootlogin`
5Backups automatizados y restauradosls -lh /backups/ y prueba trimestral
6Fail2Ban activo con backend systemdsudo fail2ban-client status sshd
7Sin servicios escuchando de mássudo ss -tulpn
8SSH restringido a IPs conocidassudo ufw status numbered
9Puerto de SSH personalizado`sudo ss -tulpn \grep sshd`
10Auditoría de archivos críticossudo auditctl -l
11Línea base de RKHunter establecidasudo rkhunter --checkall
12Antivirus, solo si recibes archivossudo 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.

¿Listo para llevar tu sitio al siguiente nivel?

Hosting con LiteSpeed, NVMe y soporte 24/7 desde $3/mes.

Ver planes de hosting

Preguntas frecuentes