Volver al índice
root@vps-donweb:~/docs/ssh$

SSH y Seguridad

protocolo SSH-2
herramienta OpenSSH
categoría Seguridad
CONECTAR Comandos básicos de conexión
# Conexión básica
ssh usuario@ip-del-vps

# Especificar puerto (si no es el 22)
ssh -p 2222 usuario@ip-del-vps

# Especificar clave privada
ssh -i ~/.ssh/mi_clave usuario@ip-del-vps

# Conexión con clave y puerto personalizado
ssh -i ~/.ssh/mi_clave -p 2222 usuario@ip-del-vps

# Ejecutar un comando remoto sin abrir sesión
ssh usuario@ip-del-vps "df -h"
ssh usuario@ip-del-vps "systemctl status nginx"

# Copiar archivos con SCP
scp archivo.txt usuario@ip:/ruta/destino/
scp -r carpeta/ usuario@ip:/ruta/destino/

# Sincronizar con rsync (más eficiente que scp)
rsync -avz carpeta/ usuario@ip:/ruta/destino/
CONFIG Archivo de configuración del cliente SSH

Definí alias para no tipear la IP, usuario y clave cada vez. Archivo en ~/.ssh/config (en tu máquina local).

# ~/.ssh/config

# Alias para tu VPS principal
Host donweb
    HostName     123.456.789.0
    User         mi_usuario
    Port         2222
    IdentityFile ~/.ssh/id_ed25519

# Otro servidor
Host staging
    HostName     98.76.54.32
    User         deploy
    IdentityFile ~/.ssh/id_ed25519_staging

# Opciones globales (aplican a todos)
Host *
    ServerAliveInterval 60      # keepalive cada 60s
    ServerAliveCountMax 3
    AddKeysToAgent      yes
# Con esto alcanza con escribir:
ssh donweb
scp archivo.txt donweb:/var/www/

Una de las mejoras de productividad más grandes para trabajar con SSH diariamente.

SESIÓN Comandos dentro de la sesión
# Ver info del servidor conectado
whoami              # usuario actual
hostname            # nombre del host
uptime              # tiempo encendido y carga
uname -a            # kernel y arquitectura

# Ver conexiones SSH activas
who
w
last | head -20     # historial de logins

# Desconectarse
exit
logout
# o Ctrl+D

# Escape para comandos especiales dentro de SSH
# ~.  → desconectar (si la sesión cuelga)
# ~?  → ver todos los escapes disponibles

Si la sesión SSH se cuelga y no responde, escribí Enter ~ . (intro, tilde, punto) para forzar el cierre sin cerrar la terminal.

GENERAR Crear par de claves SSH

Se generan dos archivos: la clave privada (queda en tu máquina, nunca la compartas) y la clave pública (la que se copia al servidor).

# Ed25519 — algoritmo moderno, recomendado
ssh-keygen -t ed25519 -C "mi-email@ejemplo.com"

# RSA 4096 bits — mayor compatibilidad
ssh-keygen -t rsa -b 4096 -C "mi-email@ejemplo.com"

# Con nombre de archivo personalizado
ssh-keygen -t ed25519 -f ~/.ssh/id_donweb -C "donweb-vps"

Te va a pedir una passphrase. Usala — agrega una capa extra de protección si alguien roba el archivo de clave privada.

INSTALAR Copiar la clave pública al servidor
# Método automático (recomendado)
ssh-copy-id usuario@ip-del-vps

# Especificando clave y puerto
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 usuario@ip-del-vps

# Método manual (si ssh-copy-id no está disponible)
cat ~/.ssh/id_ed25519.pub | ssh usuario@ip-del-vps \
  "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# En el servidor: verificar que quedó bien
cat ~/.ssh/authorized_keys

Probá que la conexión con clave funciona ANTES de deshabilitar la autenticación por contraseña.

PERMISOS Permisos correctos en el servidor

SSH es muy estricto con los permisos de archivos. Si están mal, el servidor rechaza la autenticación por clave sin dar demasiadas explicaciones.

# En el servidor, ejecutar como el usuario objetivo
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

# El directorio home tampoco debe ser world-writable
chmod 755 ~

# Verificar permisos actuales
ls -la ~/.ssh/
stat ~/.ssh/authorized_keys

Si la autenticación por clave falla sin motivo aparente, los permisos son lo primero a revisar.

SSH-AGENT Gestionar claves en memoria

El agente SSH guarda la clave desbloqueada en memoria para no pedir la passphrase en cada conexión.

# Iniciar el agente
eval "$(ssh-agent -s)"

# Agregar clave al agente
ssh-add ~/.ssh/id_ed25519

# Agregar con timeout (8 horas)
ssh-add -t 8h ~/.ssh/id_ed25519

# Ver claves cargadas en el agente
ssh-add -l

# Eliminar todas las claves del agente
ssh-add -D

En macOS podés agregar UseKeychain yes en ~/.ssh/config para que el Keychain maneje todo automáticamente.

GESTIÓN Administrar claves en el servidor
# Ver todas las claves autorizadas
cat ~/.ssh/authorized_keys

# Agregar una clave manualmente
echo "ssh-ed25519 AAAA... comentario" >> ~/.ssh/authorized_keys

# Revocar una clave (editar el archivo y borrar la línea)
nano ~/.ssh/authorized_keys

# Ver fingerprint de una clave pública
ssh-keygen -lf ~/.ssh/id_ed25519.pub

# Ver fingerprint de las claves del servidor
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub
HARDENING Configuración segura de sshd

Archivo de configuración del servidor SSH en /etc/ssh/sshd_config. Cada cambio requiere reiniciar el servicio.

# /etc/ssh/sshd_config — configuración recomendada

## Puerto ##
# Cambiar del 22 dificulta ataques automatizados
Port 2222

## Protocolo y algoritmos ##
Protocol                    2
HostKey                     /etc/ssh/ssh_host_ed25519_key
HostKey                     /etc/ssh/ssh_host_rsa_key

## Autenticación ##
PermitRootLogin             no         # nunca root directo
PasswordAuthentication      no         # solo claves SSH
PubkeyAuthentication        yes
AuthorizedKeysFile          .ssh/authorized_keys
PermitEmptyPasswords        no
ChallengeResponseAuthentication no

## Restricciones de acceso ##
MaxAuthTries                3          # máx intentos por conexión
MaxSessions                 5
LoginGraceTime              30         # seg para autenticarse

## Usuarios permitidos (solo los que necesitan) ##
AllowUsers                  mi_usuario deploy

## Comportamiento de sesión ##
ClientAliveInterval         300        # keepalive cada 5 min
ClientAliveCountMax         2
X11Forwarding               no
AllowTcpForwarding          no         # deshabilitar si no usás túneles
PrintMotd                   no
Banner                      none       # no revelar info del servidor

## Logging ##
SyslogFacility              AUTH
LogLevel                    VERBOSE
# Verificar configuración antes de aplicar
sshd -t

# Aplicar cambios
systemctl restart sshd

Si cambiás el puerto o deshabilitar contraseñas, abrí una segunda sesión SSH ANTES de cerrar la actual para asegurarte de que podés reconectarte.

SECUENCIA Orden seguro para deshabilitar login por contraseña

Este es el proceso correcto para no quedarse afuera del servidor.

# PASO 1: Desde tu máquina local, generar y copiar la clave
ssh-keygen -t ed25519 -f ~/.ssh/id_donweb
ssh-copy-id -i ~/.ssh/id_donweb.pub usuario@ip-del-vps

# PASO 2: Probar que la autenticación con clave funciona
# (abrir una NUEVA terminal, no cerrar la actual)
ssh -i ~/.ssh/id_donweb usuario@ip-del-vps

# PASO 3: Recién ahora, deshabilitar contraseñas en sshd_config
nano /etc/ssh/sshd_config
# → PasswordAuthentication no

# PASO 4: Verificar y recargar
sshd -t && systemctl restart sshd

# PASO 5: Verificar desde otra terminal que sigue funcionando
ssh -i ~/.ssh/id_donweb usuario@ip-del-vps
SERVICIO Gestión del servicio SSH
# Ver estado
systemctl status sshd

# Ver logs de autenticación en tiempo real
journalctl -u sshd -f

# Ver intentos de login fallidos
journalctl -u sshd | grep "Failed"
grep "Failed password" /var/log/auth.log | tail -20

# Ver logins exitosos
grep "Accepted" /var/log/auth.log | tail -20

# IPs que más intentos fallidos tienen
grep "Failed password" /var/log/auth.log \
  | awk '{print $11}' | sort | uniq -c | sort -rn | head -10
FAIL2BAN Qué es y cómo instalar

Fail2ban monitorea los logs del sistema y banea automáticamente las IPs que hacen demasiados intentos fallidos. Funciona con SSH, Nginx, y cualquier servicio que genere logs.

apt install fail2ban
systemctl enable fail2ban
systemctl start  fail2ban

Fail2ban agrega reglas a iptables/nftables automáticamente para bloquear las IPs. No requiere configurar el firewall manualmente para que funcione.

CONFIG Configuración recomendada

Nunca editás jail.conf directamente — creás un jail.local que lo sobreescribe. Archivo en /etc/fail2ban/jail.local

# /etc/fail2ban/jail.local

[DEFAULT]
# Tu IP para nunca banearte a vos mismo
ignoreip  = 127.0.0.1/8 ::1 TU_IP_FIJA_AQUI
bantime   = 3600      # baneado por 1 hora (en segundos)
findtime  = 600       # ventana de tiempo para contar intentos
maxretry  = 5         # intentos antes de banear
backend   = systemd   # leer logs de journald

# Protección SSH
[sshd]
enabled  = true
port     = 2222       # tu puerto SSH personalizado
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3          # más estricto que el default
bantime  = 86400      # baneado 24 horas

# Protección Nginx — demasiadas peticiones 4xx
[nginx-http-auth]
enabled  = true
port     = http,https
logpath  = /var/log/nginx/error.log

# Protección contra escaneos de bots
[nginx-botsearch]
enabled  = true
port     = http,https
filter   = nginx-botsearch
logpath  = /var/log/nginx/access.log
maxretry = 2
# Recargar después de editar
systemctl reload fail2ban
GESTIÓN Comandos del día a día
# Ver estado general
fail2ban-client status

# Ver estado de una jail específica
fail2ban-client status sshd

# Ver IPs baneadas actualmente
fail2ban-client status sshd | grep "Banned IP"

# Desbanear una IP manualmente
fail2ban-client set sshd unbanip 123.456.789.0

# Banear una IP manualmente
fail2ban-client set sshd banip 123.456.789.0

# Ver el log de fail2ban
tail -f /var/log/fail2ban.log

# Recargar configuración sin reiniciar
fail2ban-client reload

# Probar un filtro contra un log
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
FILTRO Filtro personalizado para Nginx

Crear un filtro para banear IPs que busquen rutas típicas de ataques. Archivo en /etc/fail2ban/filter.d/nginx-custom.conf

# /etc/fail2ban/filter.d/nginx-custom.conf
[Definition]
failregex = ^<HOST> .* "(GET|POST) /(wp-admin|phpmyadmin|\.env|
             xmlrpc\.php|wp-login\.php|\.git/config)
             HTTP/.*" (200|301|302|404|403)

ignoreregex =
# Agregar jail en jail.local
[nginx-custom]
enabled  = true
port     = http,https
filter   = nginx-custom
logpath  = /var/log/nginx/access.log
maxretry = 1
bantime  = 604800   # 7 días para bots agresivos
USUARIOS Crear y gestionar usuarios del sistema
# Crear usuario con directorio home
adduser mi_usuario          # interactivo, crea home
useradd -m -s /bin/bash mi_usuario  # no interactivo

# Cambiar contraseña
passwd mi_usuario

# Crear usuario sin acceso a shell (para servicios)
useradd -r -s /sbin/nologin mi_servicio

# Ver todos los usuarios del sistema
cat /etc/passwd | grep -v nologin | grep -v false

# Ver usuarios con acceso SSH real
grep "bash\|sh$" /etc/passwd

# Eliminar usuario (sin borrar su home)
userdel mi_usuario

# Eliminar usuario Y su directorio home
userdel -r mi_usuario

# Bloquear usuario (sin eliminarlo)
usermod -L mi_usuario

# Desbloquear
usermod -U mi_usuario
SUDO Configurar acceso sudo seguro
# Agregar usuario al grupo sudo
usermod -aG sudo mi_usuario

# Verificar grupos del usuario
groups mi_usuario
id mi_usuario

# Editar sudoers de forma segura (SIEMPRE con visudo)
visudo

# O crear un archivo específico en /etc/sudoers.d/
visudo -f /etc/sudoers.d/mi_usuario
# Ejemplos de reglas en sudoers

# Acceso sudo completo
mi_usuario ALL=(ALL:ALL) ALL

# Sudo sin contraseña (solo para casos específicos)
deploy ALL=(ALL) NOPASSWD: ALL

# Permitir solo comandos específicos
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, \
                             /usr/bin/systemctl reload nginx

Nunca uses NOPASSWD: ALL en producción salvo que sea un usuario de deploy muy controlado. Es un riesgo de seguridad grande.

GRUPOS Gestión de grupos
# Crear grupo
groupadd webdev

# Agregar usuario a grupo
usermod -aG webdev mi_usuario

# Ver grupos existentes
cat /etc/group
getent group webdev

# Dar al grupo acceso a un directorio web
chown -R www-data:webdev /var/www/mi-sitio
chmod -R 775 /var/www/mi-sitio
chmod g+s /var/www/mi-sitio  # archivos nuevos heredan el grupo

El flag g+s (setgid) en un directorio hace que todos los archivos creados dentro hereden el grupo del directorio, no el del usuario que los crea.

TÚNEL LOCAL Acceder a servicios internos del VPS

Redirige un puerto del servidor al tu máquina local. Útil para acceder a bases de datos, paneles de administración o servicios que no están expuestos públicamente.

# Sintaxis: -L puerto_local:host_remoto:puerto_remoto

# Acceder a MariaDB del VPS desde tu máquina local
ssh -L 3307:127.0.0.1:3306 usuario@ip-del-vps
# Ahora conectás tu cliente MySQL a localhost:3307

# Acceder a una app corriendo en el VPS (sin exponer el puerto)
ssh -L 8080:127.0.0.1:3000 usuario@ip-del-vps
# Ahora abrís http://localhost:8080 en tu navegador

# Túnel en background (sin abrir shell)
ssh -N -L 3307:127.0.0.1:3306 usuario@ip-del-vps &

# Con alias del SSH config
ssh -N -L 3307:127.0.0.1:3306 donweb

Es la forma más segura de trabajar con MariaDB — nunca exponer el puerto 3306 a internet, siempre via túnel SSH.

TÚNEL REMOTO Exponer tu máquina local al servidor
# Sintaxis: -R puerto_remoto:host_local:puerto_local

# Exponer tu app local (puerto 3000) en el VPS (puerto 8080)
ssh -R 8080:localhost:3000 usuario@ip-del-vps

# Útil para mostrar trabajo en progreso sin deploy
ssh -R 8080:localhost:3000 -N donweb

Para que funcione, el VPS debe tener GatewayPorts yes en sshd_config si querés que sea accesible desde internet (no solo desde el propio servidor).

PROXY SOCKS Navegar a través del VPS
# Crear proxy SOCKS5 en tu puerto local 1080
ssh -D 1080 -N usuario@ip-del-vps

# En background
ssh -D 1080 -N -f donweb

# Usar el proxy con curl
curl --socks5 localhost:1080 https://ejemplo.com

Configurable en el navegador como proxy SOCKS5 → localhost:1080. Todo el tráfico sale con la IP del VPS.

MOSH Alternativa a SSH para conexiones inestables

Mosh mantiene la sesión activa aunque cambie tu IP o se corte la conexión momentáneamente. Ideal para conexiones móviles o WiFi inestable.

# Instalar en el servidor
apt install mosh

# Conectar (desde tu máquina, con mosh instalado)
mosh usuario@ip-del-vps

# Con puerto SSH personalizado
mosh --ssh="ssh -p 2222" usuario@ip-del-vps

Mosh usa UDP (puertos 60000-61000). Asegurate de tenerlos abiertos en el firewall si lo usás.

CHECKLIST Hardening completo de un VPS nuevo

Seguí este orden al configurar un servidor nuevo. Cada ítem reduce significativamente la superficie de ataque.

  • Actualizar el sistemaapt update && apt upgrade -y antes de cualquier otra cosa.
  • Crear usuario no-root — nunca trabajar como root directamente. Crear un usuario con sudo.
  • Generar y copiar claves SSH — par Ed25519 desde tu máquina local al nuevo usuario.
  • Probar login con clave — abrir sesión nueva con clave antes de deshabilitar contraseñas.
  • Deshabilitar login con contraseñaPasswordAuthentication no en sshd_config.
  • Deshabilitar login como rootPermitRootLogin no en sshd_config.
  • Cambiar puerto SSH — del 22 a cualquier puerto alto (ej: 2222, 4822).
  • Configurar AllowUsers — listar explícitamente los usuarios que pueden conectarse por SSH.
  • Instalar y configurar UFW — abrir solo los puertos necesarios (SSH, 80, 443).
  • Instalar Fail2ban — proteger SSH y Nginx de ataques de fuerza bruta.
  • Agregar IP propia a ignoreip de Fail2ban — para no banearse a uno mismo.
  • Configurar actualizaciones automáticas de seguridadapt install unattended-upgrades.
  • Deshabilitar servicios innecesariossystemctl list-units --state=running y parar lo que no se use.
  • Revisar puertos abiertosss -tulnp para ver qué está escuchando.
  • Configurar alertas de login — recibir email cuando alguien se conecte por SSH.
MONITOREO Comandos de auditoría y revisión
# Ver todos los puertos escuchando
ss -tulnp
netstat -tulnp

# Ver conexiones activas
ss -tnp state established

# Revisar usuarios logueados ahora
who
w

# Historial de accesos SSH
last -20
lastb -20             # intentos fallidos

# Actividad reciente en el sistema
journalctl --since "1 hour ago" -p err

# Archivos modificados recientemente
find /etc -mtime -1 -type f 2>/dev/null
find /var/www -mtime -1 -name "*.php" 2>/dev/null

# Procesos corriendo como root
ps aux | grep "^root"

# Tareas cron de todos los usuarios
for u in $(cut -f1 -d: /etc/passwd); do \
  crontab -u $u -l 2>/dev/null; done
ALERTAS Notificación de login por email

Recibir un email cada vez que alguien se conecta por SSH. Se agrega al perfil del usuario.

# Instalar mailutils si no está
apt install mailutils

# Agregar al final de /etc/profile o ~/.bashrc del usuario
# (o en /etc/ssh/sshrc para que aplique solo a SSH)
# /etc/ssh/sshrc — se ejecuta al conectarse por SSH
echo "SSH login: $(whoami) desde $(echo $SSH_CLIENT \
  | awk '{print $1}') el $(date)" \
  | mail -s "SSH Login en VPS" tu@email.com

Alternativa más completa: instalar logwatch para recibir un resumen diario de toda la actividad del servidor.