Asegurar un VPS Linux no consiste en instalar UFW y Fail2ban y dar el trabajo por terminado. Un servidor expuesto a Internet debe defenderse en profundidad: sistema mantenido, accesos administrativos nominativos, autenticación SSH robusta, puertos estrictamente necesarios, servicios ejecutados con los mínimos privilegios, registros explotables, copias restaurables y un procedimiento de reacción en caso de compromiso.
Esta guía propone una base realista para Debian y Ubuntu. Cada cambio delicado va acompañado de una comprobación y, cuando hace falta, de una precaución contra el bloqueo remoto.
Al final debería poder responder con precisión a estas preguntas:
- ¿qué versión del sistema está instalada y hasta cuándo se mantiene?
- ¿qué servicios escuchan en IPv4 e IPv6?
- ¿quién puede conectarse por SSH, con qué método y desde qué red?
- ¿qué reglas de cortafuegos se aplican realmente?
- ¿están instalados los parches de seguridad y se señalan sus fallos?
- ¿sobreviven los registros a un reinicio y se copian fuera del VPS?
- ¿cuál es la última copia restaurada con éxito?
- ¿qué hará si una clave, una cuenta o el servidor entero resultan comprometidos?
Método, alcance y límites
Las recomendaciones se contrastaron el 31 de agosto de 2026 con las publicaciones de la ANSSI francesa sobre endurecimiento de GNU/Linux, la documentación oficial de Debian, Ubuntu Server, OpenSSH, systemd, el núcleo Linux, Docker y restic. La guía de la ANSSI aporta un marco de endurecimiento; los comandos y comportamientos susceptibles de cambiar se verificaron en la documentación actual de cada proyecto.
Las versiones, las fechas de soporte y el comportamiento de las herramientas cambian. Antes de aplicar esta base en producción, ejecútela en un VPS de prueba y compruebe los valores fechados de este artículo en las páginas oficiales enlazadas a lo largo del texto.
Esta guía cubre un VPS Debian o Ubuntu administrado directamente. No sustituye al endurecimiento propio de Nginx, Apache, PHP, Docker, una base de datos o una aplicación, ni a una arquitectura de alta disponibilidad, ni a una auditoría reglamentaria o una prueba de intrusión, ni a las reglas específicas de Kubernetes, Proxmox, un router, un servidor de correo o un hipervisor, ni a las medidas del proveedor por debajo de la capa de virtualización.
La seguridad es una propiedad del conjunto: proveedor, red, sistema, aplicación, identidades, datos, copias y explotación.
Versiones consideradas en agosto de 2026
Debian 13 «trixie» es la versión estable actual. Debian indica soporte completo hasta el 9 de agosto de 2028 y después una fase LTS hasta el 30 de junio de 2030, con un conjunto de arquitecturas reducido durante esa fase. Debian 12 ha sido sustituida por Debian 13: su soporte completo terminó el 11 de julio de 2026 y sigue cubierta por su fase LTS hasta el 30 de junio de 2028, limitada a ciertas arquitecturas. Consulte las páginas oficiales de Debian 13 y Debian 12.
Ubuntu 22.04, 24.04 y 26.04 son versiones LTS aún mantenidas en agosto de 2026. Canonical publica las fechas exactas en su ciclo de vida de Ubuntu.
| Sistema | Situación al 31 de agosto de 2026 | Decisión recomendada |
|---|---|---|
| Debian 13 | estable actual | opción Debian recomendada para una instalación nueva |
| Debian 12 | LTS, soporte más limitado según la arquitectura | planificar la migración a Debian 13 |
| Ubuntu 26.04 LTS | LTS actual | opción Ubuntu recomendada tras validar la compatibilidad aplicativa |
| Ubuntu 24.04 LTS | mantenimiento estándar hasta 2029 | excelente opción para una pila ya cualificada |
| Ubuntu 22.04 LTS | mantenimiento estándar hasta 2027 | prever la actualización de versión |
| versión sin soporte | sin parches ordinarios | migrar; un cortafuegos no compensa un sistema sin mantenimiento |
No juzgue la seguridad de un sistema solo con uname -r. Debian y Ubuntu retroportan correcciones sin adoptar necesariamente el número de versión más reciente del proyecto original. Compruebe una CVE en el Debian Security Tracker o en el seguimiento de CVE de Ubuntu, con la distribución y el paquete realmente instalados.
Modelo de amenaza: qué pretende reducir esta guía
Un VPS público está expuesto, entre otras cosas, a los escaneos automatizados y a los intentos de autenticación, a la explotación de un servicio o una dependencia sin corregir, al robo de una clave SSH, un token de API o un secreto de la aplicación, a un error de cortafuegos, de permisos o de publicación en Docker, a la escalada de privilegios tras el compromiso de una aplicación, al borrado o cifrado de los datos y las copias accesibles, a la eliminación de los registros por un atacante convertido en administrador y a un error humano durante una actualización o un cambio de red.
Esta base no hace invulnerable al VPS. Busca reducir la probabilidad de intrusión, limitar el impacto de un primer acceso, mejorar la detección y permitir una reconstrucción controlada.
Tres niveles de madurez
| Nivel | Medidas mínimas | Uso |
|---|---|---|
| Base | inventario, actualizaciones, cuenta nominativa, clave SSH, root y contraseña SSH desactivados, cortafuegos, copia remota | cualquier VPS expuesto |
| Producción | actualizaciones supervisadas, AppArmor, Fail2ban según el riesgo, registros persistentes y remotos, alertas externas, restauración probada | sitio o servicio en producción |
| Reforzado | administración por VPN o bastión, clave FIDO2 o MFA, filtrado saliente estudiado, auditd/AIDE, repositorio de copias append-only, configuración declarativa | datos sensibles o requisitos exigentes |
No todas las medidas deben aplicarse a ciegas. Desactivar el reenvío IP, por ejemplo, rompe un router, una VPN o ciertas redes de contenedores. El endurecimiento profesional empieza por el contexto.
Antes de cualquier cambio: no quedarse fuera
Antes de tocar SSH o el cortafuegos:
- compruebe que la consola de rescate del proveedor funciona;
- mantenga abierta la sesión SSH actual;
- abra una segunda ventana para probar cada cambio;
- anote la dirección y el puerto SSH efectivos;
- cree una instantánea de precaución si la plataforma lo permite;
- guarde una copia de los archivos que modifique;
- desactive el acceso antiguo solo después de validar el nuevo.
Una instantánea tomada antes del cambio facilita una vuelta atrás operativa, pero no sustituye a una copia fuera del VPS. Puede ser inconsistente si una base de datos escribe en ese instante y suele seguir administrándose desde la misma cuenta de proveedor.
1. Inventariar el sistema antes de endurecerlo
Empiece por una recogida de solo lectura:
cat /etc/os-release
uname -a
hostnamectl
systemd-detect-virt
ip -brief address
ip route
ip -6 route
sudo ss -lntup
sudo systemctl --type=service --state=running --no-pager
sudo systemctl list-unit-files --state=enabled --no-pager
df -hT
df -ih
findmnt
timedatectl
ss -lntup lista los sockets a la escucha. Para ver las conexiones TCP establecidas, incluidas las salientes:
sudo ss -tpn state established
Cree una ficha de explotación con:
| Elemento | Valor a registrar |
|---|---|
| distribución y versión | salida de /etc/os-release |
| núcleo y arquitectura | salida de uname -a |
| IPv4 e IPv6 públicas | direcciones realmente enrutadas |
| interfaz principal | nombre, dirección, puerta de enlace |
| puertos esperados | por ejemplo TCP 22, 80 y 443 |
| servicios esperados | SSH, Nginx, la aplicación, un agente de supervisión |
| administradores autorizados | cuentas nominativas, claves y origen de red |
| datos críticos | archivos, bases, secretos y configuraciones |
| RPO | pérdida de datos máxima aceptable |
| RTO | duración de interrupción máxima aceptable |
Todo puerto sin propietario ni justificación debe estudiarse antes de cerrarlo. Un servicio puede escuchar únicamente en 127.0.0.1, en una dirección privada, en todas las interfaces IPv4 con 0.0.0.0, o en IPv6 con ::. Revise ambas familias.
2. Usar cuentas nominativas y el mínimo privilegio
Evite la administración diaria con una cuenta compartida o directamente como root. Cree una cuenta por administrador para que los registros y las revocaciones sigan siendo atribuibles.
Ejemplo con adminops:
sudo adduser adminops
sudo usermod -aG sudo adminops
sudo groupadd --force ssh-admins
sudo usermod -aG ssh-admins adminops
id adminops
getent group ssh-admins
En Debian y Ubuntu, los miembros del grupo sudo pueden obtener privilegios conforme a la política local. Ubuntu explica el interés de sudo para la trazabilidad en su documentación sobre gestión de usuarios.
Desde el equipo del administrador, genere una clave moderna protegida por una frase de contraseña:
ssh-keygen -t ed25519 -a 100 -C "adminops@organizacion"
ssh-copy-id -i ~/.ssh/id_ed25519.pub adminops@DIRECCION_DEL_VPS
Ed25519 es la opción recomendada en la documentación de OpenSSH de Ubuntu. La opción -a aumenta el número de rondas de la función de derivación que protege la clave privada con su frase de contraseña; no cambia el algoritmo de la clave. Nuestra guía para configurar una clave SSH en un VPS Linux detalla el procedimiento en Windows, macOS y Linux.
Para un nivel reforzado, una clave FIDO2 de tipo ed25519-sk exige la presencia de un autenticador físico compatible:
ssh-keygen -t ed25519-sk -C "adminops-fido2@organizacion"
Conserve un método de recuperación distinto, protegido y probado. Una única llave física sin procedimiento de reserva convierte su pérdida en un incidente de disponibilidad.
Pruebe en una ventana nueva:
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 adminops@DIRECCION_DEL_VPS
sudo -v
id
No siga adelante mientras la conexión por clave y sudo no funcionen.
Auditar las cuentas existentes
getent passwd
awk -F: '($3 == 0) {print $1}' /etc/passwd
sudo lastlog
sudo passwd -S root
Normalmente debe existir un único UID 0. Bloquee o elimine las cuentas que hayan dejado de ser necesarias, tras revisar sus archivos, tareas programadas, procesos y dependencias aplicativas.
3. Endurecer OpenSSH sin interrumpir el acceso
Ubuntu acepta la configuración principal en /etc/ssh/sshd_config y los fragmentos en /etc/ssh/sshd_config.d/. Su configuración incluye normalmente ese directorio al principio del archivo principal. OpenSSH conserva el primer valor encontrado para la mayoría de las directivas; por eso un archivo llamado 00-hardening.conf resulta más previsible que uno tardío que podría quedar después de un fragmento creado por cloud-init. Este comportamiento lo documentan Ubuntu y el manual sshd_config de Debian.
Compruebe primero la inclusión:
grep -nE '^[[:space:]]*Include' /etc/ssh/sshd_config
sudo sshd -T | sort
Guarde una copia de la configuración:
sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.before-hardening
sudo install -d -m 755 /etc/ssh/sshd_config.d
sudoedit /etc/ssh/sshd_config.d/00-hardening.conf
Añada:
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
AllowGroups ssh-admins
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
PermitTunnel no
Antes de recargar:
sudo sshd -t
sudo sshd -T | grep -E '^(port|permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods|allowgroups|maxauthtries|logingracetime|x11forwarding|permittunnel) '
Si existen bloques Match, compruebe también la configuración aplicada a la cuenta y a la dirección de administración:
sudo sshd -T \
-C user=adminops,host="$(hostname -f)",addr=198.51.100.10 |
grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|authenticationmethods|allowgroups) '
La dirección 198.51.100.10 pertenece a un rango reservado a la documentación. Sustitúyala por la dirección real desde la que se conectará el administrador.
Si sshd -t no devuelve nada, la sintaxis es válida. Recargue sin cerrar la sesión actual:
sudo systemctl reload ssh
sudo systemctl status ssh --no-pager
sudo journalctl -u ssh -n 50 --no-pager
Pruebe de inmediato una conexión nueva con la clave y después sudo -v. Cierre la sesión antigua solo tras esa prueba.
Lo que debe seguir siendo condicional
AllowTcpForwarding noyAllowAgentForwarding noson útiles si no se necesita ningún túnel ni salto SSH, pero rompen esos usos;- restringir SSH a una dirección IP o a una VPN reduce mucho la exposición, pero exige una vía de reserva;
- cambiar el puerto 22 reduce sobre todo el ruido de los robots; no sustituye ni a una clave, ni a un cortafuegos, ni a los parches;
- un MFA TOTP puede complementar la clave. La documentación de Ubuntu describe la combinación
AuthenticationMethods publickey,keyboard-interactiveen su guía TOTP/HOTP.
4. Instalar y supervisar las actualizaciones de seguridad
Un comando con -y resulta cómodo en un laboratorio, pero un primer endurecimiento en producción debe permitir leer los cambios propuestos:
sudo apt update
apt list --upgradable
sudo apt-get -s upgrade
sudo apt upgrade
sudo apt autoremove --dry-run
Ejecute apt autoremove solo después de revisar la lista. Una actualización de distribución, un núcleo, un controlador o un paquete de negocio puede exigir un reinicio y una prueba aplicativa.
Activar los parches automáticos
En Ubuntu Server, unattended-upgrades está instalado y las actualizaciones de seguridad suelen estar activadas por defecto. No lo dé por hecho: compruébelo. La documentación de Ubuntu sobre actualizaciones automáticas detalla los archivos, los temporizadores, los orígenes permitidos y los registros.
En Debian, instale y active el mecanismo de forma explícita según su política:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
systemctl list-timers 'apt-daily*' --all
sudo unattended-upgrade --dry-run --debug
sudo journalctl -u apt-daily-upgrade.service -n 100 --no-pager
Compruebe en particular:
grep -RhsE 'APT::Periodic::(Update-Package-Lists|Unattended-Upgrade)' \
/etc/apt/apt.conf.d/
sudo sed -n '/Allowed-Origins/,/};/p' \
/etc/apt/apt.conf.d/50unattended-upgrades
Un origen de terceros no queda cubierto automáticamente. Compruebe qué repositorios suministran los paquetes:
grep -RhsE '^[[:space:]]*(deb |Types:|URIs:|Suites:|Signed-By:)' \
/etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null
apt-cache policy
En Debian 13, las notas de publicación proponen además esta búsqueda de paquetes instalados que no provienen de Debian:
apt list '?narrow(?installed, ?not(?origin(Debian)))'
Un repositorio añadido para un solo paquete amplía la cadena de confianza y puede suministrar actualizaciones a otros paquetes. Use repositorios oficiales o del editor, una clave dedicada mediante Signed-By, y elimine las fuentes que ya no necesite. Evite ejecutar curl ... | sh directamente sin descargar, verificar y leer el script.
Reinicios y alertas
En Ubuntu, un reinicio recomendado se señala generalmente así:
if [ -f /var/run/reboot-required ]; then
cat /var/run/reboot-required
cat /var/run/reboot-required.pkgs 2>/dev/null
fi
La automatización sin supervisión está incompleta. Alerte como mínimo del fallo del temporizador o del servicio de actualización, de la antigüedad de la última ejecución correcta, de un reinicio requerido desde hace demasiado tiempo, de un paquete retenido o un origen no cubierto, y de un sistema próximo al fin de soporte.
5. Configurar el cortafuegos: elegir un único gestor
Un cortafuegos no es una herramienta de inventario: determine primero los flujos legítimos. Complementa el endurecimiento de los servicios, pero no lo sustituye, como recuerda el manual de seguridad de Debian.
Elija un enfoque principal:
| Contexto | Opción recomendada |
|---|---|
| Ubuntu, reglas sencillas | UFW |
| Debian, política nativa y avanzada | nftables |
| Docker Engine | estudiar primero las cadenas y los límites de Docker |
| infraestructura con cortafuegos del proveedor | aplicar también el filtrado de red, sin renunciar al cortafuegos local |
UFW es la herramienta de cortafuegos predeterminada documentada por Ubuntu. nftables es el marco predeterminado y recomendado por Debian. No apile UFW, un conjunto de reglas nftables manual y otros gestores sin entender su orden.
Opción A: UFW en Ubuntu o para una necesidad sencilla
Anote el puerto SSH efectivo:
sudo sshd -T | awk '$1 == "port" {print $2; exit}'
El ejemplo siguiente supone SSH en el 22 y un servidor web. Adapte los puertos antes de activarlo:
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH administration'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw show added
sudo ufw enable
sudo ufw status verbose
sudo ufw status numbered
Mantenga la sesión abierta y pruebe una conexión SSH nueva.
Si la administración procede de una IPv4 fija, cree primero una regla restrictiva:
sudo ufw allow from 198.51.100.10 to any port 22 proto tcp \
comment 'SSH desde el equipo de administracion'
sudo ufw status numbered
Tras probar desde esa dirección, elimine la regla SSH abierta a todos usando su número:
sudo ufw delete NUMERO_DE_LA_REGLA
Repita la lógica para IPv6 si el administrador la usa. No desactive IPv6 solo para ahorrarse sus reglas: un registro AAAA o una interfaz IPv6 olvidados pueden crear una exposición distinta de la que probó en IPv4.
Nuestro tutorial para configurar UFW en un VPS Linux detalla la gestión de las reglas.
Opción B: nftables en un VPS Debian sin Docker
El ejemplo siguiente conviene a un VPS web nuevo, que no es router, sin Docker y con SSH en el 22. Sustituye todo el conjunto de reglas: no lo use si otro software ya gestiona netfilter.
Guarde primero el estado actual en un archivo que empiece él mismo por una puesta a cero del conjunto de reglas:
sudo sh -c '{
printf "%s\n" "flush ruleset"
nft list ruleset
} > /root/nftables.before-hardening.nft'
sudoedit /etc/nftables.conf
Contenido:
#!/usr/sbin/nft -f
flush ruleset
define ssh_port = 22
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept
ct state invalid drop
ct state established,related accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
tcp dport $ssh_port ct state new accept comment "SSH"
tcp dport { 80, 443 } ct state new accept comment "Web"
counter drop
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
Permitir el ICMP e ICMPv6 útiles evita romper el descubrimiento de vecinos IPv6, el diagnóstico y el descubrimiento de la MTU. No copie una regla que bloquee todo el ICMP sin entender esas funciones.
Compruebe la sintaxis antes de aplicar:
sudo nft -c -f /etc/nftables.conf
sudo nft -f /etc/nftables.conf
sudo nft list ruleset
sudo systemctl enable nftables
Pruebe una sesión SSH nueva y el servicio web. Para volver atrás desde la consola:
sudo nft -f /root/nftables.before-hardening.nft
El archivo de vuelta atrás también contiene flush ruleset: al cargarlo sustituye la política actual en lugar de añadir reglas duplicadas. Realice esa vuelta atrás desde la consola de rescate si SSH ya está interrumpido.
Si el VPS enruta tráfico, aloja una VPN, usa varias interfaces o ejecuta Docker, diseñe las cadenas forward y el NAT para esa arquitectura. Una política drop copiada sin adaptar puede interrumpir el servicio.
Añadir un cortafuegos de red
Cuando el proveedor ofrece un cortafuegos previo, úselo como segunda barrera: SSH solo desde las direcciones de administración o la VPN, HTTP/HTTPS desde Internet si el servidor es público, bases de datos y paneles de administración nunca abiertos a todos, reglas IPv4 e IPv6 coherentes y consola de rescate probada.
El filtrado previo puede bloquear tráfico antes de que consuma recursos del VPS. Sin embargo, no ve necesariamente las redes internas de los contenedores y no protege un servicio accesible desde el propio VPS.
6. Caso crítico: Docker y las reglas de UFW o nftables
Docker modifica las reglas de filtrado y de NAT para publicar los puertos de los contenedores. Su documentación advierte de que el tráfico hacia un puerto publicado se desvía antes de las cadenas INPUT y OUTPUT que usa UFW; un puerto de Docker puede seguir siendo accesible pese a una política de UFW que parece denegarlo. Consulte la página oficial Packet filtering and firewalls.
Inventaríe las publicaciones:
sudo docker ps --format 'table {{.Names}}\t{{.Ports}}'
sudo ss -lntup
sudo iptables -S DOCKER-USER 2>/dev/null
La diferencia esencial:
# Expuesto en todas las interfaces del VPS
ports:
- "8080:80"
# Accesible solo desde el VPS, por ejemplo a traves de Nginx
ports:
- "127.0.0.1:8080:80"
Para una base de datos, Redis, un panel o una aplicación tras un proxy inverso, vincule el puerto a 127.0.0.1 o a una dirección privada cuando no haga falta acceso público.
Docker recomienda usar la cadena DOCKER-USER para las políticas que deben preceder a sus propias reglas de iptables. Desaconseja desactivar su gestión de iptables/ip6tables, porque eso suele romper la red de los contenedores. La documentación de instalación de Docker precisa además que Docker Engine admite iptables-nft e iptables-legacy, pero no un conjunto de reglas creado directamente con nft como mecanismo de filtrado de Docker. No mezcle, pues, el modelo nftables anterior con Docker sin una arquitectura probada. Nuestra guía para instalar Docker en un VPS Linux cubre la instalación y la configuración del demonio.
Tras cada despliegue de contenedor, repita el escaneo desde una red externa. El archivo Compose describe la intención; la red observable describe la realidad.
7. Reducir servicios, paquetes y privilegios
Liste las unidades activas y los puertos:
sudo systemctl --type=service --state=running --no-pager
sudo systemctl list-unit-files --state=enabled --no-pager
sudo ss -lntup
Para cada servicio, pregúntese: ¿es imprescindible? ¿debe arrancar automáticamente? ¿debe escuchar en una interfaz pública? ¿funciona con una cuenta dedicada sin privilegios? ¿qué archivos, capacidades de Linux y redes necesita? ¿se vigilan su registro y su estado?
Detener y desactivar es más prudente que eliminar de inmediato:
sudo systemctl disable --now NOMBRE_DEL_SERVICIO
sudo systemctl status NOMBRE_DEL_SERVICIO --no-pager
Tras un periodo de observación y una comprobación de dependencias, elimine el paquete si se confirma que no hace falta.
No ejecutar la aplicación como root
Un servicio aplicativo debe usar una cuenta de sistema dedicada, directorios limitados y ningún intérprete de comandos interactivo si no es necesario. Las bases de datos deben escuchar en loopback o en una dirección privada, salvo necesidad explícita y filtrada.
Con systemd, analice primero el nivel de aislamiento:
sudo systemd-analyze security --no-pager NOMBRE.service
sudo systemctl cat NOMBRE.service
La puntuación de systemd-analyze security mide únicamente las protecciones de systemd que la herramienta conoce. Una puntuación alta no prueba una vulnerabilidad, y una baja no valida el código de la aplicación. El manual de systemd-analyze insiste en ese límite.
Para una aplicación interna sin JIT que solo escribe en dos directorios, un drop-in puede parecerse a esto:
[Service]
User=myapp
Group=myapp
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=strict
ProtectHome=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
LockPersonality=yes
CapabilityBoundingSet=
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
ReadWritePaths=/var/lib/myapp /var/log/myapp
Créelo con:
sudo systemctl edit NOMBRE.service
sudo systemd-analyze verify NOMBRE.service
sudo systemctl daemon-reload
sudo systemctl restart NOMBRE.service
sudo systemctl status NOMBRE.service --no-pager
sudo journalctl -u NOMBRE.service -n 100 --no-pager
Aplique las opciones de una en una. MemoryDenyWriteExecute=yes, ProtectHome=yes, la restricción de familias de direcciones o la retirada de capacidades pueden romper un entorno de ejecución JIT, un binario que carga módulos o un servicio que espera un acceso concreto. La referencia completa es systemd.exec.
8. Conservar y controlar AppArmor
AppArmor aplica un control de acceso obligatorio por programa. En Ubuntu está instalado y cargado por defecto. Compruebe su estado:
sudo aa-status
systemctl status apparmor --no-pager
La documentación de AppArmor de Ubuntu distingue en particular el modo enforce, que bloquea las operaciones prohibidas y las registra, el modo complain, útil para aprender un perfil sin bloquear, y los procesos confinados o sin perfil.
En Debian, AppArmor está disponible, pero su activación y la presencia de perfiles dependen de la imagen y del núcleo:
sudo apt install apparmor apparmor-utils
sudo systemctl enable --now apparmor
sudo aa-status
No desactive AppArmor para «arreglar» una aplicación. Analice las denegaciones:
sudo journalctl -k -g 'apparmor="DENIED"' --since today
Cree o adapte un perfil en preproducción, pase temporalmente el perfil afectado a modo de aprendizaje si hace falta y vuelva después a enforce. Un perfil demasiado permisivo o dejado en complain no ofrece la protección esperada.
9. Añadir Fail2ban cuando el servicio lo justifique
Fail2ban lee los eventos de fallo y añade temporalmente una regla de bloqueo. Reduce el ruido y algunos ataques repetidos, pero no corrige ni una contraseña débil, ni un fallo de software, ni una credencial robada.
Instálelo:
sudo apt update
sudo apt install fail2ban
sudoedit /etc/fail2ban/jail.d/sshd.local
Configuración para un sistema que usa el diario de systemd:
[sshd]
enabled = true
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
El backend systemd lee el diario y no debe recibir un logpath. Los parámetros y las unidades de tiempo se describen en el manual de Debian jail.conf.
Valide antes de arrancar:
sudo fail2ban-client -t
sudo systemctl enable --now fail2ban
sudo fail2ban-client ping
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo journalctl -u fail2ban -n 100 --no-pager
Una lista de excepciones solo es razonable para una dirección realmente estable y bajo su control. Un rango demasiado amplio elude precisamente el control que acaba de añadir. Con Docker, compruebe además que la acción elegida actúa en la cadena que el tráfico recorre de verdad.
Nuestra guía para instalar y configurar Fail2ban trata los registros recientes de Debian, la jaula SSH, el desbloqueo y las pruebas de filtros.
10. Endurecer con prudencia algunos parámetros del núcleo
Los sysctl no deben copiarse por centenares desde una lista genérica. El núcleo Linux advierte de que ciertos ajustes pueden dejar un sistema inutilizable y recomienda comprender cada modificación.
Empiece por anotar los valores:
sysctl kernel.dmesg_restrict
sysctl kernel.kptr_restrict
sysctl fs.protected_hardlinks
sysctl fs.protected_symlinks
sysctl fs.protected_fifos
sysctl fs.protected_regular
sysctl net.ipv4.conf.all.accept_redirects
sysctl net.ipv6.conf.all.accept_redirects
Para un VPS anfitrión clásico, que no es router, puede estudiarse este fragmento conservador:
sudoedit /etc/sysctl.d/60-local-hardening.conf
# Limitar la exposicion de informacion del nucleo
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
# Reforzar los objetos creados en directorios temporales compartidos
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
# Un VPS anfitrion no suele necesitar aceptar redirecciones ICMP
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# Tampoco suele necesitar emitir redirecciones IPv4
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
Cargue y compruebe:
sudo sysctl -p /etc/sysctl.d/60-local-hardening.conf
sudo sysctl --system
La documentación del núcleo detalla los sysctl de IP y los sysctl de archivos.
Esta guía no impone deliberadamente net.ipv4.ip_forward=0, porque Docker, WireGuard o un router pueden depender de él; ni rp_filter=1, porque el enrutamiento asimétrico, algunas VPN y el policy routing exigen un estudio; ni la desactivación de IPv6; ni la desactivación irreversible de módulos o de kexec; ni un ajuste de BPF o io_uring sin un inventario de las aplicaciones y los agentes.
11. Hacer los registros persistentes y explotables
Los registros locales son útiles para el diagnóstico, pero un atacante con root puede modificarlos o borrarlos. La estrategia debe combinar conservación local acotada, reloj fiable, envío remoto y alertas.
Persistencia y límite de espacio de journald
Cree un fragmento:
sudo install -d -m 755 /etc/systemd/journald.conf.d
sudoedit /etc/systemd/journald.conf.d/60-persistent.conf
Ejemplo a adaptar al tamaño del disco:
[Journal]
Storage=persistent
Compress=yes
SystemMaxUse=500M
SystemKeepFree=1G
MaxRetentionSec=30day
Después:
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
sudo journalctl --flush
sudo journalctl --disk-usage
sudo journalctl --verify
sudo journalctl -p warning..alert --since today
SystemMaxUse, SystemKeepFree y la persistencia están documentados en journald.conf. Un límite fijo debe dejar espacio suficiente al sistema y a la aplicación.
Centralizar las trazas fuera del VPS
En un servidor de producción, envíe como mínimo las autenticaciones SSH y sudo, los eventos del núcleo y del cortafuegos, los cambios de identidad, los registros del proxy inverso y de la aplicación, y las salidas de las actualizaciones automáticas, las copias y los agentes de seguridad.
Dos soluciones habituales son systemd-journal-upload hacia systemd-journal-remote, o rsyslog hacia un colector. systemd-journal-upload envía las entradas del diario; el módulo omfwd de rsyslog admite UDP, TCP o TLS y recomienda TCP con TLS para un despliegue moderno.
Una implementación seria debe autenticar el colector mediante certificado, comprobar su nombre y su autoridad de certificación, usar TLS en lugar de syslog en claro por UDP en Internet, poner los eventos en cola durante un corte, impedir que el VPS de origen borre los archivos del colector, alertar si el flujo o el latido se interrumpen, y proteger los registros frente a accesos no autorizados, ya que suelen contener datos sensibles.
Sincronizar la hora
timedatectl status
timedatectl timesync-status 2>/dev/null || true
systemctl status systemd-timesyncd chrony --no-pager 2>/dev/null || true
Use un único mecanismo de sincronización correctamente configurado. Una deriva horaria complica la correlación de eventos, los certificados, los tokens y a veces la autenticación.
12. Auditar los cambios y la integridad
Linux Audit
auditd recoge eventos producidos por el subsistema de auditoría del núcleo. Debian proporciona las herramientas para almacenar y consultar esos registros, documentadas en los manuales de auditd de Debian 13.
sudo apt install auditd audispd-plugins
sudo systemctl enable --now auditd
sudoedit /etc/audit/rules.d/50-local.rules
Base mínima:
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/sudoers -p wa -k privilege
-w /etc/sudoers.d -p wa -k privilege
-w /etc/ssh/sshd_config -p wa -k ssh_config
-w /etc/ssh/sshd_config.d -p wa -k ssh_config
Cargue y compruebe:
sudo augenrules --check
sudo augenrules --load
sudo auditctl -s
sudo auditctl -l
sudo ausearch -k ssh_config -ts today -i
sudo aureport --auth --summary
Adapte las reglas a los archivos realmente críticos. Una auditoría excesiva llena el disco y vuelve inutilizable la señal. Configure la rotación, la alerta de saturación y el envío remoto.
Verificación de paquetes y AIDE
Para detectar los archivos de paquetes modificados:
sudo dpkg -V
Una salida no es automáticamente un compromiso: hay archivos de configuración que se modifican legítimamente. Compárelos con su gestión de configuración y sus cambios aprobados.
AIDE construye una base de integridad:
sudo apt install aide
sudo aideinit
sudo aide --check
Inicialice la base solo en un servidor que se considere limpio y después del endurecimiento. Lea la salida de aideinit para confirmar qué base está activa en su distribución. Copie la base de referencia, o al menos su huella, a una ubicación protegida fuera del VPS; de lo contrario un atacante con root puede modificar tanto los archivos como su referencia.
Ni auditd ni AIDE son un EDR completo. Añaden trazas y controles de integridad, siempre que los resultados se lean y se protejan.
13. Proteger los archivos, las claves y los secretos
Busque anomalías sin corregirlas automáticamente:
sudo find /etc -xdev -type f -perm -0002 -ls
sudo find / -xdev \( -perm -4000 -o -perm -2000 \) -type f -print
sudo find /root /home -path '*/.ssh/authorized_keys' -type f \
-exec stat -c '%a %U:%G %n' {} \;
sudo find /etc/cron.d /etc/cron.daily /etc/cron.hourly \
/etc/cron.monthly /etc/cron.weekly /var/spool/cron \
-maxdepth 2 -type f -ls 2>/dev/null
systemctl list-timers --all --no-pager
Un permiso inhabitual no es necesariamente malicioso. Identifique el paquete, el propietario y el uso antes de modificar nada.
Reglas básicas: ningún secreto en Git, en una imagen Docker, en un comando visible en el historial o en una URL; archivos de secretos legibles solo por la cuenta que los necesita; tokens distintos por servicio y por entorno; privilegios mínimos en DNS, copias, base de datos y API; rotación planificada e inmediata tras una exposición; eliminación de los authorized_keys antiguos; claves privadas nunca copiadas en una documentación o un ticket.
Para los servicios systemd modernos, estudie las credenciales de systemd en lugar de variables de entorno globales. Una variable puede seguir siendo visible para procesos privilegiados y acabar en un volcado de diagnóstico.
14. Cifrar los servicios públicos con TLS
HTTPS protege el tráfico entre el cliente y el servidor; no corrige una aplicación vulnerable. Para un sitio Nginx o Apache, el registro DNS A y, si existe, el AAAA deben apuntar al servidor correcto; los puertos TCP 80 y 443 deben estar abiertos según el desafío ACME; la renovación debe estar automatizada y probada; una alerta debe preceder a la expiración; y HSTS solo debe activarse tras validar de forma duradera HTTPS en los nombres afectados.
Siga nuestra guía para instalar un certificado SSL de Let's Encrypt con Certbot y compruebe después:
sudo certbot certificates
sudo certbot renew --dry-run
systemctl list-timers '*certbot*' --all
openssl s_client \
-connect example.com:443 \
-servername example.com \
-verify_return_error </dev/null
Una redirección de HTTP a HTTPS es útil para el navegador, pero mantenga el puerto 80 accesible si la renovación por HTTP-01 depende de él. DNS-01 es necesario para un wildcard y puede evitar esa dependencia, a costa de un secreto de API DNS que hay que proteger.
15. Implantar una copia realmente restaurable
La ANSSI recuerda que las copias de seguridad son imprescindibles frente a los incidentes y recomienda en particular una política 3-2-1: tres copias, en dos soportes distintos, una de ellas fuera de línea. Pide además formalizar la pérdida de datos máxima admisible y la duración de interrupción máxima admisible, en su referencial de medidas y su guía sobre la copia de seguridad de los sistemas de información.
Distinguir archivo, instantánea y copia de seguridad
| Mecanismo | Útil para | Límite |
|---|---|---|
| archivo tar en el mismo disco | copia puntual de archivos | desaparece con el VPS o el disco |
| instantánea del VPS | vuelta atrás rápida antes de un cambio | misma cuenta de proveedor, coherencia aplicativa por verificar |
| replicación o sincronización | disponibilidad o copia rápida | replica también el borrado y la corrupción |
| copia versionada fuera del sitio | recuperación tras avería, error o compromiso | debe estar cifrada, supervisada y restaurada |
| copia fuera de línea o inmutable | resistencia al borrado y al ransomware | exige política de retención y pruebas |
Nuestros VPS ofrecen como opción copias de seguridad deslocalizadas automáticas: una copia completa del VPS, realizada cada día, almacenada en un datacenter europeo distinto, con restauración en un clic y un historial rotativo cuya profundidad elige usted. Diez copias simultáneas equivalen así a diez días de historial, y cada copia nueva sustituye a la más antigua. Esta opción ya cubre la copia fuera del servidor, la frecuencia diaria y la restauración rápida.
No obstante, no exime de las dos precauciones siguientes. Primero, la copia completa de un VPS en funcionamiento no es necesariamente coherente para una base de datos: siga produciendo un volcado justo antes, como se describe más adelante. Segundo, sigue gestionándose desde la misma cuenta de proveedor que el servidor; para el escenario de compromiso, conserve además una copia en un dominio de administración distinto, en append-only o fuera de línea según el riesgo. Y en todos los casos, pruebe la restauración: un historial de diez días solo vale algo si ha comprobado que una restauración vuelve a arrancar realmente la aplicación.
Definir el objetivo antes que la herramienta
| Dato | RPO | RTO | Retención |
|---|---|---|---|
| configuración del sistema | 24 h | 4 h | 30 días |
| archivos de clientes | 1 h | 2 h | 30 días y 12 meses |
| base transaccional | 15 min | 1 h | diarios y copias diarias |
| registros de seguridad | según política | consulta inmediata | 90 días o requisito aplicable |
Estos valores dictan la frecuencia y la tecnología. Una copia diaria no satisface un RPO de quince minutos.
Ejemplo con restic hacia un destino remoto
restic cifra y deduplica las copias. Admite varios backends; el ejemplo usa SFTP. Instale el paquete de la distribución:
sudo apt update
sudo apt install restic
sudo install -d -m 700 /root/.config/restic
sudo touch /root/.config/restic/password
sudo chown root:root /root/.config/restic/password
sudo chmod 600 /root/.config/restic/password
sudoedit /root/.config/restic/password
sudo touch /etc/restic-vps.env
sudo chown root:root /etc/restic-vps.env
sudo chmod 600 /etc/restic-vps.env
sudoedit /etc/restic-vps.env
Contenido de /etc/restic-vps.env:
RESTIC_REPOSITORY=sftp:backup@backup.example:/srv/restic/vps-01
RESTIC_PASSWORD_FILE=/root/.config/restic/password
La frase de contraseña debe ser larga, aleatoria, guardarse en un gestor distinto y estar probada. Sin ella, el repositorio cifrado no es restaurable.
Inicialice manualmente desde una sesión root, tras validar la huella SSH del servidor de copias:
sudo -i
set -a
. /etc/restic-vps.env
set +a
restic init
restic backup /etc /srv /var/www /var/backups/databases
restic snapshots
restic check
exit
La copia del directorio de datos de una base en actividad no es necesariamente coherente. Produzca un volcado o use el método físico y los diarios que recomiende el motor.
Para MariaDB, cuando está configurada la autenticación local de root por socket:
sudo install -d -m 700 /var/backups/databases
sudo sh -c 'mariadb-dump --single-transaction --routines --events --triggers --all-databases | gzip -9 > "/var/backups/databases/mariadb-$(date -u +%F-%H%M%S).sql.gz"'
Para PostgreSQL:
sudo install -d -m 700 -o postgres -g postgres \
/var/backups/databases/postgresql
sudo -u postgres sh -c 'pg_dumpall | gzip -9 > "/var/backups/databases/postgresql/all-$(date -u +%F-%H%M%S).sql.gz"'
Pruebe la restauración en una base aislada. --single-transaction mejora la coherencia de las tablas transaccionales de MariaDB/InnoDB, pero no es una garantía universal para todos los motores ni todas las operaciones.
Automatizar con un temporizador de systemd
Cree /etc/systemd/system/restic-backup.service:
[Unit]
Description=Copia restic del VPS
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
EnvironmentFile=/etc/restic-vps.env
ExecStart=/usr/bin/restic backup /etc /srv /var/www /var/backups/databases
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
Cree /etc/systemd/system/restic-backup.timer:
[Unit]
Description=Copia diaria restic del VPS
[Timer]
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
Active y compruebe:
sudo systemd-analyze verify \
/etc/systemd/system/restic-backup.service \
/etc/systemd/system/restic-backup.timer
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl start restic-backup.service
sudo systemctl status restic-backup.service --no-pager
sudo journalctl -u restic-backup.service -n 100 --no-pager
systemctl list-timers restic-backup.timer --all
El volcado de la base debe producirse justo antes de este servicio, mediante una unidad dedicada ordenada con Requires y After, o mediante un orquestador de copias. Un volcado antiguo respaldado cada noche da una ilusión de frescura.
Separar la escritura del borrado
Un VPS comprometido no debería poder borrar las copias antiguas. Cuando el backend lo permita, dé al VPS un acceso append-only. Ejecute la retención desde una máquina de administración distinta que posea los derechos de borrado:
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 12 \
--prune
restic check --read-data-subset=5%
La documentación de restic sobre forget y prune precisa que prune puede ser largo, bloquea el repositorio y debe planificarse. También recomienda una comprobación tras la limpieza. Para un repositorio append-only, estudie los riesgos particulares de las políticas de retención y separe realmente el cliente de mantenimiento.
Probar una restauración
Al menos cada trimestre, en una máquina aislada:
sudo -i
set -a
. /etc/restic-vps.env
set +a
restic snapshots
install -d -m 700 /mnt/restic-restore-test
restic restore latest --target /mnt/restic-restore-test
exit
Compruebe después la presencia y los permisos de los archivos, el descifrado con las credenciales documentadas, la restauración de las bases en un motor de prueba, el arranque de la aplicación, la coherencia funcional, el tiempo real de restauración frente al RTO y el procedimiento de reconstrucción de un VPS vacío.
Una copia «correcta» significa que el proceso terminó. Una copia fiable significa que se ha demostrado una restauración útil.
16. Supervisar el VPS desde el exterior
La supervisión local no puede avisar de un VPS apagado, aislado o totalmente comprometido. Use un servicio externo para la disponibilidad y un canal de alerta distinto del servidor.
| Control | Señal a vigilar |
|---|---|
| disponibilidad | TCP/HTTPS, contenido esperado, latencia |
| TLS | fecha de expiración, cadena y nombre |
| sistema | CPU, memoria, swap, carga |
| almacenamiento | espacio, inodos, crecimiento de los registros |
| servicios | unidades systemd fallidas, reinicios |
| red | puertos nuevos, conexiones inhabituales |
| seguridad | fallos SSH y sudo, denegaciones de AppArmor, auditd |
| parches | última ejecución, fallo, reinicio requerido |
| copias | antigüedad de la última instantánea, tamaño anómalo, fallo |
| hora | deriva o pérdida de sincronización |
Comandos de control diario:
systemctl --failed --no-pager
df -hT
df -ih
free -h
uptime
sudo ss -lntup
sudo journalctl -p warning..alert --since '-24 hours'
sudo journalctl -u ssh --since '-24 hours'
sudo fail2ban-client status sshd 2>/dev/null || true
sudo aa-status 2>/dev/null || true
Los umbrales deben reflejar el servicio. Una alerta al 80 % de disco solo es útil si llega con suficiente antelación respecto a la velocidad de crecimiento. Alerte también de la ausencia de datos: un agente silencioso puede haberse caído.
La ANSSI define la supervisión de seguridad como el conjunto de medios que permiten detectar, calificar y elegir una reacción adecuada; su guía Dirigir un proyecto de supervisión sitúa las herramientas dentro de ese proceso.
17. Verificar el resultado en lugar de confiar en la configuración
Controles locales
# Sistema y parches
cat /etc/os-release
apt list --upgradable
systemctl list-timers 'apt-daily*' --all
# Configuracion SSH efectiva
sudo sshd -t
sudo sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|kbdinteractiveauthentication|authenticationmethods|allowgroups) '
# Exposicion de red
sudo ss -lntup
sudo ufw status verbose 2>/dev/null || true
sudo nft list ruleset 2>/dev/null || true
# Controles de seguridad
sudo aa-status 2>/dev/null || true
sudo fail2ban-client status 2>/dev/null || true
sudo auditctl -s 2>/dev/null || true
# Diario y servicios
sudo journalctl --verify
systemctl --failed --no-pager
# Copia de seguridad
sudo systemctl status restic-backup.service --no-pager
Escaneo externo
Desde un equipo que usted administre y únicamente contra su propio VPS:
sudo nmap -Pn -sS -sV -p- DIRECCION_IPV4_DEL_VPS
sudo nmap -6 -Pn -sT -sV -p- DIRECCION_IPV6_DEL_VPS
Compare el resultado con la lista de puertos autorizados. La referencia de las opciones está en el manual de Nmap.
Haga el escaneo tras el primer endurecimiento, tras instalar Docker o un panel, tras modificar el cortafuegos, tras una migración de red y periódicamente desde Internet.
Tabla de aceptación
| Prueba | Resultado esperado | Evidencia a conservar |
|---|---|---|
| conexión SSH por clave | éxito con cuenta nominativa | registro SSH anonimizado |
| conexión root por SSH | rechazo | extracto de la prueba |
| contraseña SSH | rechazo | comando y resultado |
| sudo | éxito para el administrador autorizado | registro de sudo |
| sintaxis SSH | sshd -t sin errores | fecha y versión |
| puertos externos | solo los flujos aprobados | informe de Nmap para IPv4 e IPv6 |
| actualización automática | ensayo válido, temporizador activo | registro |
| cortafuegos | política y reglas conformes | exportación de UFW o nftables |
| AppArmor | activo, perfiles críticos en enforce | salida de aa-status |
| copia de seguridad | ejecución sin errores | registro e instantánea restic |
| restauración | aplicación y datos legibles | acta fechada |
| registros remotos | evento recibido y con marca de tiempo | búsqueda en el colector |
| consola de rescate | conexión posible | fecha de la última prueba |
18. Qué hacer ante la sospecha de un compromiso
Síntomas como un pico de CPU, un proceso desconocido o una conexión saliente inhabitual justifican una calificación, pero por sí solos no prueban una intrusión. A la inversa, la ausencia de síntomas no prueba la integridad.
Primeras acciones, a adaptar a la gravedad:
- use un equipo de confianza y abra un registro de incidente;
- aísle el VPS con el cortafuegos de red cuando eso no destruya pruebas;
- evite reiniciar o «limpiar» antes de la recogida si está prevista una investigación;
- preserve los registros remotos, el estado de los procesos, las conexiones, las tareas y una instantánea forense;
- revoque desde un sistema sano las claves SSH, contraseñas, tokens, certificados y accesos de proveedor expuestos;
- proteja las copias anteriores e impida su borrado;
- determine el alcance: otros VPS, repositorio Git, CI/CD, DNS, cuentas y bases de datos;
- reconstruya a partir de una imagen y una configuración consideradas sanas;
- restaure únicamente datos comprobados;
- corrija la causa antes de volver a publicar y refuerce la vigilancia.
Una instantánea del servidor sospechoso sirve para preservar o analizar un estado; no se convierte automáticamente en un punto de restauración sano. El CERT-FR recomienda en particular conservar las pruebas, limitar la propagación, poner a salvo las copias y sustituir un sistema comprometido por uno nuevo o reinstalado. Consulte Los buenos reflejos en caso de intrusión.
El NIST SP 800-61 revisión 3, publicado en abril de 2025, integra la respuesta a incidentes en el conjunto de la gestión del riesgo: preparación, detección, respuesta y recuperación no empiezan el día del ataque.
Calendario de explotación recomendado
| Frecuencia | Acciones |
|---|---|
| continua | disponibilidad externa, métricas, alertas de seguridad, fallos de copia |
| diaria | actualizaciones de seguridad, copia, comprobación de servicios fallidos |
| semanal | revisión de alertas, puertos, espacio, cuentas y cambios |
| mensual | revisión de repositorios, paquetes, claves, reglas de cortafuegos y versiones |
| trimestral | restauración completa probada, consola de rescate, ejercicio de incidente |
| semestral | revisión de arquitectura, privilegios, RPO/RTO y exposición externa |
| en cada cambio | copia, validación, escaneo externo, documentación y vuelta atrás |
Para varios VPS, gestione esta base con Ansible, un repositorio versionado y una CI que compruebe la sintaxis. Los secretos deben quedar fuera del repositorio. Una configuración declarativa no sustituye a las pruebas en el entorno real, pero hace más controlables las desviaciones y las vueltas atrás.
Errores frecuentes
- Cerrar SSH antes de probar la clave. Mantenga una sesión y la consola del proveedor.
- Abrir UFW para el puerto 22 cuando SSH escucha en otro. Compruebe
sshd -T. - Nombrar un fragmento SSH que cargue tarde. Suele ganar el primer valor; compruebe la configuración efectiva.
- Olvidar IPv6. Escanee y filtre IPv4 e IPv6 por separado.
- Creer que UFW filtra Docker automáticamente. Los puertos publicados exigen un control específico.
- Instalar Fail2ban sin comprobar la jaula. Revise
status sshdy los registros. - Activar un sysctl genérico. Un ajuste de red puede romper la VPN, el enrutamiento o los contenedores.
- Copiar al mismo disco. Una avería o un compromiso se lleva el original y la copia.
- No restaurar nunca. Un trabajo en verde no garantiza ni la contraseña, ni la coherencia, ni el plazo.
- Guardar todos los registros localmente. root puede borrarlos; envíe los eventos críticos.
- Ejecutar la aplicación como root. Un fallo aplicativo se convierte de inmediato en un compromiso del sistema.
- Confundir versión original y estado de una CVE. Consulte el rastreador de la distribución.
Preguntas frecuentes
¿Cambiar el puerto SSH asegura el VPS?
Reduce el ruido de los escaneos oportunistas y el volumen de registros, pero no añade ninguna barrera de autenticación. Una clave protegida, una cuenta sin root, la restricción de red y los parches son prioritarios.
¿Sigue siendo útil Fail2ban si las contraseñas SSH están desactivadas?
Puede reducir el ruido y algunos intentos repetidos. Su importancia disminuye si SSH solo es accesible por VPN o desde una lista de direcciones, pero no sustituye a ninguna de esas medidas.
¿Hace falta un antivirus en Linux?
Depende del servicio. ClamAV puede analizar archivos subidos o correo. Un agente EDR puede aportar telemetría y respuesta en un servidor sensible. Ningún antivirus compensa un sistema sin parches, una aplicación como root o secretos expuestos.
¿UFW o nftables?
UFW se adapta a una política sencilla y es la herramienta predeterminada documentada por Ubuntu. nftables es el marco nativo recomendado por Debian y ofrece más control. Elija un único propietario del conjunto de reglas y tenga en cuenta Docker.
¿Se puede desactivar IPv6?
No es una medida genérica de endurecimiento. Filtre y vigile IPv6 igual que IPv4. Desactivar IPv6 puede romper dependencias y ocultar una mala comprensión de la red.
¿Basta con una instantánea del proveedor?
Una instantánea es valiosa para una vuelta atrás rápida, pero suele permanecer en el mismo dominio de administración y su coherencia aplicativa debe verificarse. Conserve además una copia versionada fuera del sitio, con una copia fuera de línea o inmutable según el riesgo. Nuestras copias deslocalizadas opcionales van más allá de una simple instantánea, ya que son diarias y se almacenan en otro datacenter, pero siguen gestionándose desde su cuenta de cliente: frente al riesgo de compromiso, conserve una copia en un dominio de administración distinto.
¿Cómo saber si el VPS está comprometido?
No existe un comando único. Correlacione conexiones, procesos, cuentas, claves, tareas, registros remotos, modificaciones de archivos, tráfico y alertas. Ante una duda seria, preserve las pruebas, revoque los secretos y reconstruya desde una base sana.
¿Pueden las actualizaciones automáticas romper la producción?
Todo cambio conlleva riesgo. El riesgo de no aplicar un parche suele ser mayor, pero una aplicación crítica exige preproducción, ventanas de mantenimiento, retenciones puntuales cuando estén justificadas, supervisión y vuelta atrás. Ubuntu precisa que unattended-upgrades no es una herramienta completa de gestión de flota.
¿Esta guía hace que el VPS cumpla con la ANSSI o con CIS?
No. Se apoya en principios y fuentes reconocidos, pero el cumplimiento exige un alcance, un nivel, pruebas, excepciones y una auditoría. Los benchmarks deben adaptarse al papel del servidor; aplicarlos de forma automática puede interrumpir funciones legítimas.
Lista de comprobación final
Identidades y SSH
- una cuenta nominativa por administrador;
- claves Ed25519 o FIDO2 protegidas;
sudoprobado;PermitRootLogin noefectivo;- contraseña y keyboard-interactive desactivados si no se usan;
- grupo SSH autorizado explícitamente;
- configuración validada con
sshd -tysshd -T; - consola de rescate probada.
Sistema y red
- distribución aún mantenida;
- parches instalados y automatización supervisada;
- repositorios de terceros inventariados;
- puertos IPv4 e IPv6 justificados;
- cortafuegos local activo;
- cortafuegos de red configurado si está disponible;
- publicaciones de Docker verificadas desde Internet;
- servicios innecesarios desactivados.
Reducción del impacto
- aplicaciones bajo cuentas dedicadas;
- AppArmor activo y denegaciones examinadas;
- servicios systemd aislados según sus necesidades;
- secretos con privilegios mínimos;
- permisos y claves revisados;
- sysctl adaptados al papel, sin copia ciega.
Detección y recuperación
- registros persistentes con límite de espacio;
- reloj sincronizado;
- eventos críticos enviados fuera del VPS;
- auditd y AIDE si el riesgo lo justifica;
- supervisión externa y canal de alerta distinto;
- copias cifradas, versionadas y fuera del sitio;
- derechos de borrado separados o almacenamiento inmutable;
- restauración real probada y cronometrada;
- procedimiento de incidente y contactos disponibles sin conexión.
Para ir más lejos
Esta guía es la base transversal. Los procedimientos detallados están en nuestras guías dedicadas: configurar una clave SSH, configurar UFW, instalar Fail2ban, instalar Docker e instalar un certificado Let's Encrypt con Certbot. Si viene de un alojamiento compartido, nuestra guía para migrar un sitio a un VPS describe el cambio completo.
Fuentes principales
Recomendaciones generales
- ANSSI: recomendaciones de configuración de un sistema GNU/Linux
- ANSSI: copia de seguridad de los sistemas de información
- CERT-FR: los buenos reflejos en caso de intrusión
- NIST SP 800-61 Rev. 3: Incident Response Recommendations
Debian y Ubuntu
- Debian 13 «trixie»
- Debian Administrator's Handbook
- Debian: nftables
- Ubuntu: ciclo de vida
- Ubuntu Server: OpenSSH
- Ubuntu Server: cortafuegos
- Ubuntu Server: AppArmor
- Ubuntu Server: actualizaciones automáticas
