SSH Config: How To Work Faster With Remote Hosts
ssh_config is a power tool. I think few people realize that, because more
often than not I see people remembering IP addresses by heart, using
command-line ssh options such as
-A repeatedly, and relying on their shell
history to find out what options or IP addresses they usually reach out to.
Relying on history is absolutely fine, even a productivity boost, but depending on your history for configuration options seems like a bad idea to me. And I don't have the patience for learning to recognize IP addresses by heart.
Instead I use
ssh_config and I think you should too. Not only will it make you
faster at using ssh and its related tools like scp, you will also:
- have a much more readable shell history (for example
ssh work-laptopinstead of
- be able to chain node jumps
For more information, see
To start out, here's a simple config entry for my home router:
# ~/.ssh/config Host router Hostname 10.77.77.1 User johanan
This lets me type
ssh router instead of
ssh firstname.lastname@example.org. Not a
huge improvement in terms of number of characters, but it brings two improvements:
- it's easier to remember
- it's easier to understand when looking at my shell history
Conditional IP addresses
There are a number of devices I need to access over SSH on a regular basis, both privately and at work. Sometimes I'm on the same network and sometimes I'm not. When I'm on the same LAN I want a direct connection to avoid latency, and when I'm not I want to connect over a jump host / VPN. To do this I maintain a single Host entry per device, but with conditional rules for how to access them depending on my current network connection.
Using my home router as an example again, we can improve its config entry like so:
# ~/.ssh/config Match originalhost router exec "[ $(nmcli -g NAME c show --active | grep -xE 'wg0') ]" Hostname 10.66.66.1 Host router Hostname 10.77.77.1 User johanan
Match originalhost $HOST exec "$SHELL_COMMAND", will execute
$SHELL_COMMAND when connecting to
$HOST. If the command is successful the
configuration entries under
Match will be applied on top of the configuration
In this example, that means that
ssh router will connect to
wg0 is currently active (i.e. I'm connected to my home VPN with
WireGuard). If the
wg0 interface is inactive,
ssh router will instead
For more information on using match rules, see
man ssh_config & search for
Instead of using
ssh -A, we can configure the same behaviour by using
ForwardAgent true in the Host entry.
Note: be careful with
ForwardAgent - you must trust the devices you SSH
to with this option. From
Agent forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote host (for the agent's Unix-domain socket) can access the local agent through the forwarded connection. An attacker cannot obtain key material from the agent, however they can perform operations on the keys that enable them to authenticate using the identities loaded into the agent.
My home router entry as an example again:
# ~/.ssh/config Match originalhost router exec "[ $(nmcli -g NAME c show --active | grep -xE 'wg0') ]" Hostname 10.66.66.1 Host router Hostname 10.77.77.1 ForwardAgent true User johanan
Chaining node jumps
Consider the following scenario. You have your local laptop with an SSH key. At work you have a build server of some kind, without an SSH key and you need to access a Git repository and build stuff there. The build server is not publicly exposed and you are not connected to the same LAN. To reach it you have to go through a jump host.
If you wanted to do some development work on the build server manually, you'd have to do something like this:
ssh -A email@example.com # ssh to jump server (-A needed in order to forward the keys again to the build server) ssh -A firstname.lastname@example.org # ssh to build server (-A needed to access the Git repositories)
With a reasonable sshconfig, you just have to do
And this benefit extends to other SSH tools like SCP as well.
A sample config for the above scenario:
# ~/.ssh/config Host build-server User foobaz ProxyJump jumphost ForwardAgent yes Hostname 184.108.40.206 Host jumphost User foobar ForwardAgent yes Hostname 220.127.116.11
Note that this means that you trust the jump host, since you are forwarding your SSH key to it. If you don't trust your jump host, you should add the SSH key to the build server so that you don't have to forward it.