BitVPS
Checklist de bastionado VPS: los primeros quince minutos en un servidor nuevo
Checklist de seguridad

Checklist de bastionado VPS: los primeros quince minutos en un servidor nuevo

Un servidor nuevo es accesible desde cualquier dirección de internet a los pocos segundos de arrancar, y el primer intento automatizado de inicio de sesión suele llegar antes de que termines de leer el correo con las credenciales. Suena alarmante y en su mayor parte no lo es: la avalancha es indiscriminada, antigua y se detiene por completo con una sola línea de configuración. El fallo caro en una máquina como esta es el otro — quedarte fuera de una caja que nadie puede desbloquearte, porque el proveedor nunca supo quién eras y nunca quiso saberlo. Esta checklist ordena los ocho cambios que importan en la secuencia que evita ambos: primero la salida, luego la puerta, luego el muro, y por último las cosas que olvidaste que estaban escuchando.

Sin KYC, nunca DMCA ignorado Sin registros de tráfico Activo en 60 segundos

Qué ataca de verdad a un servidor nuevo — y qué es lo que realmente te lo quita

Apunta una IPv4 recién asignada a internet y el tráfico no solicitado llega casi de inmediato. No porque nadie te haya visto: todo el espacio de direcciones se barre de forma continua, y un host que responde en el puerto 22 simplemente se suma a una cola que ya estaba en marcha. Durante el primer día, un servidor nuevo típico registra entre varios cientos y varias decenas de miles de intentos de autenticación SSH, casi todos contra root, admin, ubuntu, test y una docena más de nombres predecibles, con contraseñas de una lista que apenas ha cambiado en una década. Parece un ataque. Se parece más al clima.

La distinción importa, porque decide qué controles merecen tus quince minutos. La adivinación de contraseñas a ese volumen no se reduce al desactivar la autenticación por contraseña — se elimina. No queda riesgo residual que gestionar, nada que ajustar, ninguna tasa que vigilar. Mientras tanto, las dos cosas que de verdad les quitan servidores pequeños a sus dueños son poco glamurosas: una aplicación expuesta a internet que ejecuta una versión con una vulnerabilidad publicada desde hace meses, y una credencial que se filtró en otro sitio y que aquí seguía funcionando. Ninguna de las dos es exótica, y ninguna tiene nada que ver con en qué puerto escucha SSH.

Hay un tercer modo de fallo, y en un servidor que nunca te preguntó quién eras es el más común de todos. Te quedas fuera tú mismo. En un proveedor convencional eso es un ticket de soporte molesto: respondes algunas preguntas, demuestras que eres la persona que figura en la factura, y alguien te restablece el acceso. Aquí ese camino no existe — no como una decisión de política tomada a regañadientes, sino porque la identidad que habría que comprobar nunca se recopiló. Lo que existe en su lugar es un acceso ligado a la cuenta y no a una persona: una consola de emergencia KVM-over-VNC en el panel, instantáneas cada hora con siete días de retención, y la posibilidad de arrancar con otra cosa completamente distinta. Con eso basta. Pero solo basta si ya las has usado una vez antes de necesitarlas.

Por eso la checklist de abajo está ordenada por consecuencia y no por moda. Los controles que eliminan toda una clase de ataque van primero, los que reducen el ruido van al final, y el paso que no cuesta nada y te salva la noche — comprobar que todavía puedes entrar — va antes que todos los demás.

Qué preocupa a la genteCómo llega en realidadQué lo detieneQué no lo detiene
Adivinación de contraseñas SSHBarridos automatizados, miles al día, listas de nombres de usuario genéricosPasswordAuthentication no — por completoUn puerto no estándar; una contraseña más larga
Servicio con vulnerabilidad conocidaUn escáner coincide con tu banner de versión semanas después de publicarse el parcheActualizaciones de seguridad automáticas más una política de reinicioUn cortafuegos, si el puerto tiene que estar abierto de todos modos
Credencial reutilizada o filtradaInicio de sesión válido al primer intento, desde una dirección que nunca has vistoAutenticación solo por clave; credenciales únicas por servicioLa limitación de velocidad — un solo intento no es una ráfaga
Servicio interno expuestoBase de datos, caché o endpoint de métricas vinculado a la dirección comodínVincular a loopback; denegación por defecto del tráfico entrante en ambas familiasSuponer que es privado porque nunca lo enlazaste
Perder tu propio accesoBastionas, cierras sesión, y el cambio que hiciste estaba malUna segunda sesión abierta, una instantánea, una consola ya probadaLa confianza

Construye la salida antes de cerrar la puerta

Esta es la secuencia que deja a la gente tirada, y cada paso, por separado, es correcto: editar la configuración de SSH, cambiar el puerto, desactivar el inicio de sesión por contraseña, activar un cortafuegos, recargar el daemon, cerrar la terminal. El error no está en ningún cambio individual. Está en que la sesión desde la que estabas escribiendo era la única prueba de que alguno de ellos funcionaba, y la descartaste antes de comprobarlo.

La regla que hace segura toda la checklist cabe en una frase: mantén abierta la sesión que funciona y demuestra el cambio desde una segunda. Abre una terminal nueva, conéctate desde cero, ejecuta id, escala con sudo. Si funciona, el cambio es real y la primera sesión pasa a ser prescindible. Si falla, todavía tienes una shell con la que deshacerlo. Esto vale para el cortafuegos, para sshd, para la clave de un usuario nuevo, y para cualquier otra cosa que pueda rechazarte en la puerta.

Antes que nada, establece la vía fuera de banda. En el panel de BitVPS, cada fila de servidor tiene un botón Consola que abre una sesión KVM-over-VNC contra la pantalla de la máquina virtual. No es una shell por red — es la pantalla y el teclado de la máquina — así que sigue funcionando cuando sshd no arranca, cuando el cortafuegos descarta todos los paquetes entrantes, y cuando la configuración de red está mal. Ábrela una vez, ahora mismo, en un servidor que no hayas roto. Confirma que te aparece un prompt de inicio de sesión. Eso lleva treinta segundos y es la diferencia entre un error y una caída del servicio.

Toma también una instantánea. Son cada hora, con siete días de retención en todos los planes, y se restauran en unos treinta segundos, lo que reduce el "pegué la regla nft equivocada" de toda una noche de recuperación a una simple reversión. Y para los cambios de los que de verdad no estás seguro, un interruptor de hombre muerto cuesta una sola línea: systemd-run --on-active=10min /usr/sbin/ufw --force disable arma un temporizador que deshace el cortafuegos a los diez minutos a menos que lo canceles. Si las reglas nuevas funcionan, cancelas. Si te dejan fuera, la máquina te deja volver a entrar sin que tengas que estar allí.

SSH: las cuatro directivas que hacen el trabajo — y el archivo que las anula

Genera la clave en tu propia máquina, nunca en el servidor: ssh-keygen -t ed25519 -C "laptop-2026". Ed25519 es la opción por defecto correcta en 2026 — claves cortas, verificación rápida, sin parámetros que puedas elegir mal, y compatible con todos los OpenSSH compilados en la última década. RSA a 4096 bits no es inseguro, simplemente es más grande y más lento sin ninguna ventaja. Pon una frase de contraseña a la clave privada; ssh-agent hace que la escribas una sola vez por sesión, y es lo único que se interpone entre un portátil robado y todos los servidores que tienes.

Copia la mitad pública con ssh-copy-id y confirma que puedes iniciar sesión con ella antes de desactivar nada. Los permisos importan, y OpenSSH es estricto con ellos por diseño: ~/.ssh en 700, authorized_keys en 600, ambos propiedad del usuario. Una clave que falla en silencio casi siempre es un problema de permisos, y sshd -e -d en primer plano te lo dirá en una sola línea.

Después, cuatro directivas en /etc/ssh/sshd_config hacen prácticamente todo el trabajo. Todo lo demás en ese archivo es cuestión de preferencia.

DirectivaPonla enQué haceQué se rompe si te equivocas
PasswordAuthenticationnoElimina por completo las contraseñas como método de inicio de sesión — toda la avalancha de fuerza bruta se vuelve imposible, no solo más lentaTe quedas fuera si tu clave nunca llegó a instalarse de verdad. Pruébalo antes, en una segunda sesión
KbdInteractiveAuthenticationnoCierra la segunda puerta a la misma habitación — la vía interactiva por teclado de PAM todavía puede aceptar una contraseña aunque la primera directiva esté activadaRompe las configuraciones legítimas de doble factor que dependen de PAM. Déjala activada solo si usas una
PermitRootLoginprohibit-passwordRoot todavía puede iniciar sesión con una clave (útil para automatización) pero nunca con una contraseñano es más estricto y está bien — siempre que tu usuario sudo funcione. Verifícalo primero
PubkeyAuthenticationyesEl método que conservas. Aquí es mejor ser explícito que confiar en el valor por defectoNada, pero merece la pena dejarlo explícito para que una edición futura no lo elimine sin darte cuenta
AllowUsers / AllowGroupstu usuario o grupoOpcional, y la línea opcional de mayor valor — el daemon rechaza a cualquier otra cuenta antes de la autenticaciónUn error tipográfico deniega a todo el mundo. Configúrala en último lugar, y desde una segunda sesión

Ahora viene la parte que atrapa incluso a gente con experiencia. En Debian 12, Ubuntu 22.04 y todo lo posterior, /etc/ssh/sshd_config empieza con Include /etc/ssh/sshd_config.d/*.conf, y OpenSSH usa el primer valor que obtiene para cada palabra clave. Las imágenes cloud traen archivos drop-in en ese directorio — normalmente uno que fija PasswordAuthentication yes — y como el include está al principio, ese drop-in gana a la línea que editaste con cuidado doscientas líneas más abajo. El archivo dice una cosa y el daemon hace otra.

La solución es no confiar nunca en el archivo. Pregúntale al daemon qué resolvió en realidad: sshd -T | grep -Ei 'passwordauth|permitrootlogin|kbdinteractive|pubkeyauth' imprime la configuración efectiva después de aplicar cada include, cada bloque match y cada valor por defecto. Ese único comando vale más que el resto de esta sección. Combínalo con sshd -t, que valida la sintaxis y sale con un código distinto de cero si hay un error, y solo entonces systemctl reload ssh — un reload no altera las sesiones existentes, así que incluso un reload equivocado deja viva tu shell actual.

En cuanto a mover SSH del puerto 22: elimina quizá el 95% de tu volumen de registros y cero por ciento de tu riesgo. Cualquier escáner que merezca preocuparte barre los 65,535 puertos completos, y los que no lo hacen de todas formas nunca iban a superar la autenticación solo por clave. Muévelo si el ruido te molesta o si mantiene callada una alerta de monitorización, pero no lo cuentes como un control de seguridad — y si lo mueves, mantenlo por debajo de 1024, porque solo los procesos con privilegios pueden vincularse a esos puertos, así que nada sin privilegios puede ocupar el puerto si el daemon llega a detenerse.

El cortafuegos: denegar el tráfico entrante por defecto, y la mitad que todo el mundo olvida

En un servidor de propósito único, el cortafuegos tiene un solo trabajo: hacer que el conjunto de puertos accesibles sea igual al conjunto de puertos para los que puedes nombrar un motivo. Denegar el tráfico entrante por defecto, permitir el saliente, permitir que vuelvan las conexiones establecidas y relacionadas, y luego abrir las dos o tres cosas que de verdad ejecutas. Si usas Debian o Ubuntu, ufw son cuatro comandos y es la opción correcta; si prefieres tener un único archivo de reglas legible, nftables es la respuesta moderna dentro del kernel, y es lo que hay debajo escribiendo las reglas de ufw.

El orden importa en un único punto: permite tu puerto SSH antes de activar la política. ufw allow 22/tcp, luego ufw default deny incoming, luego ufw enable. Si lo inviertes, el paso de activación corta la sesión desde la que estás escribiendo — algo sobrevivible si ya hiciste la sección anterior y todavía tienes una consola, y si no, es la forma clásica de terminar la noche antes de tiempo.

La mitad olvidada es IPv6. Aquí, todos los servidores vienen con un /64 enrutado, y los servicios se vinculan a ambas familias por defecto. Un conjunto de reglas escrito solo con iptables gobierna IPv4 y no dice absolutamente nada sobre IPv6, así que la base de datos que protegiste con tanto cuidado sigue siendo accesible desde todo internet a través del otro protocolo. ufw gestiona ambas cuando IPV6=yes está activado en /etc/default/ufw (el valor por defecto en las versiones actuales — compruébalo, no lo des por hecho), y nftables esquiva el problema de forma estructural: un conjunto de reglas table inet cubre ambas familias con un solo juego de reglas. Si vas a escribir a mano una sola línea de configuración de cortafuegos, que sea esa.

Luego está Docker, que no tanto evita tu cortafuegos como llega por debajo de él. Publicar un puerto con -p 5432:5432 inserta reglas DNAT en la tabla nat, y esas se evalúan antes de las cadenas de filtro que gestiona ufw. El resultado es un contenedor accesible desde internet mientras ufw status muestra el puerto como cerrado, y cada año esto sorprende a gente que ejecuta una base de datos en un contenedor detrás de lo que creían que era una política de denegar todo. Publica en loopback en su lugar — -p 127.0.0.1:5432:5432 — o pon el contenedor en una red interna y accede a él desde otro contenedor por nombre.

Lo que creesLo que es cierto en realidadCómo comprobarlo con un comando
"El cortafuegos deniega todo lo que no permití"Cierto solo para IPv4, si escribiste reglas exclusivas de IPv4ip6tables -L -n or nft list ruleset
"La base de datos no está expuesta, está en un contenedor"Un puerto publicado es accesible sin importar la política de filtradodocker ps --format '{{.Ports}}'
"No hay nada escuchando en ese puerto"Algo se reinició y volvió a vincularse a él después de la última vez que mirastess -tulpn
"El puerto está cerrado, mi escaneo lo dice"Un escaneo desde la propia máquina prueba loopback, no internetEscanea desde un segundo host, o desde tu portátil

Qué está escuchando en realidad — el comando que acaba con las suposiciones

Un solo comando responde a la pregunta más útil sobre la exposición de un servidor: ss -tulpn. Lista todos los sockets TCP y UDP a la escucha junto con el proceso que los posee, y la columna que importa es la dirección local. 127.0.0.1:5432 significa que solo esta máquina puede conectarse. 0.0.0.0:5432 significa que puede hacerlo cualquier dirección que alcance la máquina, sujeto solo al cortafuegos. [::]:5432 significa lo mismo por IPv6, y es la línea que la gente se salta de un vistazo.

Los culpables habituales son siempre el mismo puñado. Redis, que durante la mayor parte de su historia se vinculaba ampliamente y venía sin autenticación. PostgreSQL y MySQL, cuando alguien editó un archivo de configuración para aceptar conexiones "desde la app" y la app se mudó de sitio. MongoDB y Elasticsearch, que entre los dos han producido una década de titulares sobre exposición de datos exactamente por este motivo. Memcached, cuyo listener UDP se convirtió en un amplificador de ancho de banda muy popular. Prometheus node_exporter, que con gusto le contará los detalles internos de tu host a quien se lo pregunte. La API de Docker en el puerto 2375, que es ejecución remota de código disfrazada de interfaz REST. Y un servidor de desarrollo que alguien arrancó "solo un minuto" en un panel de tmux hace once meses.

La regla es simple y no exige criterio: si un servicio no necesita ser accesible desde internet, vincúlalo a loopback. Todo lo que tú necesitas para acceder a él sigue funcionando — ssh -L 5432:127.0.0.1:5432 user@server te da un puerto local que tunelea sobre la conexión en la que ya confías, y si varias máquinas necesitan acceso, una interfaz privada de WireGuard les da un rango de direcciones que nunca toca la internet pública. Ninguna de las dos opciones cuesta nada, y ambas eliminan el servicio de la superficie de ataque por completo en lugar de limitarse a defenderlo.

Verifica desde fuera, no desde dentro. Que tu propia máquina informe de un puerto como filtrado es una afirmación sobre tu propia pila loopback; que una segunda máquina no pueda alcanzarlo es una prueba. Conéctate desde tu portátil, o desde otro servidor, y comprueba los puertos que esperas que estén abiertos y uno que esperas que esté cerrado — una prueba que solo puede salir bien no es una prueba.

ServicioValor por defecto habitualQué entrega una instancia expuestaLa solución
RedisVinculación amplia, históricamente sin contraseñaLectura/escritura completa, y una vía muy conocida para escribir archivos como el usuario redisVincula a loopback; configura requirepass; mantén activado protected-mode
PostgreSQL / MySQLLoopback, hasta que alguien lo editaTodo tu conjunto de datos, si una credencial es débil o está reutilizadaVincula a loopback; accede por SSH o WireGuard
Docker APIDesactivada — a menos que un tutorial la activaraEjecución de código equivalente a root en el hostNunca la expongas; usa un contexto SSH en su lugar
node_exporter / metricsTodas las interfaces, puerto 9100Nombres de host, puntos de montaje, versiones, procesos en ejecuciónVincula a loopback; recoge las métricas por la interfaz privada
Envío de correo, paneles de administración webTodas las interfaces por necesidadUna superficie de adivinación de contraseñas que las claves no pueden protegerAquí es donde la limitación de velocidad de verdad tiene su sitio

Fail2ban y CrowdSec: cuánto valen una vez que las contraseñas ya no existen

Este es el elemento que la mayoría de las checklists ponen cerca del principio y que la mayoría de los operadores sobrevaloran, así que merece la pena ser precisos. Con PasswordAuthentication no, una adivinación de contraseña no puede tener éxito — no raramente, no con dificultad, sino nunca. Bloquear una dirección tras cinco fallos no hace más imposible una autenticación que ya es imposible. Lo que fail2ban te da a nivel de SSH es un auth.log más silencioso, algo menos de CPU gastada en establecer conexiones, y gráficas de monitorización más fáciles de leer. Esos son beneficios reales. Son higiene operativa, no un control de seguridad, y catalogarlos bajo el epígrafe equivocado es la forma en que la gente termina con un archivo de registro bastionado y una aplicación sin parchear.

Donde esta clase de herramienta de verdad se gana su sitio es en cada capa donde todavía existe una contraseña: un formulario de inicio de sesión de una aplicación web, un puerto de envío de correo, un admin de Nextcloud o de WordPress, un servidor IMAP. Esas capas no se pueden pasar a autenticación por clave pública, así que la adivinación sigue siendo posible y la limitación de velocidad es la defensa real. CrowdSec añade encima una fuente de reputación compartida, que resulta genuinamente útil en la capa HTTP — te beneficias de direcciones que otras personas ya han visto comportarse mal — y casi irrelevante en la capa SSH una vez que las claves son obligatorias.

Merece la pena nombrar dos trampas típicas. La primera es bloquearte a ti mismo, normalmente mientras pruebas algo a las tres de la madrugada; configura ignoreip para incluir tus propios rangos, y recuerda que una dirección compartida o de NAT de operador significa que bloquear a "un atacante" también puede bloquear a varios cientos de personas ajenas al asunto. La segunda es que la herramienta tiene que poder leer los registros que está filtrando: en distribuciones que solo registran en el journal de systemd, el backend de archivo por defecto vigila en silencio un archivo que ya no recibe nada, y la jail se queda ahí, con buen aspecto, sin hacer nada.

La recomendación honesta: instálalo si el ruido te molesta, configúralo para la capa de tu aplicación donde de verdad importa, y no lo cuentes dos veces. Si quieres esa misma tranquilidad sin nada que mantener, MaxStartups y LoginGraceTime en el daemon SSH, junto con la autenticación solo por clave, te llevan la mayor parte del camino y no pueden dejarte fuera de tu propia máquina.

Los parches: el control aburrido que evita la mayoría de los compromisos reales

Lee cualquier informe de incidente que involucre a un servidor pequeño expuesto a internet y el patrón se repite: la vulnerabilidad tenía un parche, el parche llevaba semanas o meses disponible, y nadie lo aplicó. El catálogo de vulnerabilidades explotadas conocidas de CISA es la lectura útil aquí, precisamente porque no es una lista de gravedad teórica — es una lista de cosas que se están explotando activamente ahora mismo, y está dominada por problemas que ya tienen solución publicada. Las actualizaciones de seguridad automáticas son, en consecuencia, los quince segundos de mayor rendimiento de toda esta página.

En Debian y Ubuntu, instala unattended-upgrades, actívalo con dpkg-reconfigure -plow unattended-upgrades, y confirma que el origen de seguridad es el que está seleccionado en /etc/apt/apt.conf.d/50unattended-upgrades. Verifica que hace algo con unattended-upgrades --dry-run --debug, que imprime exactamente qué paquetes tomaría y por qué — la página de la wiki de Debian es la referencia. En Rocky y Alma, dnf-automatic con apply_updates = yes y el timer activado hace el mismo trabajo. Restringirlo al repositorio de seguridad es deliberado: es la configuración que casi nunca rompe nada, que es el único tipo de automatización que la gente deja activado.

Después, decide qué hacer con los reinicios, de forma explícita, porque aquí es donde el control suele filtrarse. Instalar un paquete de kernel nuevo no sustituye el kernel que está en ejecución, y sustituir una biblioteca compartida no reinicia los daemons que ya tenían la copia antigua mapeada en memoria. needrestart en Debian y Ubuntu indica con precisión qué servicios siguen sujetando bibliotecas ya eliminadas; una actualización de kernel necesita un reinicio, punto final, y el live-patching es una función de pago que no va a llegar a una instancia de $8.50. O bien configura Unattended-Upgrade::Automatic-Reboot con un Automatic-Reboot-Time discreto, o pon un reinicio mensual en tu calendario y trátalo como mantenimiento, no como un incidente.

Por último, entiende qué no cubren las actualizaciones automáticas, porque ahí es donde la gente cae. Cualquier cosa instalada fuera del gestor de paquetes le resulta invisible: un binario descargado de un release de GitHub, una dependencia de runtime de lenguaje instalada con pip, npm o cargo, un tema o plugin dentro de una aplicación web, y sobre todo las imágenes de contenedor. Un host que informa de cero actualizaciones pendientes puede estar ejecutando una imagen base construida hace dos años, y nada en la máquina te lo va a decir. Si ejecutas contenedores, reconstruir y volver a descargar según un calendario es parte del parcheo, no una actividad aparte.

SistemaMecanismoQué cubreQué se le escapa en silencio
Debian / Ubuntuunattended-upgrades, solo el origen de seguridadPaquetes de la distribución, aplicados cada nocheEl kernel en ejecución y las bibliotecas mapeadas, hasta un reinicio
Rocky / Almadnf-automatic con apply_updates = yesLo mismo, mediante un timer de systemdEl mismo hueco del reinicio; comprueba con dnf needs-restarting
ContenedoresNada, por defectoNadaTodo — la imagen queda congelada en el momento de construirse
Dependencias del lenguajeNada, por defectoNadaLa superficie de ataque real de tu aplicación

Usuarios, sudo, y las puertas que se vuelven a abrir en silencio

Crea un usuario normal, añádelo a sudo o wheel, instala ahí tu clave, y deja de iniciar sesión como root. El motivo no es que root con una clave sea peligroso en sí mismo — es una cuenta de un solo factor con un nombre universalmente conocido y sin ningún registro de qué humano la usó. Una cuenta con nombre propio más sudo produce un rastro de auditoría, permite que haya más de un operador sin compartir una credencial, y hace que la eventual pregunta de "quién ejecutó eso" tenga respuesta. Eso sí, no le des NOPASSWD para todo y luego reutilices esa cuenta para un servicio web.

Los servicios tampoco deberían ejecutarse como root, y systemd hace que la versión barata de eso sea casi gratis. Un drop-in creado con systemctl edit <unit> que contenga NoNewPrivileges=yes, ProtectSystem=strict, ProtectHome=yes y PrivateTmp=yes confina a un daemon comprometido a una vista de sistema de archivos de solo lectura sin ninguna vía para escalar — cuatro líneas, descritas en la documentación de systemd.exec, que convierten muchas vulnerabilidades de aplicación de "root en el host" en "un error en un registro". systemd-analyze security puntúa cada unidad de la máquina y te dice cuáles merecen los cinco minutos.

Mantén authorized_keys honesto. Una clave por dispositivo, cada una con un comentario que nombre el dispositivo, y borra cualquier cosa que no puedas identificar. Vuelve a leer el archivo después de que se ejecute cualquier herramienta de aprovisionamiento, porque cloud-init, los pipelines de generación de imágenes y los paneles de control añaden todos sus propias entradas, y una clave que tú no añadiste es una clave que no puedes revocar. Lo mismo aplica a las cuentas: un usuario por defecto que dejó atrás una imagen, con una contraseña puesta por un script y nunca usada desde entonces, es un inicio de sesión que no estás vigilando.

El elemento más sutil de esta lista es el reenvío de agente. ForwardAgent yes permite que un proceso en el host remoto use tu clave privada local mientras estés conectado — eso es exactamente para lo que está diseñado, y por eso el root de una máquina que no controlas del todo puede tomar prestada tu clave para llegar a cualquier otro servidor que confíe en ella. Usa ProxyJump (ssh -J bastion target) en su lugar: te da el mismo alcance tunelizando la conexión, y tu clave nunca llega a ser utilizable en el host intermedio. Si tienes que reenviar un agente, hazlo por host en ~/.ssh/config, nunca de forma global.

Copias de seguridad: el control que convierte un mal día en solo una tarde

Todo lo anterior reduce la probabilidad de tener un mal día. Las copias de seguridad deciden cuánto cuesta ese mal día, y en un proveedor que deliberadamente no puede identificarte, importan más de lo habitual: no hay ninguna vía de soporte que reconstruya tu máquina a partir de la copia de otra persona, ningún flujo de recuperación de cuenta que te entregue discretamente una restauración, y ningún registro de facturación con un número de teléfono asociado. Lo que tienes es lo que tú mismo guardaste.

El esquema que funciona no tiene ningún misterio. restic o borg, cifrando en el servidor para que los datos ya sean ilegibles antes de cruzar la red, enviados a una segunda máquina — e idealmente a una segunda jurisdicción, que aquí es una casilla que marcar y no un proyecto, cuando el mismo panel te ofrece Islandia, los Países Bajos, Rumanía y Suiza. Las instantáneas por hora incluidas en todos los planes son una primera línea genuinamente buena y cubren a la perfección el caso de "rompí la configuración hace una hora". No cubren un archivo que borraste hace cinco semanas, y viven en la misma infraestructura que aquello que protegen. Las instantáneas y las copias de seguridad resuelven problemas distintos; usa las dos.

Haz que el repositorio sea append-only. Este es el detalle que separa una copia de seguridad de una simple copia: un servidor comprometido guarda las credenciales de su propio destino de copias de seguridad, y a todo lo que pueda borrar se le va a ordenar que borre. Tanto borg serve --append-only como el rest-server --append-only de restic lo imponen en el lado receptor, de modo que la máquina puede escribir instantáneas nuevas y no puede eliminar las antiguas. Haz la poda desde otro sitio, según un calendario, con una credencial que el servidor nunca ha visto.

Dos últimas cosas, y la gente se salta las dos. La frase de contraseña del repositorio no debe vivir solo en la máquina que protege — apúntala, guárdala en un gestor de contraseñas en otro sitio, trátala como lo que en la práctica es: una frase semilla. Y restáurala una vez. Una copia de seguridad que nunca has restaurado es una hipótesis; la forma habitual de descubrir que una regla de exclusión se saltó en silencio el volcado de la base de datos es durante la recuperación que no te puedes permitir que salga mal. Levanta una instancia Starter, restaura en ella, comprueba los datos, destrúyela. Eso cuesta $8.50 y una hora, y es la única forma de que el resto de esta página llegue a ser un ensayo en lugar de un primer intento.

Contra qué no te protege el bastionado

No protege el disco de alguien que tiene el disco en sus manos. Todos los controles de esta página asumen que el sistema operativo está en ejecución e imponiendo sus propias reglas; ninguno de ellos se aplica a una máquina apagada cuyo almacenamiento ha sido clonado. Ese es un problema distinto con una respuesta distinta — mira cifrado de disco completo, desbloqueo remoto, y qué es lo que realmente recupera una incautación — y el resumen honesto es que el bastionado y el cifrado defienden contra amenazas disjuntas. Hacer uno no hace parcialmente el otro.

No arregla la aplicación que ejecutas. Un servidor puede pasar todas las comprobaciones de esta página y aun así perderse por un foro desactualizado, un endpoint de administración sin autenticación, un motor de plantillas que evalúa la entrada del usuario, o un token subido por error a un repositorio público. El bastionado del host reduce el radio de impacto de un compromiso a nivel de aplicación — que es exactamente para lo que sirve el confinamiento con systemd de más arriba — pero no audita tu código, y la forma más habitual en que se pierde un servidor pequeño sigue siendo algo que instaló el propio operador.

No cambia quién sabe que alquilaste la máquina. Una caja perfectamente bastionada pagada desde una cuenta de exchange con identidad verificada, pedida con un correo personal, es una caja perfectamente bastionada con tu nombre puesto. La capa de seguridad y la capa de identidad son independientes, y la segunda se decide al pagar, no en la shell — lo rastreable que es en realidad el hosting cripto explica dónde se forman realmente esos vínculos.

Y no hace nada contra el análisis de tráfico. Un observador situado para vigilar tus conexiones aprende su forma — momento, volumen, quién habla con quién — sin importar lo bien configurados que estén los extremos. El cifrado esconde el contenido, no la conversación, y ningún ajuste de sshd cambia eso.

La checklist, en el orden en que debes ejecutarla

Ocho pasos. Los primeros cuatro son los quince minutos del título y eliminan categorías enteras de riesgo; los últimos cuatro llevan más tiempo y son lo que separa un servidor que puedes defender de uno que simplemente configuraste. Cada fila incluye cómo sabes que funcionó, porque un paso de bastionado que no verificaste es un paso de bastionado que no diste.

#PasoCómo sabes que funcionó
1Abre la consola del panel, confirma que aparece un prompt de inicio de sesión, toma una instantáneaViste el prompt en un servidor que no estaba roto
2Crea un usuario no root, instala tu clave ed25519, prueba sudoUna segunda terminal inicia sesión como ese usuario y escala privilegios
3Desactiva la autenticación por contraseña e interactiva por tecladosshd -T informa passwordauthentication no
4Cortafuegos con denegación por defecto del tráfico entrante, cubriendo IPv4 e IPv6nft list ruleset muestra ambas familias; un escaneo desde otro host lo confirma
5Audita los sockets a la escucha, revincula los servicios internos a loopbackss -tulpn no muestra ninguna vinculación comodín que no puedas justificar
6Activa las actualizaciones de seguridad automáticas y una política de reiniciounattended-upgrades --dry-run --debug selecciona el origen de seguridad
7Confina los servicios con systemd, ordena authorized_keyslas puntuaciones de systemd-analyze security mejoran; todas las claves tienen nombre
8Copia de seguridad cifrada, append-only y externa, restaurada una vezRestauraste en una instancia desechable y los datos estaban ahí

Nada de esto es exótico, y esa es la cuestión. Los controles que importan en un servidor pequeño son los que eliminan una clase de problema en lugar de gestionarla: sin contraseñas, sin nada escuchando donde no debería, sin paquetes sin parchear, sin una única copia de los datos. Todo lo demás es preferencia, y la preferencia sale barata una vez que los cuatro cambios estructurales están hechos y verificados.

Si estás aprovisionando la máquina ahora mismo en lugar de leyendo por adelantado, la secuencia cabe cómodamente en la primera sesión: despliega una instancia, abre la consola una vez para comprobar que funciona, y ejecuta los ocho pasos en orden antes de instalar nada en absoluto. Un servidor bastionado antes de tener ningún servicio no tiene ningún legado con el que lidiar — que es la única ventaja que tiene una caja nueva, y dura aproximadamente un día.

Respuestas rápidas

Preguntas frecuentes

¿Debería mover SSH del puerto 22?
Elimina la mayor parte del ruido de tus registros y nada de tu riesgo. Los escáneres que importan barren el rango completo de puertos, y los que solo prueban el 22 nunca iban a superar la autenticación solo por clave. Muévelo si el ruido te molesta o si silencia una alerta de monitorización — pero no lo cuentes como un control de seguridad, y recuerda abrir el puerto nuevo en el cortafuegos antes de recargar el daemon.
¿Sigue mereciendo la pena instalar fail2ban si solo permito claves SSH?
A nivel de SSH compra tranquilidad, no seguridad: con PasswordAuthentication no una adivinación no puede tener éxito, así que limitar la velocidad de un inicio de sesión imposible no cambia nada. Se gana su sitio en las capas donde todavía existe una contraseña — un panel de administración web, el envío de correo, un servidor IMAP. Instálalo ahí, configura ignoreip con tus propios rangos para no poder bloquearte a ti mismo, y confirma que está leyendo un registro que sigue recibiendo entradas.
Me he quedado fuera de mi servidor — ¿qué puedo hacer en realidad?
Abre el botón Consola en la fila del servidor dentro del panel. Es una sesión KVM-over-VNC contra la pantalla propia de la máquina, así que funciona cuando sshd no arranca y cuando el cortafuegos descarta todos los paquetes — inicia sesión ahí y deshaz el cambio. Si el sistema no arranca en absoluto, restaura una de las instantáneas por hora (siete días de retención, unos treinta segundos). Lo que no podemos hacer es verificar que eres tú y restablecerte el acceso: no se recopiló ninguna identidad en el registro, así que el acceso ligado a la cuenta es la única vía de recuperación que existe.
¿Necesito un cortafuegos si no hay nada escuchando?
Sí, porque "no hay nada escuchando" es una afirmación sobre este minuto exacto. Una actualización de paquete arranca un daemon, un contenedor publica un puerto, un compañero prueba algo y lo deja en marcha. Una política de denegar por defecto convierte cada uno de esos casos en algo intrascendente en lugar de una exposición de la que te enteras más tarde. Cuesta cuatro comandos, y es el único control de esta página que te protege de tus propios cambios futuros.
PermitRootLogin: ¿debería usar prohibit-password o no?
prohibit-password es la opción por defecto sensata — root todavía puede autenticarse con una clave, lo que mantiene funcionando la automatización y el acceso de emergencia, pero nunca con una contraseña. no es más estricto y correcto si ya has verificado que tu usuario sudo funciona desde una segunda sesión, algo que deberías hacer antes de configurar cualquiera de las dos opciones. La mitad importante es que root nunca debe aceptar una contraseña; que acepte una clave o no es una cuestión de preferencia operativa.
¿Pueden las actualizaciones de seguridad automáticas romper mi servidor?
Rara vez, cuando se restringen al origen de seguridad — ese repositorio existe precisamente para enviar correcciones mínimas sin cambios de comportamiento, y es la configuración que la gente deja activada durante años. El riesgo mayor es el contrario: un operador que desactiva la automatización por una mala noche, y que luego se queda seis meses atrasado. Si alojas algo frágil, activa la descarga automática con aplicación manual, y pon el paso de aplicar en tu calendario en lugar de en tus intenciones.
¿Por qué es accesible mi contenedor Docker si ufw dice que el puerto está cerrado?
Porque publicar un puerto escribe reglas DNAT en la tabla nat, que el kernel evalúa antes que las cadenas de filtro que gestiona ufw — el paquete se redirige a tu contenedor antes de que la política de denegación llegue siquiera a verlo. Publica en loopback con -p 127.0.0.1:5432:5432 y accede por un túnel SSH, o pon el contenedor en una red Docker interna para que no se publique nada en absoluto. Comprobar ufw status nunca lo revelará; ss -tulpn y un escaneo desde otra máquina sí lo harán.
¿Con qué frecuencia debería repetir todo esto?
Los pasos de configuración son cosa de una sola vez. Tres cosas necesitan una revisión recurrente: ss -tulpn después de instalar cualquier cosa que pueda escuchar, authorized_keys cada vez que un dispositivo cambia de manos, y una prueba de restauración más o menos dos veces al año. Todo lo demás, o es automático, o no cambia. Una entrada de calendario cada seis meses que diga "puertos, claves, restauración" cubre toda la carga permanente de esta página.
Aplicar esto

Cargas de trabajo a las que aplica esta guía

Cada tarjeta abre una página específica por carga de trabajo con recomendaciones de dimensionamiento y un FAQ para sysadmins.

Seguir leyendo

Otras guías

Lecturas complementarias que retoman donde esta termina.

¿Ya leíste suficiente? Despliega en 60 segundos

Sin verificación de correo, sin ID, sin cuenta. Elige un plan, paga en cualquier criptomoneda, obtén root.