4 November 2021
Managing SSH config
OpenSSH is an awesome tool. However, using it may seem tedious. So many parameters to remember and type out. Three jump hosts in one line? I’m not sure it’s even possible.
Not to worry! We are going easy our interaction with the tool and tidy up its config.
No config at all
Let’s say we have a wonderful server with an address 111.222.333.444
and a user remote-user
.
To access we have to type a bulky command:
ssh [email protected]
We can save some time by skipping remote-user@
if our local user has exactly the same name.
We still have to remember an IP address which is somewhat doable with IPv4 but IPv6 is much more questionable.
It can be solved by a domain name but they are not always there.
There are other popular options like a private key, a non-standard port.
ssh [email protected] -i ~/.ssh/wonderful_server -p 54321
Well, that’s definitely a lot to remember.
Non-native ssh config
A power user of a shell may have a nice trick up their sleeve if it’s the only server we have or one of a few. Shell alias.
For zsh we can add the following alias to ~/.zshrc
:
alias ws='ssh [email protected] -i ~/.ssh/wonderful_server -p 54321'
where ws
stands for Wonderful Server.
It’s probably the easiest way to offload it from the memory.
The result is the shortest one.
Unfortunately, it doesn’t scale really well.
Native ssh config MVP
By default ssh looks for its config in ~/.ssh/config
.
Let’s map a familiar command to a config file.
ssh [email protected] -i ~/.ssh/wonderful_server -p 54321
should become
Host ws wonderful_server
User remote-user
HostName 111.222.333.444
IdentityFile ~/.ssh/wonderful_server
Port 54321
Now we can access it either by typing:
ssh ws
or
ssh wonderful_server
Both ws
and wonderful_server
are just local names (aliases) for us to call this server.
You can use as many aliases as you like (as I’m aware).
It’s super useful with services like GitLab and GitHub.
I recommend having three aliases: gh
, github
, github.com
The first one is for you to be able to make a quick git clone
:
git clone gh:ejiek/detox
The second one is handy when you have multiple upstreams.
The third one is for tools that supports ssh git interaction but have no way to override a host.
ProxyJumps
This is the first option that takes us beyond plain ssh commands in a console. For quite some time OpenSSH natively support jumping through the hosts with forwarding traffic bach to the original client. It’s awesome because you can limit your keys and ssh agent just to a local machine.
The ability to jump through multiple hosts is limited to a config file.
It’s not exactly true.
There is a flag -J
.
Unfortunately, I had a lot of struggle specifying multiple jumphosts that are not in a config file when they have a lot of parameters.
In this example, we have 3 servers: ws0
, ws1
, ws2
.
For some reason, maybe related to security, we can’t access ws1
and ws2
directly.
ws0
knows how to get to ws1
.
ws1
knows how to get to ws2
.
Let’s jump:
Host ws0 wonderful_server
User remote-user
HostName 111.222.333.444
IdentityFile ~/.ssh/wonderful_server
Port 54321
Host ws1 wonderful_server1
User anothe-remote-user
HostName 222.333.444.555
IdentityFile ~/.ssh/wonderful_server
Port 54321
ProxyJump ws0
Host ws2 wonderful_server2
User anothe-remote-user
HostName 333.444.555.666
IdentityFile ~/.ssh/wonderful_server
Port 54321
ProxyJump ws1
Connection to ws2
would actually establish a connection to ws0
, from there to ws1
forwarding traffic back to you.
Only then it’s going to connect to ws2 from ws1.
If you have a passphrase for your key and it’s not in an ssh agent, you’ll have to enter the passphrase three times. One time for each server in a chain.
Includes
There could be a lot of wonderful servers. At some point, they are going to eat up a lot of space in the main file. Fortunately, OpenSSH supports includes.
In my config I have the following before any actual host definitions:
Include config.d/*
Since the provided path is relative, it’s going to look for config.d
in ~/.ssh
.
Let’s move all wonderful servers into a separate file ~/.ssh/conig.d/wonderful_servers
Be careful with placing the include directive. It supports using inside Match and Host.
vim configuration non default files
I had my config highlighting broken for all included files. To fix it in Vim, it was enough to add one line:
" ssh config.d/* syntax highlighting
autocmd BufRead,BufNewFile ~/.ssh/config.d/* set syntax=sshconfig
Wildcard
All the wonderful servers look pretty much the same. It’s as bad with just a few of them. With dozens - it’s a disaster.
Let’s shave things off wonderful servers configs:
Host ws0 wonderful_server
User remote-user
HostName 111.222.333.444
Host ws1 wonderful_server1
HostName 222.333.444.555
ProxyJump ws0
Host ws2 wonderful_server2
HostName 333.444.555.666
ProxyJump ws1
Host ws* wonderful_server*
User anothe-remote-user
IdentityFile ~/.ssh/wonderful_server
Port 54321
A wildcard must go after hosts that use it. OpenSSH keeps the first value for a given parameters. Having a wildcard in front would block us from overriding values in a Host. In this example we are overriding user for ws0.
Sometimes it’s necessary to override ProxyJump not to jump at all.
It’s possible with ProxyJump none
.
My global wildcards
There are two of them right in the beginning of my ~/.ssh/config
:
Host *
ServerAliveInterval 240
IdentitiesOnly yes
The first one keeps alive connections with NAT somewhere in the way. When you idle for too long, a TCP session for your ssh connect isn’t closed. However, some firewalls can decide that enough is enough and just forget about it. This option sends some packets once it 4 minutes just to keep NATs happy. You may need to tune the time.
IdentityOnly
stop your OpenSSH client from going through all the keys you have, when the provided one isn’t working.
Aside from not wasting time and effort, it helps not to reach the server’s attempts limit (if there is one) and be sure that you’re using a correct key.
It can be fun to remove a key you think you don’t use.
Not that I know of =]
To the infinity and …
OpenSSH knows many more cool tricks. Port forwarding in both directions, socks5 proxy, and much more. To find out more use man 5 ssh_config.