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 ofssh 10.0.0.13
) - be able to chain node jumps
For more information, see man ssh_config
.
#
Adding hostsTo 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 addressesThere 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 forwardingInstead 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 jumpsConsider 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