Generar una llave Ed25519
Ejecuta en Windows Terminal, macOS o Linux:
ssh-keygen -t ed25519 -a 100 -C "administracion-terranode" Acepta la ruta propuesta y protege la llave con una frase de paso. Se crearán un archivo privado y otro terminado en .pub. Nunca envíes el privado.
Copiar la llave al VPS
En macOS o Linux:
ssh-copy-id usuario@IP_DEL_VPS Si el comando no existe, muestra la pública con type $env:USERPROFILE\\.ssh\\id_ed25519.pub en PowerShell o cat ~/.ssh/id_ed25519.pub en Linux/macOS. Pega una sola línea en ~/.ssh/authorized_keys del usuario remoto.
Corrige los permisos:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys Probar antes de cambiar SSH
Mantén abierta la sesión actual. Desde otra terminal ejecuta:
ssh -i ~/.ssh/id_ed25519 usuario@IP_DEL_VPS Comprueba además que sudo whoami devuelve root. Si falla, no continúes.
Desactivar contraseñas y root remoto
Crea /etc/ssh/sshd_config.d/99-keys-only.conf:
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no Valida la sintaxis y recarga, sin reiniciar a ciegas:
sudo sshd -t
sudo systemctl reload ssh Abre una tercera conexión para confirmar. Si Ubuntu usa cloud-init, revisa que otro archivo de configuración no reintroduzca PasswordAuthentication; sshd -T muestra los valores efectivos.
Usar varias llaves con un archivo config
En ~/.ssh/config del computador puedes guardar alias:
Host terranode-produccion
HostName 203.0.113.10
User adminweb
IdentityFile ~/.ssh/id_ed25519_terranode
IdentitiesOnly yes Luego basta ssh terranode-produccion. Usa una llave distinta por persona; no compartas archivos privados entre el equipo. Para revocar acceso, elimina únicamente la línea pública de esa persona.
Errores frecuentes
Permission denied (publickey) suele indicar usuario incorrecto, llave equivocada o permisos inseguros. Revisa ssh -v desde el cliente y journalctl -u ssh desde la consola del VPS. Si la llave privada se filtra, elimínala de authorized_keys y genera otra.
Las llaves son una capa del checklist de seguridad de Ubuntu, junto con firewall, parches, privilegios mínimos y backups. Los VPS de Terranode ofrecen consola web para recuperar acceso si una configuración SSH falla.
Cómo funciona la autenticación por llave
El servidor guarda una clave pública y el cliente demuestra que posee la privada correspondiente firmando un desafío. La privada no se copia al VPS ni viaja durante el inicio de sesión. Una frase de paso protege el archivo local si alguien roba el portátil, mientras que un agente puede mantenerla desbloqueada durante una sesión.
Cada persona y dispositivo debería tener una identidad propia. Compartir id_ed25519 por correo o mensajería elimina la trazabilidad: no puedes revocar a un técnico sin cambiar el acceso de todos y tampoco sabes quién usó la cuenta.
Identifica claramente las públicas con comentarios:
ssh-keygen -lf ~/.ssh/id_ed25519.pub
cat ~/.ssh/id_ed25519.pub El comentario al final de la línea no participa en la criptografía, pero ayuda a reconocer ana-portatil-2026 frente a una lista de claves indistinguibles.
Generar llaves en Windows, macOS y Linux
OpenSSH usa el mismo comando en los tres sistemas actuales, aunque la ruta del perfil cambia. En PowerShell:
ssh-keygen -t ed25519 -a 100 -C "ana-portatil-2026" -f "$env:USERPROFILE\.ssh\id_ed25519_terranode" En macOS o Linux:
ssh-keygen -t ed25519 -a 100 -C "ana-portatil-2026" -f ~/.ssh/id_ed25519_terranode El parámetro -a aumenta las rondas usadas para proteger el archivo cuando introduces una frase. No mejora una llave sin frase de paso. Escoge una frase larga y única; no uses la contraseña del VPS.
Lista los archivos sin mostrar la privada:
ls -l ~/.ssh/id_ed25519_terranode*
ssh-keygen -lf ~/.ssh/id_ed25519_terranode.pub En Windows PowerShell puedes usar:
Get-ChildItem "$env:USERPROFILE\.ssh\id_ed25519_terranode*"
ssh-keygen -lf "$env:USERPROFILE\.ssh\id_ed25519_terranode.pub" Nunca pegues en un ticket el archivo sin .pub. Una privada OpenSSH suele comenzar con una cabecera que indica que es una clave privada; si la compartiste, considérala comprometida aunque luego borres el mensaje.
Instalar la pública en la cuenta correcta
La llave autoriza una cuenta concreta del servidor, no todo el VPS de forma abstracta. Si la copias para deploy, no permitirá entrar como root ni como otro usuario.
Con acceso por contraseña temporal en macOS o Linux:
ssh-copy-id -i ~/.ssh/id_ed25519_terranode.pub deploy@IP_DEL_VPS En Windows, o cuando ssh-copy-id no está disponible, puedes canalizar solo la pública:
Get-Content "$env:USERPROFILE\.ssh\id_ed25519_terranode.pub" | ssh deploy@IP_DEL_VPS "umask 077; mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys" Antes de ejecutar, abre la .pub y confirma que contiene una sola línea. En el servidor revisa propietario y modos:
chown -R "$USER":"$USER" ~/.ssh
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
namei -l ~/.ssh/authorized_keys namei -l muestra permisos de cada directorio del camino. Un authorized_keys correcto puede ser rechazado si el directorio personal pertenece a otra cuenta o es escribible por usuarios no confiables.
Probar la identidad exacta antes de endurecer sshd
Fuerza la llave que quieres comprobar para no entrar por accidente con otra cargada en el agente. Usa modo verboso y IdentitiesOnly:
ssh -vv -o IdentitiesOnly=yes \
-i ~/.ssh/id_ed25519_terranode \
deploy@IP_DEL_VPS Busca en la salida que el cliente ofrece esa pública y que el servidor la acepta. Ya dentro, confirma identidad y privilegios:
id
sudo -v
sudo whoami Mantén la sesión original abierta. La prueba debe hacerse en otra ventana porque una conexión ya establecida no demuestra que las nuevas sesiones funcionen.
Si administras el VPS por un puerto no estándar, inclúyelo en la prueba. No cambies a la vez puerto, usuario, firewall y autenticación: si falla, no sabrás qué capa bloqueó la entrada.
Entender los archivos de configuración incluidos
Las distribuciones modernas pueden cargar fragmentos desde sshd_config.d, y otro archivo puede cambiar el valor que acabas de editar. Antes de modificar, consulta las directivas activas y las inclusiones:
sudo grep -RniE '^(Include|PasswordAuthentication|KbdInteractiveAuthentication|PubkeyAuthentication|PermitRootLogin)' \
/etc/ssh/sshd_config /etc/ssh/sshd_config.d
sudo sshd -T | grep -E 'passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitrootlogin' sshd -T muestra la configuración efectiva general. Las reglas Match pueden variar según usuario, grupo u origen; si las usas, consulta el resultado con contexto específico:
sudo sshd -T -C user=deploy,host=vps,addr=198.51.100.20 \
| grep -E 'passwordauthentication|pubkeyauthentication|permitrootlogin' No edites un fragmento generado automáticamente sin saber quién lo recrea. En imágenes cloud, cloud-init puede establecer autenticación durante el aprovisionamiento. Crea un archivo administrado por ti con un nombre y orden claros, y verifica el resultado efectivo.
Desactivar contraseñas con una secuencia recuperable
La seguridad del cambio depende tanto del contenido como del orden. Haz una copia, escribe el fragmento y valida antes de recargar:
sudo cp -a /etc/ssh/sshd_config.d/99-keys-only.conf \
/etc/ssh/sshd_config.d/99-keys-only.conf.bak 2>/dev/null || true
sudo tee /etc/ssh/sshd_config.d/99-keys-only.conf > /dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sudo sshd -t Si sshd -t no devuelve salida y termina correctamente, recarga el nombre de servicio de tu distribución:
sudo systemctl reload ssh
systemctl is-active ssh
sudo sshd -T | grep -E 'passwordauthentication|kbdinteractiveauthentication|permitrootlogin' En algunas distribuciones el servicio se llama sshd. Confírmalo con systemctl status ssh sshd en vez de copiar el nombre a ciegas.
Abre una tercera terminal con la llave. Luego ejecuta una prueba negativa explícita que no use identidades:
ssh -o PubkeyAuthentication=no \
-o PreferredAuthentications=password,keyboard-interactive \
deploy@IP_DEL_VPS Debe rechazar el acceso sin ofrecer una vía útil por contraseña. Solo entonces cierra las sesiones anteriores.
No usar root como cuenta cotidiana
Bloquear PermitRootLogin obliga a identificar primero a una cuenta y eleva después con sudo. Crea un usuario administrativo con grupos mínimos y prueba sus permisos antes de cerrar root:
sudo adduser deploy
sudo usermod -aG sudo deploy
sudo install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
sudo install -m 600 -o deploy -g deploy \
/home/USUARIO_ACTUAL/.ssh/authorized_keys \
/home/deploy/.ssh/authorized_keys Copiar todas las públicas puede ser adecuado durante una migración, pero después revisa cuáles necesita deploy. Para equipos, es mejor añadir la pública de cada persona individualmente y evitar una cuenta compartida. Si la aplicación no requiere shell interactivo, usa una cuenta de servicio separada sin sudo.
sudo no debe convertirse en una contraseña conocida por todos. Mantén cuentas individuales o una solución de acceso que registre identidades; así la baja de una persona no exige coordinar un cambio global.
Usar ssh-agent sin dejar la privada desprotegida
El agente guarda temporalmente una llave desbloqueada y evita escribir la frase en cada conexión. En macOS o Linux:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519_terranode
ssh-add -l En Windows, el servicio OpenSSH Authentication Agent puede habilitarse según la política del equipo y luego recibir la llave con ssh-add. Un agente desbloqueado hereda el nivel de seguridad de tu sesión local: bloquea la pantalla, cifra el disco y elimina la llave cuando termines en equipos compartidos.
ssh-add -d ~/.ssh/id_ed25519_terranode No uses una llave sin frase solo para evitar el agente en un portátil personal. Las automatizaciones sí pueden requerir identidades no interactivas; limítalas desde authorized_keys y protege el sistema que las ejecuta.
Organizar varios servidores con ~/.ssh/config
Un alias evita equivocarte de usuario, puerto o llave y hace que scripts como scp usen la misma configuración. Un archivo de cliente puede contener:
Host tienda-produccion
HostName 203.0.113.10
User deploy
Port 22
IdentityFile ~/.ssh/id_ed25519_terranode
IdentitiesOnly yes
ServerAliveInterval 30
Host tienda-bastion
HostName 10.20.0.15
User deploy
IdentityFile ~/.ssh/id_ed25519_terranode
ProxyJump tienda-produccion Protege el archivo porque revela nombres y topología, aunque no contiene necesariamente secretos:
chmod 600 ~/.ssh/config
ssh -G tienda-produccion | grep -E 'hostname|user|port|identityfile'
ssh tienda-produccion ssh -G muestra la configuración resuelta sin conectarse. Es útil cuando varias secciones Host * y alias aplican opciones distintas.
Restringir una llave de automatización
Una llave usada por un backup no necesita una shell general. En authorized_keys, las opciones se escriben antes de la pública y pueden forzar un comando o bloquear funciones:
restrict,command="/usr/local/sbin/recibir-backup" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... backup-origen restrict desactiva varias capacidades como reenvíos y asignación de terminal. El comando forzado debe validar entradas y escribir solo en la ruta prevista. Prueba la automatización y confirma que una shell interactiva es rechazada.
No reutilices esa llave limitada para administración. Separar identidades por función permite rotar el backup sin tocar accesos humanos y reduce lo que un sistema comprometido puede hacer.
Revocar accesos y responder a una filtración
Eliminar la línea pública corta nuevas autenticaciones, pero no necesariamente una sesión ya abierta. Identifica el comentario o huella antes de editar:
ssh-keygen -lf ~/.ssh/authorized_keys
cp -a ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak
nano ~/.ssh/authorized_keys Después comprueba sesiones y registros:
w
sudo journalctl -u ssh --since '24 hours ago'
sudo last -a | head -30 Si sospechas compromiso, revisa también sudo, tareas programadas, nuevas cuentas, otras llaves y credenciales de aplicaciones. Rotar SSH no revoca tokens copiados desde el servidor ni deshace persistencia añadida por un atacante.
Una llave perdida pero protegida con frase no debe ignorarse. Revócala, genera otra y actualiza su inventario; no puedes saber si la frase resistirá para siempre.
Diagnosticar Permission denied (publickey)
La salida verbosa del cliente y el registro del servidor muestran lados distintos del intercambio. Desde el cliente:
ssh -vvv -o IdentitiesOnly=yes \
-i ~/.ssh/id_ed25519_terranode \
deploy@IP_DEL_VPS Desde la consola del VPS:
sudo journalctl -u ssh -f
sudo sshd -T | grep -E 'authorizedkeysfile|pubkeyauthentication' | Mensaje o síntoma | Qué revisar |
|---|---|
| El cliente no ofrece la llave | Ruta, agente e IdentityFile |
| Ofrece la pública pero se rechaza | Cuenta, authorized_keys y huella |
bad ownership or modes | Propietario y permisos de todo el camino |
| Funciona para un usuario, no otro | La pública está en el home equivocado |
| Funciona por IP, falla con alias | Opciones de ~/.ssh/config |
| Tras recarga acepta contraseña | Otro fragmento o regla Match sobrescribe |
No cambies permisos de todo /home ni uses chmod 777. Corrige el archivo o directorio concreto y vuelve a probar con la sesión de rescate abierta.
Combinar llaves con las demás capas
Las llaves eliminan la adivinación de contraseñas en SSH, pero no corrigen un servicio desactualizado ni una cuenta con sudo excesivo. Mantén parches, limita el firewall, registra accesos y conserva una consola fuera de banda. Fail2Ban puede reducir ruido, aunque con contraseñas realmente desactivadas los intentos no tienen una credencial reutilizable que adivinar.
Haz una revisión periódica de authorized_keys: cada línea debe tener propietario, dispositivo y necesidad vigente. Una llave de un proveedor que terminó el proyecto hace meses es una cuenta pendiente aunque nunca aparezca en /etc/passwd.
Verificar la clave del host y evitar conectarte al servidor equivocado
La llave del usuario demuestra quién eres; la llave del host demuestra a qué servidor te conectas. En la primera conexión, OpenSSH muestra una huella. Aceptarla sin comparar permite que un intermediario o una IP reutilizada se haga pasar por el VPS.
Obtén las huellas desde la consola del proveedor o una sesión confiable:
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
sudo ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub Compara con la que muestra el cliente. Si aparece REMOTE HOST IDENTIFICATION HAS CHANGED, no ejecutes ssh-keygen -R hasta confirmar si el servidor fue reinstalado, cambió de IP o existe un ataque. Revisa la entrada concreta:
ssh-keygen -F IP_DEL_VPS
ssh-keyscan -t ed25519 IP_DEL_VPS ssh-keyscan recupera una pública, pero no autentica por sí mismo que sea la correcta. Verifícala mediante un canal independiente y luego actualiza known_hosts.
En automatizaciones, no uses StrictHostKeyChecking=no como solución permanente. Precarga una huella validada o administra certificados de host; de otro modo la tarea cifra la conexión con cualquier máquina que responda.
Añadir segundo factor sin reactivar contraseñas SSH
Una llave puede combinarse con otro método, pero la configuración debe distinguir autenticación de cuenta y contraseña reutilizable. OpenSSH permite exigir varias credenciales con AuthenticationMethods. La elección del segundo factor depende de la distribución, PAM y tu capacidad de recuperación.
Antes de habilitarlo, prueba el módulo en una cuenta no crítica, conserva consola y excluye de forma consciente automatizaciones que no pueden responder. Un ejemplo conceptual puede exigir pública más teclado interactivo:
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive Esto no es una configuración completa: PAM debe proporcionar el segundo factor y no caer de nuevo en una contraseña ordinaria. Revisa valores efectivos, prueba una segunda sesión y documenta códigos de recuperación. Una mala combinación puede bloquear todas las cuentas incluso con llaves válidas.
Rotar llaves sin interrumpir el acceso
La rotación segura agrega la pública nueva, la prueba y solo después elimina la antigua. Genera otra identidad con comentario y fecha, añádela como una nueva línea y fuerza su uso:
ssh -o IdentitiesOnly=yes \
-i ~/.ssh/id_ed25519_terranode_2026 \
deploy@IP_DEL_VPS Dentro confirma usuario y sudo. Después elimina la línea vieja por su huella o comentario, abre otra sesión y verifica que la antigua es rechazada:
ssh -o IdentitiesOnly=yes \
-i ~/.ssh/id_ed25519_terranode_antigua \
deploy@IP_DEL_VPS No borres el archivo privado antiguo del equipo hasta completar la prueba de rechazo y verificar todos los servidores del inventario. Si la misma pública se instaló en diez VPS, la rotación no termina al actualizar uno.
Automatizar authorized_keys sin duplicar ni borrar accesos ajenos
La automatización debe agregar una pública de forma idempotente y preservar las demás identidades autorizadas. Antes de cambiar, valida que el texto recibido sea una única pública y crea copia.
cp -a ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak
grep -qxF 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... ana-portatil-2026' \
~/.ssh/authorized_keys \
|| printf '%s\n' 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... ana-portatil-2026' \
>> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys No copies el ejemplo literal: usa la pública completa verificada. Herramientas de configuración como Ansible reducen diferencias entre servidores, pero también necesitan una identidad de emergencia y una revisión para no reemplazar el archivo completo con una lista incompleta.
Guarda el inventario de accesos fuera de los VPS. Así puedes responder qué servidores aún confían en una llave comprometida y demostrar la revocación.
Respaldar una llave privada sin multiplicar copias inseguras
Una llave personal puede respaldarse cifrada, pero cada copia aumenta la superficie de robo. En equipos con cifrado de disco y recuperación corporativa quizá sea preferible generar una nueva identidad tras pérdida en lugar de almacenar privadas en carpetas sincronizadas.
No guardes llaves en repositorios, notas compartidas ni el mismo VPS que protegen. Si tu política exige copia, usa un almacén cifrado con acceso individual y prueba que la frase de paso sigue siendo necesaria. Documenta revocación: restaurar una privada antigua que ya fue retirada de authorized_keys no debe reabrir acceso.
Para automatizaciones, respalda preferentemente el procedimiento y la pública autorizada; rota la privada desde el sistema que ejecuta el job. Así la recuperación no depende de repartir un secreto histórico entre operadores.
Evitar el reenvío indiscriminado del agente
ssh -A permite que un servidor intermedio solicite firmas a tu agente mientras la sesión está abierta. La privada no se copia, pero un host comprometido puede usar el agente reenviado para saltar a otros destinos accesibles. No actives ForwardAgent yes de forma global.
Para llegar a un servidor privado a través de un bastión, ProxyJump suele ser mejor: el cliente establece la conexión final y usa localmente la identidad correspondiente.
Host bastion
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_bastion
ForwardAgent no
Host base-privada
HostName 10.20.0.15
User admin-db
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519_db
ForwardAgent no ssh -G base-privada | grep -E 'proxyjump|identityfile|forwardagent'
ssh base-privada Usa llaves distintas si los niveles de riesgo o responsables cambian. Limita el bastión con firewall, parches y registros; no debería alojar aplicaciones públicas innecesarias. Si excepcionalmente necesitas agent forwarding, restríngelo al alias exacto y elimina las llaves del agente al finalizar.
Preparar la recuperación antes de bloquear el último método
La consola web debe probarse antes de necesitarla. Confirma que puedes abrirla, que conoces las credenciales del proveedor y que permite iniciar en modo rescate o editar el disco. Una consola inexistente descubierta después de cerrar contraseñas convierte un error pequeño en reinstalación.
Guarda fuera del VPS los pasos para montar el sistema y corregir authorized_keys o el fragmento de sshd. No copies allí las privadas de todos los administradores. La recuperación necesita acceso al proveedor y una pública nueva verificable.
Si el equipo depende de una sola persona para esa consola, la autenticación técnica no es el único punto de fallo. Define responsable alterno, protege su cuenta con segundo factor y registra quién puede autorizar una recuperación.
Genera Ed25519, protege la llave privada, instala la pública y prueba una sesión nueva. Solo entonces desactiva contraseñas y root remoto. Este orden convierte un cambio delicado en un procedimiento reversible.
Hosting con LiteSpeed, NVMe y soporte 24/7 desde $3/mes.