Seguridad SSH en servidores VPS: una guía práctica para empezar bien
Seguridad SSH en servidores VPS: una guía práctica para empezar bien
Ahora que estamos desarrollando más aplicaciones gracias a las posibilidades que dan los codificadores agénticos, es más fácil llevar ideas a la vida. Podemos construir prototipos, APIs, sitios internos, automatizaciones y pequeñas plataformas con una velocidad que antes era difícil de imaginar.
Para poner todo eso en línea, muchas veces terminamos usando un VPS. Se consiguen a buenos precios, dan bastante control y permiten ahorrar frente a servicios más administrados. Pero ese ahorro trae un compromiso: si el servidor queda mal configurado, también queda expuesto.
Esta guía busca ayudarte a mejorar la seguridad básica de tus VPS, sobre todo en el acceso por SSH. No pretende cubrir todos los escenarios posibles, pero sí darte una base práctica para empezar con menos riesgos.
La idea principal: no abras todo por comodidad
Un VPS conectado a internet recibe intentos de conexión todo el tiempo. Algunos son simples escaneos automáticos. Otros buscan contraseñas débiles, puertos abiertos, paneles sin protección o bases de datos expuestas.
La regla de partida es simple:
En un VPS no se abre todo “por si acaso”. Se habilitan solo los puertos necesarios, para los usuarios necesarios y desde los orígenes necesarios.
La seguridad no depende de una sola configuración. Conviene pensarla en capas.
| Capa | Pregunta que responde | Herramientas habituales |
|---|---|---|
| Identidad | ¿Quién puede entrar? | Usuarios Linux, llaves SSH, grupos |
| Acceso | ¿Cómo puede entrar? | sshd_config, autenticación por llave, bloqueo de root |
| Red | ¿Por dónde puede entrar? | ufw, reglas por puerto, reglas por IP |
Si una capa falla, las demás deben reducir el daño.
Antes de tocar nada: mantén una salida de emergencia
Antes de cambiar SSH o activar firewall, revisa si tu proveedor permite abrir una consola web de recuperación. Casi todos los proveedores de VPS la tienen.
También trabaja con dos sesiones abiertas:
- Una sesión SSH donde haces los cambios.
- Otra sesión para probar que todavía puedes entrar.
No cierres la sesión original hasta confirmar que la nueva configuración funciona. Este detalle evita muchos sustos.
Paso 1: crea un usuario administrador distinto de root
Entrar como root por SSH es cómodo, pero no es una buena práctica. Lo recomendable es crear un usuario normal con permisos de administración mediante sudo.
Un ejemplo:
adduser devadmin
usermod -aG sudo devadmin
Luego entra con ese usuario:
ssh devadmin@IP_DE_TU_VPS
La idea es que root quede reservado para recuperación o tareas desde la consola del proveedor, no para el acceso diario.
Una separación básica de usuarios podría verse así:
| Usuario | Permisos | Uso recomendado |
|---|---|---|
root | Control total | Recuperación o consola del proveedor |
devadmin | Puede usar sudo | Administración del servidor |
deploy | Sin sudo o con permisos limitados | Despliegues automatizados |
www-data | Sin login SSH | Ejecución del servidor web |
backup | Permisos limitados | Tareas de respaldo |
No entregues sudo a usuarios que ejecutan servicios, agentes o tareas automáticas salvo que exista una razón clara.
Paso 2: usa llaves SSH, no contraseñas
Una llave SSH tiene dos partes:
- La llave privada, que se queda en tu computador y no se comparte.
- La llave pública, que se copia al servidor.
Para crear una llave moderna puedes usar:
ssh-keygen -t ed25519 -C "[email protected]"
Luego copia la llave pública al servidor:
ssh-copy-id devadmin@IP_DE_TU_VPS
Prueba el acceso:
ssh devadmin@IP_DE_TU_VPS
En el servidor, los permisos del directorio .ssh deben ser restrictivos:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Cuando confirmes que puedes entrar con llave, recién tiene sentido desactivar el acceso por contraseña.
Paso 3: endurece la configuración de SSH
El archivo principal suele estar en:
sudo nano /etc/ssh/sshd_config
Una configuración base puede incluir esto:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
X11Forwarding no
AllowTcpForwarding no
AllowUsers devadmin deploy
ClientAliveInterval 300
ClientAliveCountMax 2
Qué significa cada línea:
| Directiva | Para qué sirve |
|---|---|
PermitRootLogin no | Evita entrar directamente como root |
PasswordAuthentication no | Obliga a usar llaves SSH |
PubkeyAuthentication yes | Permite autenticación con llave pública |
KbdInteractiveAuthentication no | Desactiva métodos interactivos parecidos a contraseña |
X11Forwarding no | Cierra una función que no suele usarse en VPS comunes |
AllowTcpForwarding no | Evita túneles SSH si no los necesitas |
AllowUsers devadmin deploy | Limita qué usuarios pueden entrar por SSH |
ClientAliveInterval 300 | Ayuda a cerrar sesiones inactivas |
ClientAliveCountMax 2 | Define cuántas comprobaciones fallidas se toleran |
Antes de reiniciar SSH, valida la configuración:
sudo sshd -t
Si no muestra errores, reinicia el servicio:
sudo systemctl restart ssh
En algunas distribuciones el servicio se llama sshd:
sudo systemctl restart sshd
Después abre una segunda conexión y verifica que puedes entrar. No cierres la primera sesión hasta probarlo.
Paso 4: decide si cambiarás el puerto SSH
Cambiar el puerto SSH no reemplaza las llaves, el firewall ni una buena configuración. Solo reduce algo de ruido de bots que prueban el puerto 22 por defecto.
Si decides usar otro puerto, por ejemplo 2222, agrega esta línea en sshd_config:
Port 2222
Antes de reiniciar SSH, abre ese puerto en el firewall:
sudo ufw allow 2222/tcp
sudo ufw reload
Luego conectas así:
ssh -p 2222 devadmin@IP_DE_TU_VPS
No cambies el puerto SSH sin abrir primero el puerto nuevo. Es una forma rápida de quedarte fuera.
Paso 5: activa UFW con una política cerrada
UFW permite administrar el firewall de forma sencilla. Para la mayoría de VPS, una base razonable es bloquear entradas y permitir salidas.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw limit ssh
sudo ufw enable
sudo ufw status verbose
Si usas un puerto personalizado:
sudo ufw limit 2222/tcp
La diferencia entre allow y limit importa:
| Regla | Efecto |
|---|---|
allow ssh | Permite SSH sin limitar intentos |
limit ssh | Permite SSH, pero limita intentos repetidos desde una misma IP |
deny incoming | Bloquea conexiones entrantes no autorizadas |
allow outgoing | Permite que el servidor salga a internet |
ufw limit no reemplaza llaves SSH ni fail2ban, pero agrega una barrera útil cuando SSH queda expuesto.
Paso 6: restringe SSH por IP si puedes
Si tienes una IP fija o usas VPN, lo mejor es permitir SSH solo desde esa dirección.
sudo ufw allow from TU_IP_PUBLICA to any port 22 proto tcp
Si usas puerto personalizado:
sudo ufw allow from TU_IP_PUBLICA to any port 2222 proto tcp
Luego revisa las reglas numeradas y elimina la regla general de SSH si ya no la necesitas:
sudo ufw status numbered
sudo ufw delete NUMERO_DE_REGLA
Si no tienes IP fija, puedes dejar SSH abierto con limit ssh, pero debes compensar con llaves, fail2ban y revisión de logs.
Paso 7: abre puertos según el tipo de servicio
No todos los VPS deben exponer lo mismo. Un servidor web no necesita abrir los puertos de base de datos. Un servidor de monitoreo no debería publicar todos sus paneles a internet.
VPS solo para administración o agentes remotos
Si el servidor se usa para scripts, bots internos, tareas programadas o herramientas de desarrollo remoto, probablemente solo necesite SSH.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from TU_IP_PUBLICA to any port 22 proto tcp
sudo ufw enable
Si no tienes IP fija:
sudo ufw limit ssh
Servidor web público
Para Nginx, Apache, aplicaciones estáticas o apps detrás de proxy, lo normal es abrir HTTP y HTTPS.
sudo ufw allow from TU_IP_PUBLICA to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Si usas perfiles de UFW:
sudo ufw app list
sudo ufw allow "Nginx Full"
API pública
Si tienes una API en FastAPI, Express, Django, Laravel o similar, evita exponer directamente el puerto interno de la aplicación.
Lo recomendable es usar Nginx o Apache como proxy inverso y abrir solo 80 y 443 al público.
sudo ufw allow from TU_IP_PUBLICA to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
La aplicación debería escuchar en 127.0.0.1, no en 0.0.0.0, si solo será atendida por el proxy.
Base de datos
Una base de datos no debería quedar abierta a todo internet.
| Servicio | Puerto frecuente | Recomendación |
|---|---|---|
| PostgreSQL | 5432/tcp | Abrir solo desde IPs autorizadas |
| MySQL o MariaDB | 3306/tcp | Abrir solo desde IPs autorizadas |
| MongoDB | 27017/tcp | Evitar exposición pública |
| Redis | 6379/tcp | No exponer públicamente |
Ejemplo para PostgreSQL desde un servidor de aplicación:
sudo ufw allow from IP_DEL_SERVIDOR_APP to any port 5432 proto tcp
Ejemplo para MySQL:
sudo ufw allow from IP_DEL_SERVIDOR_APP to any port 3306 proto tcp
Para Redis, si no hay una razón muy clara, bloquea acceso público:
sudo ufw deny 6379/tcp
No uses reglas como sudo ufw allow 5432/tcp salvo que sepas exactamente por qué necesitas exponer ese puerto.
Moodle, WordPress o LMS
En plataformas educativas o sitios con usuarios, lo normal es abrir web y mantener la base de datos cerrada si vive en el mismo VPS.
sudo ufw allow from TU_IP_PUBLICA to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw deny 3306/tcp
Si la base de datos está en otro servidor, permite el puerto solo entre servidores.
sudo ufw allow from IP_DEL_SERVIDOR_MOODLE to any port 3306 proto tcp
Docker
Con Docker hay que tener cuidado. Docker puede publicar puertos aunque UFW parezca restrictivo.
Buenas prácticas:
- No publiques puertos innecesarios con
ports:. - Expón al público solo
80y443si usas proxy inverso. - Usa redes internas de Docker para comunicación entre contenedores.
- No expongas bases de datos en
0.0.0.0.
Ejemplo inseguro para una base de datos:
ports:
- "5432:5432"
Ejemplo más seguro para un servicio interno:
expose:
- "5432"
Además de revisar UFW, mira qué puertos publicó Docker:
docker ps
VPN
Si usas WireGuard u OpenVPN, abre solo el puerto de la VPN y luego limita SSH a la red privada.
WireGuard:
sudo ufw allow 51820/udp
OpenVPN:
sudo ufw allow 1194/udp
Cuando la VPN funcione, puedes permitir SSH solo desde la red VPN:
sudo ufw allow from 10.8.0.0/24 to any port 22 proto tcp
Monitoreo
Herramientas como Grafana, Prometheus o Node Exporter no deberían quedar abiertas sin control.
| Servicio | Puerto frecuente | Recomendación |
|---|---|---|
| Grafana | 3000/tcp | Acceso por VPN o IP autorizada |
| Prometheus | 9090/tcp | Mejor acceso privado |
| Node Exporter | 9100/tcp | No abrir a internet |
Ejemplo para Grafana solo desde tu IP:
sudo ufw allow from TU_IP_PUBLICA to any port 3000 proto tcp
Ejemplo para Node Exporter solo desde el servidor de monitoreo:
sudo ufw allow from IP_MONITOR to any port 9100 proto tcp
Paso 8: instala fail2ban
fail2ban bloquea IPs que realizan muchos intentos fallidos. No reemplaza una buena configuración SSH, pero ayuda a bajar ataques de fuerza bruta.
En Ubuntu o Debian:
sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Verifica el estado:
sudo systemctl status fail2ban
Paso 9: mantén el sistema actualizado
La seguridad no termina el día de la instalación. Un VPS requiere mantenimiento.
sudo apt update
sudo apt upgrade -y
También conviene revisar intentos de acceso.
En Ubuntu y Debian:
sudo journalctl -u ssh
En otros sistemas puede ser:
sudo journalctl -u sshd
Para revisar sesiones recientes:
last
Comandos de consulta rápida
Ver estado del firewall:
sudo ufw status verbose
Ver reglas numeradas:
sudo ufw status numbered
Eliminar una regla por número:
sudo ufw delete NUMERO_DE_REGLA
Ver puertos escuchando en el servidor:
sudo ss -tulpn
Validar configuración SSH:
sudo sshd -t
Reiniciar SSH:
sudo systemctl restart ssh
Checklist antes de cerrar la sesión
Antes de dar por terminado el trabajo, revisa esto:
- Existe un usuario administrador distinto de
root. - El usuario administrador puede usar
sudo. - Los usuarios de servicios o agentes no tienen
sudosi no lo necesitan. - Puedes entrar con llave SSH.
PermitRootLogin noestá configurado.PasswordAuthentication noestá configurado.sudo sshd -tno muestra errores.- UFW está activo.
- UFW bloquea entradas por defecto.
- Solo están abiertos los puertos necesarios.
- SSH está restringido por IP si es posible.
- Las bases de datos no están abiertas públicamente.
- Los paneles internos no están expuestos sin protección.
- Existe una forma de recuperación desde la consola del proveedor.
Cierre
Un VPS seguro no es el que tiene más herramientas instaladas. Es el que expone menos superficie, usa llaves SSH, separa usuarios, restringe privilegios y abre solo los puertos necesarios.
Los codificadores agénticos ayudan a construir más rápido, pero publicar una aplicación también implica hacerse cargo del entorno donde vive. Si vas a usar VPS baratos para ahorrar, está bien. Solo conviene pagar ese ahorro con orden, no con descuido.
Recursos
- Herramientas mencionadas: OpenSSH, UFW, fail2ban, Docker