Skip to main content

SSH Config

sshconfig 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 sshconfig 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-laptop instead of ssh 10.0.0.13)
  • be able to chain node jumps

For more information, see man ssh_config.

Adding hosts#

To start out, here's a simple config entry I use to for my home network router:

# ~/.ssh/config
Host router  Hostname 192.168.1.1  User johanan

This lets me type ssh router instead of ssh johanan@192.168.1.1. Not a huge improvement in terms of number of characters, but still much easier to remember and easier to understand when looking at 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 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.

My sshconfig entry for my home router looks like this:

# ~/.ssh/config
Match originalhost router exec "[ $(nmcli -g NAME c show --active | grep -xE 'wg0') ]"  HostName <wireguard IP>Host router  Hostname <local IP>  User johanan

This line, Match originalhost <host> exec "<shell command>", will execute <command> when connecting to <host>. If the command is successful the configuration entries under Match will be applied on top of the configuration options for host.

In this example, that means that ssh router will connect to <local IP> unless the interface wg0 is currently active (i.e. I'm connected to my home VPN with WireGuard).

For more information, see man ssh_config & search for Match.

Key forwarding#

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 man ssh_config:

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.

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 foobar@123.123.123.24 # ssh to jump serverssh -A foobaz@124.124.124.25 # ssh to build server (-A commonly needed for access to Git repositories)

With a reasonable sshconfig, you just have to do

ssh build-server

And this benefit extends to other SSH tools like SCP as well.

A sample config for the above scenario:

# ~/.ssh/configHost build-server  User foobaz  ProxyJump jumphost  ForwardAgent yes  Hostname 124.124.124.25
Host jumphost  User foobar  ForwardAgent yes  Hostname 123.123.123.24