La primera hora no es opcional
El espacio IPv4 de internet es lo bastante pequeño como para que escanearlo entero le lleve a un desconocido con buenos recursos unos minutos, y a un portátil normal unas horas. Los rangos de hosting están publicados, catalogados y reescaneados constantemente, así que una dirección nueva no es discreta —es una entrada más en una lista que ya existe. En la práctica, el primer intento automatizado de inicio de sesión SSH sobre una máquina recién arrancada llega mucho antes de que termines de leer el correo de bienvenida, y le seguirán miles más desde fuentes no relacionadas entre sí, todas probando las mismas pocas centenas de contraseñas contra los mismos pocos nombres de usuario. Nada de eso va dirigido a ti. Es una máquina que clasifica internet en responde y no responde, y lo único que decide en qué montón acabas es lo que hiciste en la primera hora.
La buena noticia es que el trabajo es aburrido y acotado. Cuatro controles hacen casi todo: autenticarte con claves en lugar de con contraseñas, rechazar todo puerto entrante que no estés sirviendo deliberadamente, aplicar actualizaciones de seguridad sin que nadie te lo pida, y dejar de operar como root. Cada uno lleva unos minutos y ninguno es exótico. Lo que hace que merezca la pena detallarlo específicamente para un servidor offshore no-KYC es la asimetría en el otro extremo —la vía de recuperación. En un proveedor convencional, un sshd_config roto termina en un ticket de soporte, una verificación de identidad y una sesión de consola. Aquí no hay ninguna identidad registrada que comprobar, que es la razón de ser del producto y también el motivo por el que una pulsación de tecla descuidada te cuesta la máquina, y no veinte minutos. Cada paso de abajo está escrito teniendo eso en cuenta.
Qué ataca realmente a un servidor pequeño
En los logs aparecen dos poblaciones muy distintas, y vale la pena separarlas, porque se derrotan con cosas diferentes. La inmensa mayoría es escaneo masivo indiscriminado: bots que recorren el espacio de direcciones buscando SSH que acepte contraseñas, bases de datos vinculadas a 0.0.0.0, paneles de administración con credenciales por defecto, copias de staging olvidadas, aplicaciones web sin parchear con un exploit público. A esta población no le importa para qué sirve tu servidor. No atiende a razones, no se detiene nunca, y la lista de comprobación de esta guía la derrota por completo —no porque la lista sea ingeniosa, sino porque los bots buscan máquinas que se la saltaron, y de esas hay de sobra.
La segunda población es dirigida —alguien que quiere tu máquina en concreto—, y es rara, cara, y casi nunca entra por SSH. Llega a través de la aplicación que desplegaste, una dependencia que no auditaste, una credencial reutilizada, o un portátil que ya estaba comprometido antes de tocar siquiera el servidor. Por eso el endurecimiento no termina en el firewall: las preguntas de verdad pasan a ser con qué usuario corre tu servicio, qué puede alcanzar en saliente, y con qué rapidez aplicas los parches. Vale la pena saberlo mientras planificas: nuestros planes de VPS son de virtualización completa KVM, así que ejecutas tu propio kernel y toda la caja de herramientas —nftables, ufw, namespaces, seccomp, sysctl personalizado— funciona de verdad, algo que no ocurre en los productos "VPS" basados en contenedores, donde el kernel pertenece a otra persona.
SSH: claves, y una sola puerta
La autenticación por contraseña en un puerto SSH público es el mayor riesgo autoinfligido de un servidor alquilado, y eliminarla son los cinco minutos de mayor valor de toda esta guía. Genera un par de claves Ed25519 en tu propia máquina —nunca en el servidor, donde la mitad privada nacería en el mismo host que intentas proteger—, protégela con una frase de contraseña, y cárgala en un agente para que la frase de contraseña te cueste un solo prompt por sesión en lugar de uno por cada inicio de sesión. Sube la mitad pública, confirma que funciona, y solo entonces desactiva las contraseñas. Con PasswordAuthentication no y KbdInteractiveAuthentication no aplicados, los miles de intentos diarios dejan de ser un riesgo y pasan a ser mero ruido: no hay contraseña que adivinar, así que el intento falla antes incluso de resultar interesante.
Root merece su propia decisión. PermitRootLogin prohibit-password conserva el acceso root por clave para emergencias; PermitRootLogin no es más estricto y obliga a que toda sesión pase por una cuenta con nombre y sudo, que es lo que quieres en cuanto más de una persona toque la máquina. Añade AllowUsers para que una cuenta perdida creada por algún paquete nunca pueda convertirse en una vía de acceso. Sacar el demonio del puerto 22 vale la pena, pero seamos honestos sobre el motivo: no es un control de seguridad —cualquiera que escanee tu dirección encontrará el nuevo puerto en segundos—, es higiene de logs, y elimina la gran mayoría del ruido automatizado para que lo que queda en auth.log sean entradas que de verdad merezca la pena leer. Cambies lo que cambies, valídalo con sshd -t antes de recargar, y mantén tu sesión actual abierta hasta que una segunda terminal se haya conectado con éxito. Esa costumbre es la diferencia entre una errata y un servidor perdido.
Denegación por defecto, y la mitad del firewall que nadie configura
Un firewall en un servidor tiene un solo trabajo: hacer que la respuesta a "¿qué está a la escucha aquí?" sea igual a la lista de cosas que has publicado deliberadamente. Deniega por defecto el tráfico entrante, permite el saliente, y luego abre los puertos de uno en uno, cada uno con un motivo asociado. Antes de escribir una sola regla, ejecuta ss -tulpen y lee qué hay ya a la escucha —una instalación por defecto escucha en más puertos de los que la mayoría espera—, y una base de datos o una caché que escucha en 0.0.0.0 en lugar de en 127.0.0.1 es la forma clásica en que un servidor pequeño termina en el dataset de alguien. Vincula primero los servicios locales a loopback; el firewall es tu segunda línea, no la única.
Luego está la mitad que todo el mundo se salta. Todos los planes de aquí incluyen un /64 de IPv6 junto a su IPv4, y la mayoría de los demonios modernos se vinculan sin más a ambas familias. Si tus reglas solo cubren v4, un servicio que crees protegido por el firewall sigue siendo alcanzable por v6 para cualquiera que resuelva la dirección —y el escaneo de IPv6 sobre un prefijo de hosting conocido es completamente rutinario. ufw sí gestiona ambas familias, pero solo cuando IPV6=yes está definido en /etc/default/ufw; verifícalo con ufw status verbose en lugar de darlo por hecho. Docker merece la misma sospecha: publicar el puerto de un contenedor con -p inserta reglas en su propia cadena de iptables, que se evalúan antes que las de ufw, así que un contenedor que creías protegido a menudo está completamente abierto. Vincúlalo explícitamente a 127.0.0.1:port y pon un proxy inverso delante. Sea lo que sea lo que configures, pruébalo desde algún otro punto de internet —una regla que solo se ha leído es una regla que nunca se ha probado.
Actualizaciones que no tienes que recordar
El software sin parchear es la forma en que realmente se pierden la mayoría de los servidores pequeños, y el motivo es humano, no técnico: aplicar parches es una tarea pesada que compite con todo lo demás que tienes que hacer. Automatiza el canal de seguridad y el problema desaparece. unattended-upgrades en Debian y Ubuntu aplica las actualizaciones de seguridad con un temporizador y no se mete en tu camino; limítalo al bloque de seguridad en lugar de a cualquier actualización disponible, para que un lanzamiento rutinario de funciones nunca reinicie tu aplicación a las tres de la madrugada. Esto importa más en una máquina offshore autogestionada que en una plataforma gestionada, porque nadie la parchea por ti y ningún gestor de cuenta te va a escribir un correo sobre un CVE crítico —no hay ninguna dirección de correo registrada a la que llegar.
Las actualizaciones de kernel necesitan un reinicio para surtir efecto, así que decide tu política de reinicios de forma deliberada en lugar de descubrirla sobre la marcha. needrestart te dirá qué servicios siguen corriendo contra bibliotecas ya borradas, y una ventana de Unattended-Upgrade::Automatic-Reboot en la madrugada está bien para un servicio sin estado. Hay una interacción importante: si has seguido nuestra guía de cifrado de disco completo y tu sistema de archivos raíz está cifrado, un reinicio automático se detiene en un prompt de frase de contraseña y se queda ahí hasta que lo desbloquees por red. O bien mantienes desactivados los reinicios automáticos en esas máquinas, o te aseguras de que el desbloqueo remoto está probado y de que vas a estar despierto durante la ventana. Elijas lo que elijas, anótalo —una política que solo vive en tu cabeza deja de existir en cuanto te vas de vacaciones.
Limitación de tasa, fail2ban y el ruido de fondo
Una vez desactivada la autenticación por contraseña, la fuerza bruta contra SSH no puede tener éxito. Vale la pena ser claros sobre qué te aporta una herramienta como fail2ban a partir de ese punto: no una defensa contra las adivinanzas —eso ya es imposible—, sino un log más silencioso, menos CPU gastada en intentos de conexión condenados al fracaso, y un control genuino en las capas donde los secretos sí se pueden adivinar todavía. Apúntalo a los sitios que importan: el formulario de acceso de una aplicación web, el SMTP AUTH de un servidor de correo, una ruta de administración que alguien está enumerando. ufw limit te da un límite barato de tasa de conexión sin ningún software adicional. Un puñado de ajustes de kernel merecen los mismos cinco minutos —SYN cookies activadas, filtrado de ruta inversa activado, respuestas a broadcast ICMP desactivadas, y anuncios de enrutador IPv6 ignorados en un servidor con dirección estática.
Aun así, hay que saber dónde termina el host. Nada de esto sobrevive a un ataque volumétrico, porque una inundación satura la tubería de red mucho antes de molestar a la CPU: cuando los paquetes llegan a tus reglas de nftables, ya han consumido el ancho de banda que intentabas proteger. Por eso una limpieza de tráfico L3/L4 de hasta 1.5 Tbps se sitúa aguas arriba de la flota y está incluida en todos los planes en lugar de venderse como extra, con un escudo L7 opcional para las inundaciones de capa de aplicación que parecen peticiones legítimas. Tu firewall de host se encarga de la precisión; la red se encarga del volumen. Tratar a cualquiera de los dos como sustituto del otro es la forma en que la gente termina llevándose una sorpresa.
El riesgo real aquí es quedarte fuera tú mismo
De todo lo que puede salir mal en esta primera hora, el resultado con diferencia más probable no es una intrusión. Eres tú, al final de una sesión larga, recargando un sshd_config roto o activando un firewall cuya regla de permiso tiene una errata, y descubriendo que la puerta se ha cerrado a tu espalda. En un proveedor convencional eso es una molestia. Aquí merece un respeto real, porque el registro es un nombre de usuario y una contraseña con ocho códigos de recuperación y ningún correo electrónico en ningún punto del proceso, precisamente para que no haya identidad que filtrar —y un proveedor que no puede identificarte tampoco puede identificarte para devolverte a tu servidor. Nadie puede responder por ti. Esa propiedad es el producto funcionando tal como está diseñado, y es la razón por la que las salvaguardas de abajo son costumbres, no sugerencias.
Cuatro de esas salvaguardas no cuestan nada. Toma una instantánea antes de tocar SSH o el firewall, para que una mala recarga sea una reversión y no una reconstrucción. Inscribe una segunda clave pública desde un dispositivo distinto —un teléfono, un portátil de trabajo, una copia fuera de línea—, porque una sola clave en un solo disco está a un café derramado de no ser ninguna clave. Mantén una segunda terminal conectada mientras cambias cualquier cosa que pudiera cortar la primera, y prueba siempre la configuración nueva desde una conexión nueva antes de soltar la antigua. Y acepta dónde termina la escalera de recuperación: las instantáneas viven en el mismo host y son una comodidad de reversión, no una copia de seguridad, así que todo lo que de verdad echarías en falta pertenece a un almacenamiento fuera del host —el complemento de copias de seguridad cifradas diarias, o tus propias copias cifradas en el lado del cliente enviadas a otro sitio. Tu peor caso debería ser redesplegar y restaurar, medido en minutos, y no perderlo todo.
SP·08Qué añadir después, según lo que haga la máquina
La lista de comprobación de arriba es el suelo, y es la misma para toda máquina. Lo que se añade encima depende por completo del trabajo que haga. Un servidor web público quiere TLS, un proxy inverso que lo termine, la aplicación corriendo como usuario sin privilegios, y la base de datos en loopback o en otra máquina completamente distinta. Un extremo VPN tiene una forma diferente —un solo puerto UDP, sin pila web, sin ningún servicio público— y se trabaja de principio a fin en monta tu propia VPN con WireGuard. Un servidor de correo es el más exigente de los tres y necesita control de rDNS sobre la dirección, algo que incluyen todos los planes; autoalojar correo en un VPS offshore cubre la mitad de la entregabilidad. Un relé de Tor es deliberadamente lo contrario de anónimo —es un servicio publicado y contactable— y los compromisos se explican en llevar un relé en un VPS no-KYC. Todo lo que guarde estado privado en reposo también debería estar cifrado, que es un control aparte con sus propios modos de fallo, cubierto en LUKS y desbloqueo remoto.
Vale la pena terminar situando el endurecimiento en el cuadro más amplio, porque es solo uno de tres controles, y los tres fallan de forma independiente. El primero es lo que el proveedor sabe de ti, y aquí es casi nada: un nombre de usuario financiado por un saldo prepago en cripto desde $30.00, sin tarjeta ni documento en toda la cadena —el tema de pagar el hosting de forma anónima. El segundo es qué ley se aplica, que decide dónde está el hardware entre nuestras 6 regiones y no dónde estás tú, y se trabaja región por región en qué ubicación offshore deberías elegir. El tercero es lo que permite la propia máquina, y ese depende solo de ti —ningún proveedor puede configurarlo en tu lugar. Un VPS desde $8.00/mes está en línea en unos 15 min, lo que significa que la hora siguiente es donde se decide la seguridad real del asunto. Gástala con intención.
SP·09Paso a paso
-
01
Despliega, y entra antes que nada
Despliega desde el panel y elige una distribución que de verdad vayas a mantener parcheada —un Debian actual o un Ubuntu LTS es la respuesta aburrida y correcta. Un VPS está en línea en unos 15 min y sus credenciales de root llegan a tu panel. Conéctate de inmediato, pon el sistema completamente al día, y define un hostname para que los logs posteriores sean legibles. En esta máquina no pasa nada más hasta que termines el resto de estos pasos.
ssh root@203.0.113.10 apt update && apt full-upgrade -y hostnamectl set-hostname edge-01 apt install -y ufw unattended-upgrades needrestart
-
02
Sal de root: un usuario con nombre, una clave, y sudo
Genera el par de claves en tu portátil, nunca en el servidor. Luego crea una cuenta con nombre en la máquina, pon la mitad pública en su
authorized_keys, y dalesudo. Abre una segunda terminal e inicia sesión como ese usuario ahora mismo —antes de cambiar nada más, mientras root por SSH todavía funciona como red de seguridad.# on your own machine ssh-keygen -t ed25519 -C "laptop" ssh-copy-id -i ~/.ssh/id_ed25519.pub root@203.0.113.10 # on the server adduser --disabled-password --gecos "" ops usermod -aG sudo ops install -d -m 700 -o ops -g ops /home/ops/.ssh cp /root/.ssh/authorized_keys /home/ops/.ssh/ chown ops:ops /home/ops/.ssh/authorized_keys chmod 600 /home/ops/.ssh/authorized_keys
-
03
Bloquea el demonio SSH —con una segunda terminal abierta
Escribe los cambios en un archivo drop-in en lugar de editar la configuración de fábrica, para que una actualización de la distribución nunca los revierta en silencio. Valida la sintaxis con
sshd -tantes de recargar, recarga, y luego demuéstralo desde una conexión completamente nueva mientras la actual sigue viva. Si la conexión nueva falla, todavía tienes una sesión funcional desde la que deshacerlo. Una trampa propia de la distribución: en Ubuntu 24.04 el demonio se activa por socket, así quePortensshd_configse ignora —define el puerto consystemctl edit ssh.socketen su lugar, o desactiva la unidad de socket.cat > /etc/ssh/sshd_config.d/10-hardening.conf <<'EOF' Port 2222 PermitRootLogin prohibit-password PasswordAuthentication no KbdInteractiveAuthentication no AllowUsers ops X11Forwarding no MaxAuthTries 3 LoginGraceTime 20 EOF sshd -t && systemctl reload ssh # new terminal, do not close the old one: ssh -p 2222 ops@203.0.113.10
-
04
Denegación por defecto en el firewall, en ambas familias de IP
Confirma que IPv6 está activado en ufw, y luego deniega todo el tráfico entrante y abre solo los puertos que sirves deliberadamente —incluido el nuevo puerto SSH, que debe permitirse antes de activar el firewall. Ya que estás, comprueba qué está realmente a la escucha, y mueve a loopback todo lo que debería ser local.
grep IPV6 /etc/default/ufw # must read IPV6=yes ufw default deny incoming ufw default allow outgoing ufw limit 2222/tcp ufw allow 80,443/tcp ufw enable ufw status verbose ss -tulpen # anything on 0.0.0.0 or :: ?
-
05
Activa las actualizaciones de seguridad desatendidas
Activa solo el canal de seguridad, para que los parches lleguen sin que una actualización de funciones reinicie tu aplicación sin avisar. Decide la política de reinicios de forma explícita —y deja desactivados los reinicios automáticos si el sistema de archivos raíz está cifrado y necesita un desbloqueo manual.
dpkg-reconfigure -plow unattended-upgrades cat > /etc/apt/apt.conf.d/51-local <<'EOF' Unattended-Upgrade::Automatic-Reboot "false"; Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; EOF unattended-upgrade --dry-run --debug | tail -20
-
06
Recorta el ruido y ajusta los parámetros del kernel
Añade
fail2banpara las capas donde todavía se puede adivinar un secreto, y define el puñado de valores de sysctl que simplemente son correctos en un servidor público con dirección estática. Esto sale barato, y hace que merezca la pena leer los logs.apt install -y fail2ban cat > /etc/sysctl.d/99-harden.conf <<'EOF' net.ipv4.tcp_syncookies = 1 net.ipv4.conf.all.rp_filter = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.conf.all.accept_redirects = 0 net.ipv6.conf.all.accept_ra = 0 kernel.kptr_restrict = 2 EOF sysctl --system
-
07
Verifica desde fuera, y luego escribe el manual
Confía en la vista desde internet, no en la vista desde dentro de la máquina. Confirma que el puerto SSH antiguo ha desaparecido, que nada inesperado responde, y que el acceso solo por clave está realmente forzado. Después anota los tres datos que necesitarás en tu peor día: dónde vive tu segunda clave, qué instantánea tomaste, y dónde está la copia de seguridad fuera del host.
# from another machine ssh -p 22 ops@203.0.113.10 # must time out or be refused ssh -p 2222 -o PreferredAuthentications=password ops@203.0.113.10 # expected: Permission denied (publickey) ssh -p 2222 ops@203.0.113.10 'sudo ufw status verbose; uptime'


