ssh: Could not resolve hostname con un alias de config

Escribes el alias que definiste en ~/.ssh/config para abrir un túnel hacia una base de datos y ssh responde que no lo conoce:

PS> ssh -N -L 5436:localhost:5432 mi_alias_db
ssh: Could not resolve hostname mi_alias_db: Host desconocido.

El texto después de los dos puntos depende del sistema y del idioma (en Windows con idioma inglés suele ser No such host is known.; en Linux, Name or service not known). El escenario es OpenSSH en Windows 11, un archivo config con un servidor intermedio (bastión) mediante ProxyJump y una base de datos PostgreSQL detrás de él, a la que luego te conectas desde DataGrip. Las comprobaciones de este artículo se hicieron con OpenSSH for Windows 9.5 y con OpenSSH 10.3, el que incluye Git para Windows.

Por qué pasa

ssh busca en el archivo de configuración un bloque Host que coincida con el nombre que escribiste. Si ninguno coincide, no falla por eso: trata el nombre como un servidor real, porque la documentación de HostName dice que su valor por defecto es el nombre dado en la línea de comandos. Entonces intenta resolver mi_alias_db por DNS y falla. Por eso este error significa casi siempre que el alias no existe en el archivo que ssh está leyendo.

En este caso, el bloque nuevo del servidor de base de datos se copió de uno existente y conservó el mismo nombre en Host, así que el alias mi_alias_db nunca llegó a definirse:

Host bastion
    HostName bastion.example.com
    User deploy

Host mi_alias_app
    HostName app.example.com
    User deploy
    ProxyJump bastion

# Bloque nuevo copiado del anterior: faltó cambiar el nombre
Host mi_alias_app
    HostName db.example.com
    User postgres
    ProxyJump bastion
    ServerAliveInterval 30

Además, el bloque duplicado no es "config muerta" del todo. El manual de ssh_config establece que, salvo indicación contraria, para cada directiva se usa el primer valor especificado. Los dos bloques con el mismo Host se combinan: lo que el primero ya definió (HostName, User) gana, y el segundo solo aporta lo que al primero le falta (aquí, ServerAliveInterval). Es una mezcla fácil de pasar por alto.

Solución

  1. Mira cómo resuelve ssh el alias, sin conectarse. La opción -G imprime la configuración resultante tras evaluar los bloques Host y Match, y termina:

    :: cmd
    ssh -G mi_alias_db | findstr /b /i "hostname proxyjump"
    
    # PowerShell
    ssh -G mi_alias_db | Select-String '^(hostname|proxyjump|user) '
    
    # Git Bash o Linux
    ssh -G mi_alias_db | grep -E '^(hostname|proxyjump|user) '

    Usa /b en findstr: sin él, la búsqueda de hostname también devuelve líneas como canonicalizehostname false. Ojo con una trampa: con un alias inexistente, ssh -G no da error (termina con código 0). Si la línea hostname repite el alias en lugar de un servidor real, es que ningún bloque coincidió.

  2. Localiza los bloques duplicados. El modo detallado indica qué archivo se lee y qué líneas se aplican:

    ssh -v -G mi_alias_app 2>&1 | Select-String 'Reading configuration|Applying options'

    Debes ver una línea "Applying options for" por cada bloque que coincide. Con el archivo de arriba aparece dos veces (líneas 5 y 11). Con un alias inexistente no aparece ninguna. También puedes listar todas las líneas Host con su número:

    Select-String -Path "$env:USERPROFILE\.ssh\config" -Pattern '^\s*Host\s'
  3. Haz una copia y renombra el bloque. Guarda el archivo antes de tocarlo y cambia el segundo Host por el alias que querías:

    Copy-Item "$env:USERPROFILE\.ssh\config" "$env:USERPROFILE\.ssh\config.bak"
    Host mi_alias_db
        HostName db.example.com
        User postgres
        ProxyJump bastion
        ServerAliveInterval 30

    Si usas un bloque general Host *, déjalo al final: el manual recomienda poner las declaraciones más específicas al principio del archivo y los valores generales al final.

  4. Vuelve a comprobar con -G. Ahora hostname debe ser db.example.com, user debe ser postgres y proxyjump debe ser bastion.

  5. Abre el túnel en su propia consola.

    ssh -N -L 5436:localhost:5432 mi_alias_db

    -N evita ejecutar un comando remoto (sirve solo para reenviar puertos). -L 5436:localhost:5432 reenvía el puerto local 5436 al puerto 5432 de localhost, un nombre que se resuelve desde el servidor al que ssh se conecta, es decir, el de la base de datos. La consola se queda sin mensajes y sin devolver el control: es lo normal; no la cierres mientras uses el túnel. Si el puerto 5436 ya está ocupado, elige otro y úsalo también en el cliente.

    Si el túnel se cae tras un rato inactivo, añade -o ServerAliveInterval=30 al comando o la línea ServerAliveInterval 30 al bloque. El manual explica que, si no llegan datos del servidor en ese intervalo, ssh envía un mensaje para pedir respuesta; el valor por defecto es 0, que no envía nada.

  6. Conecta DataGrip al extremo local del túnel. Crea un origen de datos de tipo PostgreSQL con Host localhost, Port 5436 y tu usuario, contraseña y base de datos. Deja desactivada la opción "Use SSH tunnel" de la pestaña SSH/SSL. La documentación de DataGrip describe los tipos de autenticación del túnel integrado (contraseña, par de claves y "OpenSSH config and authentication agent"), pero no menciona ProxyJump. El soporte de saltos intermedios en el cliente SSH integrado de cada herramienta puede variar, y abrir el túnel con el ssh del sistema evita depender de eso.

Cómo verificar que quedó resuelto

  • ssh -G mi_alias_db muestra el hostname, el user y el proxyjump esperados, y ssh -v -G mi_alias_db muestra una sola línea "Applying options for".
  • Con el túnel abierto, en otra consola: Get-NetTCPConnection -LocalPort 5436 -State Listen debe devolver una fila.
  • En DataGrip, "Test Connection" termina bien. Si tienes psql, puedes probar también desde la terminal:
psql "host=localhost port=5436 dbname=mi_base user=mi_usuario" -c "select 1"

Variantes y errores relacionados

El error nombra un servidor real y no el alias

Si el mensaje dice Could not resolve hostname db.example.com (el valor de tu HostName), el alias sí existe y el problema es otro: un HostName mal escrito, un DNS interno que no resuelve o un bastión inaccesible. Distinguir entre "nombre del alias" y "nombre del servidor" en el mensaje te ahorra buscar en el lugar equivocado.

ssh no lee el archivo que crees

OpenSSH lee config, sin extensión, dentro de la carpeta .ssh de tu usuario. En Windows es fácil que un editor lo guarde como config.txt. La línea "Reading configuration data" de ssh -v -G muestra exactamente qué archivo se leyó. La opción -F permite probar otro archivo de configuración sin tocar el de uso diario.

Un Host * al principio del archivo

Como se usa el primer valor de cada directiva, un bloque general colocado arriba pisa los valores específicos de los bloques siguientes. Ponlo siempre al final.

Probar el salto sin editar el archivo

La opción -J de ssh permite indicar el servidor intermedio en la línea de comandos. Es útil para descartar si el fallo está en el archivo config o en el acceso al bastión (consulta el manual de ssh para la sintaxis).

Resumen

  • "Could not resolve hostname" con un alias significa que ningún bloque Host coincidió y ssh trató el alias como un nombre DNS.
  • Un Host repetido por copiar y pegar un bloque deja sin definir el alias nuevo; además, ssh usa el primer valor de cada directiva y combina los bloques duplicados.
  • Diagnostica con ssh -G alias (el hostname no debe repetir el alias) y ssh -v -G alias para ver qué bloques se aplican.
  • Renombra el bloque correcto, abre el túnel con ssh -N -L 5436:localhost:5432 alias en su propia consola y añade ServerAliveInterval 30 contra cortes por inactividad.
  • En DataGrip, usa una conexión PostgreSQL normal a localhost:5436 en lugar de su pestaña SSH si el cliente integrado no respeta ProxyJump.

Referencias

Comentarios