Un esempio funzionante
Include ~/.ssh/config.d/*
Host web
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
Host *.example.com
User admin
Host *
ServerAliveInterval 60
User user
Ora ssh web significa ssh -p 2222 -i ~/.ssh/id_ed25519_work deploy@203.0.113.10, e invia anche un keepalive ogni 60 secondi. Gli stessi nomi funzionano per scp, sftp e rsync.
Il file è ~/.ssh/config. Non deve essere scrivibile da altri, altrimenti ssh si ferma con Bad owner or permissions. Esegui chmod 600 ~/.ssh/config. Le impostazioni di sistema vengono lette dopo, da /etc/ssh/ssh_config.
Con decine di host il file è solo una parte della risposta. Vedi come gestire molti server SSH per nomi, gruppi e chiavi che restano in ordine.
Vince il primo valore
È la regola che sorprende le persone. Ogni blocco Host che corrisponde si applica, non solo il primo. Per ogni opzione, ssh tiene il primo valore che legge e ignora i successivi. Nell'esempio:
ssh webottieneUser deploy, perché il suo blocco viene prima diHost *.ssh db.example.comottieneUser admin.ssh otherottieneUser user, e tutti e tre ottengonoServerAliveInterval 60.
Quindi metti gli host specifici in alto e i valori predefiniti in fondo. Se sposti Host * in alto, il suo User vince ovunque. Le opzioni sulla riga di comando vengono prima di tutto, quindi ssh -l other web, ssh other@web e ssh -p 3000 web sovrascrivono il file.
C'è un'eccezione da conoscere. IdentityFile si accumula: un valore in Host web-* e un altro in Host * vengono provati entrambi, in ordine. Aggiungi IdentitiesOnly yes se vuoi evitare le chiavi dell'agent, e lascia IdentityFile fuori da Host * se vuoi una chiave per host.
Pattern di Host
| Pattern | Corrisponde a |
|---|---|
Host web db | Uno qualsiasi dei due nomi. |
Host *.example.com | Qualsiasi nome che finisce con .example.com. |
Host web-? | web- e un carattere. |
Host web-* !web-old | Tutti i nomi web- tranne web-old. Una negazione da sola non corrisponde a nulla: esclude soltanto da una corrispondenza positiva. |
Il pattern viene confrontato con ciò che digiti, non con l'indirizzo a cui si risolve. %h sta per quel nome, il che permette nomi brevi:
Host web-*
HostName %h.example.com
ssh web-1 ora si connette a web-1.example.com.
Include
Include ~/.ssh/config.d/*
Legge altri file come se fossero incollati in quel punto, il che ti permette di tenere un file per progetto. I percorsi relativi partono da ~/.ssh. Richiede OpenSSH 7.3 o successivo.
Mettilo in cima al file. Un blocco Host continua fino al successivo, e un Include messo dopo fa parte di quel blocco. L'abbiamo provato: con Include sotto un blocco Host a, le impostazioni del file incluso non facevano nulla per nessun altro host. Puoi sfruttarlo di proposito, per includere un file solo per alcuni host.
Match
Match è una forma più potente di Host, con condizioni:
Match host "*.internal" user deploy
Port 2200
Match exec "test -f /tmp/at-office"
ProxyJump bastion
Il primo si applica solo quando entrambe le condizioni sono vere. Il secondo esegue un comando di shell e si applica se termina con 0, ed è il modo per cambiare le impostazioni in base alla rete o al luogo. Nota che questo comando viene eseguito ogni volta che la configurazione viene letta, anche con ssh -G.
Le condizioni utili sono host, originalhost, user, localuser, exec, tagged, final e all. host controlla il nome dopo che HostName è stato applicato, e originalhost controlla ciò che hai digitato. final fa leggere a ssh la configurazione una seconda volta, il che permette a un blocco di vedere il risultato del primo passaggio:
Host *.corp
HostName %h.example.com
Match final host *.example.com
User admin
In OpenSSH 9.4 e successivi puoi anche etichettare gli host, e selezionarli con Match tagged o ssh -P:
Host web
Tag prod
Match tagged prod
User deploy
ProxyJump ha una pagina tutta sua: come usare ProxyJump e un jump host in SSH.
Vedere il risultato con ssh -G
ssh -G web
Stampa ogni impostazione che ssh userebbe per quell'host, con tutti i file e le regole applicati, ed esce senza connettersi. È il modo più rapido per rispondere a "perché usa quell'utente?":
ssh -G web | grep -E '^(hostname|user|port|identityfile) '
Per scoprire se la causa di un problema è la tua configurazione, ignorala per un comando. -F none salta sia il file dell'utente sia quello di sistema:
ssh -F none user@203.0.113.10
Per la connessione in sé, ssh -v web stampa quali righe di configurazione sono state applicate.
Errori comuni
- Un
Host *in cima che sovrascrive tutto ciò che sta sotto. - Un'opzione globale in fondo al file. Le opzioni fuori da un blocco devono venire prima del primo
Host. In fondo, appartengono all'ultimo blocco. - Un errore di battitura in un'opzione. ssh si ferma con
Bad configuration optione non si connette a nulla, su nessun host. Per un'opzione che solo alcune versioni conoscono, metti sopraIgnoreUnknowne il nome dell'opzione. - Segreti nel file. Contiene percorsi verso le chiavi, non le chiavi, e non ha un'opzione per la password. Deve restare così.
Domande
Dove si trova il file config di SSH?
Su Linux e macOS è ~/.ssh/config nella cartella home. Su Windows è C:\Users\nome\.ssh\config. Non esiste finché non lo crei. Le impostazioni di sistema in /etc/ssh/ssh_config vengono lette dopo.
Perché ssh ignora un'impostazione del mio config?
Un altro blocco corrispondente ha impostato la stessa opzione prima, e vince il primo valore. Esegui ssh -G seguito dal nome dell'host per vedere il valore che ssh userà, e sposta gli host specifici sopra Host *.
Il file config di SSH vale anche per scp, sftp e rsync?
Sì. Usano ssh per connettersi, quindi i nomi degli host e le opzioni di ~/.ssh/config valgono anche per loro, per esempio scp file.txt web:/tmp/.
Fonti
- ssh_config(5), manuale OpenBSD
- ssh(1), manuale OpenBSD
- Note di rilascio di OpenSSH 7.3, Include
- Note di rilascio di OpenSSH 9.4, tag