Konfigurační soubor SSH na straně klienta je ~/.ssh/config (ve Windows C:\Users\<you>\.ssh\config). Každý blok Host dá spojení krátké jméno a uloží všechno, co bys jinak psal pokaždé: HostName pro skutečnou adresu, User, Port, IdentityFile pro klíč a ProxyJump pro stroj uprostřed. Potom ssh web nahradí ssh -i ~/.ssh/id_work -p 2222 deploy@203.0.113.10 a stejně tak scp, sftp, rsync, Git i každý editor, který umí SSH, protože všechny čtou stejný soubor.
Jedno pravidlo vysvětluje téměř každé překvapení: u každého nastavení vyhrává první hodnota, kterou ssh najde. Konkrétní bloky patří nahoru, univerzální Host * dolů a nastavení zadané na příkazové řádce přebije cokoli v souboru. Když si tohle pamatuješ, zbytek návodu je přehled, ze kterého můžeš kopírovat.
Tento článek je o straně klienta. Generování klíčů, agent a zabezpečení sshd_config na serveru najdeš v článku SSH klíče a zabezpečení sshd_config; pokud ještě nemáš klíč, přečti si nejdřív ten.
Kde konfigurační soubor leží#
Soubory jsou dva a čtou se postupně: nejdřív tvůj, pak systémový.
| Systém | Uživatelský soubor | Systémový soubor |
|---|---|---|
| Linux, BSD | ~/.ssh/config | /etc/ssh/ssh_config |
| macOS | ~/.ssh/config | /etc/ssh/ssh_config |
| Windows OpenSSH | %USERPROFILE%\.ssh\config | %ProgramData%\ssh\ssh_config |
Dokud ho nevytvoříš, soubor neexistuje. Na Linuxu a macOS do něj nesmí zapisovat nikdo kromě tebe, jinak ho ssh odmítne použít a vypíše Bad owner or permissions on /home/you/.ssh/config:
$ mkdir -p ~/.ssh && chmod 700 ~/.ssh$ touch ~/.ssh/config && chmod 600 ~/.ssh/configVšimni si názvu: ssh_config je klient, sshd_config (s d jako daemon) je server. Upravit špatný soubor je překvapivě častý způsob, jak ztratit odpoledne, a serverový soubor leží ve stejném adresáři /etc/ssh.
Dva přepínače soubor zprůhlední. ssh -G name vypíše plně vyhodnocenou konfiguraci pro dané jméno, aniž by se připojil - každou volbu poté, co se uplatnily všechny bloky a výchozí hodnoty. ssh -F /dev/null name se připojí a přitom ignoruje tvoji konfiguraci, takže jedním krokem zjistíš, jestli je problém v souboru. -G přišlo v OpenSSH 6.8, takže je k dispozici na všem, na co pravděpodobně narazíš.
$ ssh -G web | grep -E '^(hostname|user|port|identityfile|proxyjump) 'hostname 203.0.113.10user deployport 2222identityfile ~/.ssh/id_workproxyjump noneBloky Host a jak ssh vybírá hodnotu#
Řádek Host začíná blok, který trvá až do dalšího řádku Host nebo Match. Odsazení je pro tebe, ne pro ssh. Klíčová slova nerozlišují velikost písmen, hodnoty většinou ano, a můžeš psát Keyword value i Keyword=value.
Host web HostName 203.0.113.10 User deploy Port 2222 IdentityFile ~/.ssh/id_work IdentitiesOnly yesHost *.lab User admin StrictHostKeyChecking accept-newHost * ServerAliveInterval 30 AddKeysToAgent yesKdyž napíšeš ssh web, ssh projde soubor odshora dolů. Každý blok, jehož vzor odpovídá, přispěje nastaveními, která ještě neviděl. Takže web dostane port ze svého bloku a ServerAliveInterval z Host *. Kdyby Host * stál nahoře s User root, všechny pozdější řádky User by se ignorovaly, což je klasická podoba hlášky „moje konfigurace se ignoruje“.
Výjimkou je malá skupina voleb, které se místo první hodnoty sčítají: IdentityFile, CertificateFile, LocalForward, RemoteForward, DynamicForward a SendEnv. Několik řádků IdentityFile z více odpovídajících bloků vytvoří seznam, který se zkouší popořadě.
Vzory se porovnávají s názvem, který jsi napsal, ne s HostName. Podporují * a ?, několik vzorů na jednom řádku a negaci pomocí !:
Host web db cache User deployHost 10.0.0.* !10.0.0.1 ProxyJump bastionHost * !github.com ForwardAgent noSamotný negovaný vzor nikdy nic neodpovídá; jen vylučuje z ostatních vzorů na stejném řádku. Host !github.com samotný je blok, který se nevztahuje na nic.
Match pro podmínky, které Host nevyjádří
Bloky Match testují podmínky, ne jména. Užitečné jsou host (jméno po použití HostName), originalhost (co jsi napsal), user, localuser, exec a all.
# Use the office jump host only when not on the office networkMatch host 10.20.* !exec "ip route | grep -q 10.20.0.0/16" ProxyJump gw.example.comexec spustí příkaz shellu a odpovídá, pokud skončí se stavem nula. Běží při každém připojení, takže ho drž rychlý, a pamatuj, že je to příkaz shellu spuštěný na tvém stroji - nikdy nevkládej takový, kterému nerozumíš.
Nastavení, která stojí za to znát#
Tohle jsou volby, které si v opravdové konfiguraci zaslouží místo. Výchozí hodnoty jsou výchozí hodnoty OpenSSH.
| Volba | Výchozí | Co dělá |
|---|---|---|
HostName | napsané jméno | Skutečná adresa nebo DNS jméno |
User | tvé lokální uživatelské jméno | Vzdálený účet |
Port | 22 | Vzdálený port SSH |
IdentityFile | standardní soubory id_* | Soukromý klíč, který se nabídne |
IdentitiesOnly | no | Nabídne jen uvedené klíče |
ProxyJump | žádný | Nejdřív přeskočí přes tyto hosty |
ServerAliveInterval | 0 (vypnuto) | Sekundy mezi keepalive pakety |
ServerAliveCountMax | 3 | Počet zmeškaných keepalive paketů, než se to vzdá |
ConnectTimeout | systémový timeout TCP | Sekundy čekání na připojení |
StrictHostKeyChecking | ask | Jak naložit s neznámými klíči hostů |
HostName přijímá tokeny, takže jeden blok může obsloužit celou rodinu strojů. %h je jméno, které jsi napsal:
Host *.prod HostName %h.example.comTo nedělá úplně to, co lidé čekají: ssh api.prod se připojí k api.prod.example.com. Pokud tvoje skutečná jména .prod neobsahují, napiš raději jeden blok na každý host. Chytré vzory šetří řádky a stojí přehlednost, a konfigurace je soubor, který budeš číst ve dvě ráno.
User stojí za to nastavit v každém bloku, protože výchozí hodnota je tvoje lokální přihlašovací jméno. Na Windows notebooku je to často jméno s velkým písmenem nebo ve tvaru e-mailu, které na žádném linuxovém serveru neexistuje, a dostaneš jen prosté Permission denied, které na uživatelské jméno nijak neukazuje.
Port je důležitý hlavně u strojů, které přesunuly SSH z portu 22, aby zklidnily logy, a u všeho, co na jiném portu provozuje vlastní službu mluvící SSH. ssh -p 2222 na příkazové řádce přebije soubor, jako každá volba z příkazové řádky.
IdentityFile a IdentitiesOnly
IdentityFile pojmenuje soukromý klíč a cesta může začínat ~. Bez něj zkouší ssh standardní jména v ~/.ssh - id_rsa, id_ecdsa, id_ed25519 a jejich varianty pro bezpečnostní klíče - plus cokoli, co je načtené v agentovi.
S jedním klíčem je to výchozí chování v pořádku. S více klíči způsobí selhání, které dřív nebo později potká každého, kdo má pracovní a osobní klíč: ssh nabídne jeden po druhém každý klíč z agenta, každá nabídka se počítá jako pokus o autentizaci a server s MaxAuthTries 3 tě odpojí s Too many authentication failures, dřív než se dostane k tomu správnému. IdentitiesOnly yes říká ssh, aby nabízelo jen klíče pojmenované pro daný host, i když jich agent drží víc. Dej ho do Host * ke konci a klíč pojmenuj v každém bloku, který ho potřebuje.
IdentityFile přijímá také soubor .pub, když druhá polovina leží jinde, například ve správci hesel, který funguje jako agent. ssh podle veřejného klíče vybere, který klíč z agenta nabídne, což je nejčistší způsob, jak spojit IdentitiesOnly s agentem, který drží tucet klíčů.
Kontrola klíčů hostů bez zvyku ano-ano-ano
StrictHostKeyChecking accept-new (OpenSSH 7.6 a novější) přidá klíče hostů, které jsi nikdy neviděl, bez ptaní a stále hlasitě odmítne, když se klíč známého hosta změní. To je rozumné nastavení pro laboratoř z jednorázových strojů a špatné pro produkční server, ke kterému se připojuješ poprvé, kde je dotaz jediným okamžikem, kdy můžeš porovnat otisk. Omez ho vzorem, nedávej ho do Host *. UserKnownHostsFile může skupinu hostů nasměrovat na samostatný soubor, což se hodí pro testovací síť, která se každý týden staví znovu:
Host *.lab StrictHostKeyChecking accept-new UserKnownHostsFile ~/.ssh/known_hosts_labProxyJump a jump hosty#
Jump host (říká se mu také bastion) je jeden stroj, na který se dostaneš z internetu a který stojí před dalšími, na které ne: databáze v privátní síti, herní server za firewallem, který povoluje SSH jen z bastionu, nebo všechny interní stroje malé firmy. ProxyJump udělá z přeskoku neviditelný krok.
Host bastion HostName 203.0.113.10 User jump IdentityFile ~/.ssh/id_ed25519Host db HostName 10.0.0.20 User deploy IdentityFile ~/.ssh/id_ed25519 ProxyJump bastionssh db se teď připojí k bastion, požádá ho o otevření TCP spojení na 10.0.0.20:22 a skrz tento tunel spustí druhou, úplnou relaci SSH. Důležitá vlastnost je, kde probíhá autentizace: na tvém notebooku, end to end, pro oba přeskoky. Bastion jen přeposílá šifrované bajty a nikdy nevidí tvůj soukromý klíč, tvého agenta ani tvoji relaci. Proto ProxyJump nahradil forwarding agenta jako správný způsob, jak se dostat na druhý stroj.
Co je na něm dobré vědět:
- Přišel v OpenSSH 7.3. Na starších verzích je ekvivalentem
ProxyCommand ssh -W %h:%p bastion, které dělá totéž a ukazuje ho většina návodů z doby před rokem 2017. Nenastavuj oba na jednom hostu; vyhraje ten, který ssh přečte první. - Každý přeskok se vyhledává v konfiguraci.
ProxyJump bastionpoužije adresu, uživatele, port a klíč z blokubastion. Přeskok můžeš zapsat i přímo jakouser@host:port. - Řetězce se oddělují čárkou.
ProxyJump bastion,innerprojde oběma v pořadí, každý přeskok se znovu vyhodnotí z konfigurace. - Na příkazové řádce je to `-J`.
ssh -J jump@203.0.113.10 deploy@10.0.0.20je jednorázová podoba a-Jpřijímají iscpasftp. - `ProxyJump none` ve specifičtějším bloku vypne přeskok zděděný ze širokého vzoru níže.
Cíl vidí, že spojení přichází z privátní adresy bastionu, takže pravidla firewallu na vnitřním stroji by měla povolit SSH z této adresy a z ničeho jiného. Na samotném bastionu musí sshd povolit TCP forwarding: AllowTcpForwarding no nebo DisableForwarding yes v jeho sshd_config rozbije každý přeskok hláškou channel 0: open failed: administratively prohibited.
Účet na bastionu, který umí jen přeskakovat
Bastion je užitečnější, když účet na něm nesmí nic kromě forwardingu. V souboru authorized_keys uživatele jump na bastionu to přesně udělají volby klíče z návodu k zabezpečení:
restrict,port-forwarding,permitopen="10.0.0.20:22",permitopen="10.0.0.21:22" ssh-ed25519 AAAAC3Nza... laptoprestrict vypne všechno volitelné, port-forwarding forwarding znovu zapne a permitopen ho omezí na vypsané cíle. S tímto klíčem ssh bastion samotné nedostane shell, zatímco ssh db funguje. Odcizený klíč otevře dva porty SSH na dvou privátních strojích, které stále potřebují vlastní klíče.
Keepalive a zamrzající spojení#
Relace, která po několika minutách nečinnosti místo ukončení zamrzne, je téměř vždy případ záznamu v NAT tabulce domácího routeru, mobilní sítě nebo firemního firewallu, který se tiše zahodil. Oprava je na straně klienta:
Host * ServerAliveInterval 30 ServerAliveCountMax 3Po každých 30 sekundách ticha pošle ssh uvnitř šifrovaného kanálu požadavek a čeká odpověď. Provoz brání prostředníkům zapomenout spojení, a pokud chybí tři odpovědi po sobě, ssh relaci po asi 90 sekundách zavře, místo aby nechalo zamrzlý terminál. Nepleť si to s TCPKeepAlive, které je ve výchozím stavu zapnuté a pracuje na úrovni TCP; je snazší ho podvrhnout a časování určuje operační systém, často dvě hodiny, což je proti routeru, který zapomíná po pěti minutách, k ničemu.
ConnectTimeout 10 je doprovodné nastavení pro skripty. Bez něj připojení ke stroji, který je vypnutý, čeká na timeout TCP operačního systému, který může být výrazně přes minutu, a záložní skript procházející hosty se zasekne na prvním mrtvém.
Opětovné použití spojení pomocí ControlMaster#
Multiplexing nechá další relace ke stejnému hostu jet po TCP spojení té první. Druhé ssh web, každé scp i každý krok Ansiblu nebo git pull startují okamžitě a znovu se neautentizují. Na pomalé lince nebo přes jump host je rozdíl vteřiny na každý příkaz.
Host * ControlMaster auto ControlPath ~/.ssh/cm-%C ControlPersist 10mControlMaster auto udělá z prvního spojení master a dovolí ho používat dalším. ControlPath je lokální soubor socketu; %C je hash údajů o spojení (lokální host, vzdálený host, port, uživatel), takže je pro každý cíl jedinečný a vždy krátký. To je důležité: cesty k Unix socketům mají limit zhruba sto znaků a starší styl %r@%h:%p selže u dlouhých jmen hostů. ControlPersist 10m drží master na pozadí otevřený deset minut po zavření poslední relace.
Master ovládáš přepínačem -O:
$ ssh -O check web # is a master running for this host?Master running (pid=48213)$ ssh -O exit web # close it and every session on itÚskalí jsou skutečná a jsou důvodem, proč to někteří lidé nechávají vypnuté:
- Všechno sdílí jedno spojení. Když spadne síť, zaniknou najednou všechny relace na něm.
- Nastavení určuje master. Nová relace s jinými volbami, například s přesměrováním portu, se připojí ke stávajícímu spojení a volby působící na úrovni spojení, mimo jiné uživatel a cesta přes jump, patří masteru. Když se zdá, že změna konfigurace nemá žádný efekt, spusť nejdřív
ssh -O exit. - Socket je přihlašovací údaj. Kdokoli, kdo může soubor otevřít, může použít tvoje autentizované spojení, proto patří do adresáře, který může číst jen ty.
- Windows OpenSSH to nepodporuje. Vestavěný klient nemá multiplexing přes Unix sockety a řádek
ControlMasterzpůsobí chyby, ne zrychlení. Použij ochranu přesMatch exec, nech to v samostatném souboru pro své stroje s Linuxem a macOS, nebo použij WSL.
Windows OpenSSH: cesty a pasti#
Windows 10 (1809 a novější) a Windows 11 dodávají klienta OpenSSH jako C:\Windows\System32\OpenSSH\ssh.exe a ten čte stejný formát konfigurace. Uživatelský soubor je C:\Users\<you>\.ssh\config a ~ v IdentityFile funguje. Cesty s mezerami potřebují dvojité uvozovky; lomítka dopředu se vyhnou všem otázkám kolem escapování:
Host web HostName 203.0.113.10 User deploy IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yesHost db HostName 10.0.0.20 User deploy IdentityFile "C:/Users/you/Key Store/id_db" ProxyJump webVšechny pasti leží mimo syntaxi.
Kódování. Ve Windows PowerShell 5.1 zapíše echo "Host web" > config UTF-16 a ssh soubor odmítne se zkomolenou hláškou Bad configuration option na řádku 1. Soubor vytvoř příkazem New-Item -ItemType File $HOME\.ssh\config a edituj ho v editoru, který ukládá čisté UTF-8. PowerShell 7 zapisuje ve výchozím stavu UTF-8 a tenhle problém nemá.
Oprávnění klíče. ssh ve Windows kontroluje ACL soukromých klíčů a odmítne ten, který mohou číst jiné účty, s hláškou UNPROTECTED PRIVATE KEY FILE. Obvykle se to stane klíči zkopírovanému odjinud. Odeber zděděná oprávnění a přidej jen sobě:
icacls "$HOME\.ssh\id_ed25519" /inheritance:ricacls "$HOME\.ssh\id_ed25519" /grant:r "$($env:USERNAME):(R)"Agent je služba. AddKeysToAgent yes nic nedělá, dokud neběží OpenSSH Authentication Agent. Z PowerShellu spuštěného jako správce:
Get-Service ssh-agent | Set-Service -StartupType AutomaticStart-Service ssh-agentDva programy ssh. Git for Windows dodává vlastní ssh v C:\Program Files\Git\usr\bin. Čte stejný ~/.ssh/config, ale používá vlastního agenta, takže klíče přidané Windows ssh-add Git nevidí. Opravíš to nasměrováním Gitu na systémového klienta: git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe". Rozšíření Remote-SSH ve VS Code čte stejný konfigurační soubor, takže se v jeho seznamu objeví každé jméno Host, které definuješ.
Recepty, které se vracejí pořád dokola#
Dva účty GitHub na jednom počítači
GitHub tě identifikuje podle klíče a každý účet se připojuje jako git@github.com, takže druhý účet potřebuje druhý klíč a alias:
Host github-work HostName github.com User git IdentityFile ~/.ssh/id_work IdentitiesOnly yesKlonuj s aliasem místo jména hostu - git clone git@github-work:company/app.git - a testuj pomocí ssh -T github-work. Bez IdentitiesOnly může agent nabídnout nejdřív osobní klíč, GitHub ho přijme a ty pushuješ jako špatná osoba.
Přístup k databázi přes SSH
K databázi, která na serveru poslouchá jen na 127.0.0.1, se dostaneš z notebooku pomocí forwardu uloženého v konfiguraci:
Host web-pg HostName 203.0.113.10 User deploy LocalForward 15432 127.0.0.1:5432 SessionType nonessh web-pg pak drží otevřený tunel bez shellu (SessionType none vyžaduje OpenSSH 8.7; na starších klientech použij ssh -N web-pg) a klient na tvém stroji se připojí na localhost:15432. Je to často lepší odpověď než otevření portu databáze do internetu, o čemž pořádně pojednává článek vzdálená připojení k PostgreSQL.
Rozdělení souboru pomocí Include
Include (OpenSSH 7.3 a novější) čte další soubory, i se zástupnými znaky, a relativní cesty se berou od ~/.ssh. Dej ho úplně nahoru, mimo jakýkoli blok, jinak platí jen pro blok, ve kterém stojí:
Include config.d/*Host * IdentitiesOnly yes ServerAliveInterval 30Jeden soubor na klienta nebo projekt v ~/.ssh/config.d/ udrží dlouhou konfiguraci čitelnou a umožní smazat všechny hosty celého projektu jedním krokem.
Spravované servery přes SFTP
Herní, aplikační nebo webový server v hostingovém panelu obvykle nemá shell, ale jeho přístup přes SFTP z bloku také těží. Na RE:NODE je SFTP dostupné na každém serveru s přihlašovacími údaji vydávanými pro každý server zvlášť, ne pro účet, takže blok pro každý server s hostem, portem a uživatelským jménem z panelu umožní, aby sftp mc-world nahradilo dlouhý řetězec, a editory čtoucí konfiguraci ho vypíšou podle jména. Heslo se stále zadává pokaždé; nezkoušej na takovém bloku vynucovat klíč pomocí IdentitiesOnly. SFTP a správce souborů popisuje klienty i stranu panelu.
Kompletní konfigurace, od které můžeš začít#
Dohromady vypadá konfigurace pro jedno VDS, za ním privátní stroj a GitHub takhle:
Include config.d/*Host vds HostName 203.0.113.10 User deploy IdentityFile ~/.ssh/id_ed25519Host db HostName 10.0.0.20 User deploy IdentityFile ~/.ssh/id_ed25519 ProxyJump vdsHost github.com User git IdentityFile ~/.ssh/id_ed25519Host * IdentitiesOnly yes AddKeysToAgent yes ServerAliveInterval 30 ServerAliveCountMax 3 ConnectTimeout 10 ControlMaster auto ControlPath ~/.ssh/cm-%C ControlPersist 10mNa Windows odstraň tři řádky Control. Pokud je server čerstvý, první hodina na novém VDS popisuje účet a firewall na druhé straně a návod k ufw ukazuje, jak povolit SSH jen z bastionu, jakmile jump host funguje.
Řešení potíží s konfigurací#
| Příznak | Obvyklá příčina |
|---|---|
| Nastavení se zdají ignorovaná | Dřívější blok je nastavil jako první |
Too many authentication failures | Agent nabízí každý klíč; přidej IdentitiesOnly yes |
Bad owner or permissions | Konfigurace nebo klíč je zapisovatelný pro ostatní |
Bad configuration option na řádku 1 | Soubor v UTF-16 z PowerShellu 5.1 |
administratively prohibited při přeskoku | Bastion má vypnutý forwarding |
| Změna konfigurace nemá efekt | Spojení ControlMaster je stále otevřené |
Could not resolve hostname | Jméno nemá blok Host, nebo je v něm překlep |
Postup pro cokoli dalšího jsou stejné tři kroky. ssh -G name ukáže, jaká nastavení si ssh myslí, že platí. ssh -v name ukáže, které řádky konfigurace použilo, které klíče nabídlo a kde se spojení zastavilo; u ProxyJump výstup pokrývá oba přeskoky, takže si přečti, který selhal. ssh -F /dev/null user@address soubor úplně potvrdí nebo vyloučí.
FAQ#
Používají scp, rsync a Git moji konfiguraci SSH?
Ano. Všechny spouštějí systémového klienta ssh, který čte ~/.ssh/config, takže alias Host funguje všude, kam bys napsal jméno hostu: scp file web:/tmp/, rsync -a dir/ web:/srv/, git@github-work:org/repo.git. Nástroje s vlastní implementací SSH, například některé grafické klienty SFTP, mohou soubor ignorovat nebo číst jen jeho část.
Jaký je rozdíl mezi ProxyJump a forwardingem agenta?
U ProxyJump probíhají obě přihlášení na tvém stroji a prostřední host jen předává bajty. U forwardingu agenta (ssh -A) se přihlásíš na prostřední host a pak odtud používáš svého agenta, takže kdokoli s právy root na tom stroji si může tvoje klíče půjčit, dokud jsi připojený. Použij ProxyJump vždy, když je cílem dostat se na jiný stroj.
Můžu použít jiný port a jump host současně?
Ano. Port v bloku platí pro host toho bloku a každý přeskok se vyhodnocuje zvlášť, takže bastion na portu 2222 a cíl na 22 potřebují jen své vlastní řádky Port. Přímo to udělá ProxyJump jump@203.0.113.10:2222.
Je bezpečné dát ControlMaster do Host star?
Na Linuxu a macOS je to pro interaktivní použití bezpečné, pokud ControlPath míří dovnitř tvého vlastního adresáře ~/.ssh. Někteří lidé vyloučí hosty používané pro dlouhé přenosy souborů, protože jeden zaseknutý master zasekne každou relaci na něm. Na Windows to úplně vynech.
Proč se ssh pořád ptá, který klíč, nebo používá špatný?
Obvykle agent drží několik klíčů a není nastavené IdentitiesOnly, nebo je v cestě k IdentityFile překlep a ssh se tiše vrátí k výchozím. ssh -v vypíše každý klíč, který nabídlo, popořadě, a ssh -G ukáže, které řádky identityfile skutečně vyhodnotilo.


