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
To access we have to type a bulky command:
We can save some time by skipping
[email protected] 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
alias ws='ssh [email protected] -i ~/.ssh/wonderful_server -p 54321'
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
Let's map a familiar command to a config file.
ssh [email protected] -i ~/.ssh/wonderful_server -p 54321
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:
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:
The first one is for you to be able to make a quick
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.
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
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:
For some reason, maybe related to security, we can't access
ws0 knows how to get to
ws1 knows how to get to
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
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.
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:
Since the provided path is relative, it's going to look for
Let's move all wonderful servers into a separate file
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
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
My global wildcards
There are two of them right in the beginning of my
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.