En esta página
SSH sin miedo
SSH (Secure Shell) es un túnel cifrado entre tu máquina y otra. Sirve para entrar a un servidor, subir archivos, autenticarte contra GitHub y redirigir puertos. Casi todo lo que haces en remoto pasa por aquí.
Qué pasa cuando te conectas
tu máquina servidor
┌──────────────┐ ┌──────────────┐
│ clave privada│ ── canal cifrado ──► │ clave pública│
└──────────────┘ └──────────────┘
Dos verificaciones distintas, que conviene no mezclar:
| Pregunta | Quién la responde | Con qué |
|---|---|---|
| ¿El servidor es de verdad? | tu cliente | host key del servidor |
| ¿Yo soy quien digo ser? | el servidor | tu clave pública |
El detalle clave: tu clave privada nunca viaja. El servidor manda un desafío, tu cliente lo firma con la privada, y el servidor verifica la firma con la pública. Si alguien intercepta la conexión, no puede reusar nada.
Generar un par de claves
ssh-keygen -t ed25519 -C "tu@email.com"
| Parte | Significado |
|---|---|
-t ed25519 | tipo de clave: moderna, corta y segura |
-C | comentario, normalmente el email (para identificarla) |
Te va a preguntar dónde guardarla (Enter = ~/.ssh/id_ed25519) y una
passphrase. Ponla: si te roban el archivo, sin passphrase tienen tu
identidad.
Genera dos archivos:
~/.ssh/id_ed25519 ← privada. NUNCA se comparte.
~/.ssh/id_ed25519.pub ← pública. Se copia a servidores y a GitHub.
Permisos: el 90 % de los problemas
SSH es estricto a propósito: si las claves son legibles por otros usuarios, se niega a usarlas.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
| Archivo | Permiso | Por qué |
|---|---|---|
~/.ssh | 700 | solo tú entras |
| clave privada | 600 | solo tú lees |
| clave pública | 644 | se puede compartir |
~/.ssh/config | 600 | puede tener rutas privadas |
~/.ssh/authorized_keys (servidor) | 600 | mismas razones |
El agente SSH
Si tu clave tiene passphrase, el agente la mantiene desbloqueada durante la sesión para no escribirla en cada operación.
eval "$(ssh-agent -s)" # arranca el agente
ssh-add ~/.ssh/id_ed25519 # carga la clave (pide la passphrase una vez)
ssh-add -l # lista lo cargado
En macOS suele integrarse con el llavero; en Linux, agrega las dos líneas al
~/.bashrc o ~/.zshrc para que arranque solo.
Autorizar la clave
En un servidor
ssh-copy-id usuario@servidor
Eso agrega tu clave pública a ~/.ssh/authorized_keys del servidor. Después:
ssh usuario@servidor
En GitHub
- Copia el contenido de la clave pública:
cat ~/.ssh/id_ed25519.pub - GitHub → Settings → SSH and GPG keys → New SSH key.
- Pega la línea completa y guarda.
Prueba:
ssh -T git@github.com
La respuesta esperada es algo como:
Hi usuario! You've successfully authenticated, but GitHub does not provide shell access.
Ese "no shell access" es normal: GitHub no te da una terminal, solo usa el túnel para autenticar.
La primera conexión: known_hosts
La primera vez que te conectas a un host, SSH te muestra su huella:
The authenticity of host 'ejemplo.com' can't be established.
ED25519 key fingerprint is SHA256:...
Are you sure you want to continue connecting (yes/no)?
Si escribes yes, guarda la huella en ~/.ssh/known_hosts. En las siguientes
conexiones compara: si cambia, corta con un warning enorme. Puede ser que
reinstalaron el servidor… o que hay un ataque. Verificá la huella por un canal
confiable antes de borrar la entrada.
El archivo ~/.ssh/config
Aquí está la diferencia entre "uso SSH" y "uso SSH cómodo". Sirve para poner alias, usuarios, puertos y claves por host.
Host gh
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
IdentitiesOnly yes
Host vps
HostName 203.0.113.10
User laura
Port 2222
IdentityFile ~/.ssh/id_ed25519
Con eso:
ssh vps # en lugar de ssh -p 2222 laura@203.0.113.10
git clone gh:usuario/repo.git # en lugar de git@github.com:usuario/repo.git
IdentitiesOnly yes evita el clásico Too many authentication failures: le dice
a SSH que use solo la clave indicada y no pruebe todas las que tenga el agente.
Cambiar un repo de HTTPS a SSH
git remote -v
git remote set-url origin git@github.com:usuario/repo.git
ssh -T git@github.com
git fetch
Las URL git@github.com:... usan SSH; las https://... usan usuario y token.
No son intercambiables: si copiaste una y tu clave está configurada para la
otra, no va a autenticar.
Copiar archivos
scp archivo.txt usuario@servidor:/ruta/destino
scp -r carpeta usuario@servidor:/ruta/
scp usuario@servidor:/ruta/archivo.txt .
rsync es mejor para carpetas grandes: copia solo lo que cambió y se puede
reanudar.
rsync -avz --progress carpeta/ usuario@servidor:/ruta/
El / final en carpeta/ importa: copia el contenido, no la carpeta.
Túneles: traer un puerto remoto a tu máquina
ssh -L 8080:localhost:80 usuario@servidor
Ahora http://localhost:8080 en tu máquina llega al puerto 80 del servidor.
Muy útil para ver un servicio que solo escucha en la red interna.
ssh -N -L 5433:localhost:5432 usuario@servidor
-N = no ejecutes comandos, solo el túnel (queda en primer plano; Ctrl+C para
cortar). Al revés, -R, expone un puerto tuyo en el servidor.
Reglas de seguridad
| Regla | Motivo |
|---|---|
| La privada nunca sale de tu máquina | con ella, eres tú |
| Passphrase siempre | un archivo robado sin passphrase es acceso total |
| Una clave por propósito (personal, trabajo, GitHub) | si se filtra una, revocas solo esa |
600 en las claves | SSH no las usa si son públicas |
Nunca commitear ~/.ssh | se filtra en el repo y en el historial |
| Rotar si se filtró | borrarla del repo no alcanza: ya está en la historia |
| Verificar huellas la primera vez | evita un ataque de intermediario |
Diagnóstico
ssh -v usuario@servidor # un nivel de detalle
ssh -vvv usuario@servidor # tres niveles: qué clave probó y por qué falló
| Mensaje | Causa | Solución |
|---|---|---|
Permission denied (publickey) | la clave no está autorizada o no se ofrece | ssh-add, revisar authorized_keys |
Bad permissions | permisos abiertos | chmod 600 / chmod 700 |
Too many authentication failures | el agente prueba demasiadas claves | IdentitiesOnly yes en el config |
Connection refused | SSH no escucha en ese puerto | revisar el servidor y el puerto |
Connection timed out | red o firewall | probar otro puerto/red |
Host key verification failed | la huella cambió | verificar y, si corresponde, borrar la entrada |
Could not resolve hostname | nombre mal escrito o DNS | revisar HostName |
Siguiente parada: Bash, Zsh y Fish.
Hecho con amor para Laura, por Bogdan.