Simplify your SSH commands with SSH configuration files.
For years I use to SSH into machines the hard way, specifying every argument, every time:
ssh -A -p 9898 james@core.example.net
That's not too horrendous, but you'll find yourself searching through your shell history to find the right command for each server every time.
With an SSH config file you could achieve the same SSH connection with a much simpler command:
ssh core
Introducing SSH Config
The man page for ssh
does a good job of explaining how configuration works:
$ man ssh configTODO
NAME
ssh_config — OpenSSH SSH client configuration files
DESCRIPTION
ssh(1) obtains configuration data from the following sources in the following order:
1. command-line options
2. user's configuration file (~/.ssh/config)
3. system-wide configuration file (/etc/ssh/ssh_config)
If we have a user configuration file located at ~/.ssh/config
we can configure the SSH client so that we don't need to pass in every argument every single time.
Let's take an SSH command:
ssh -A -p 9898 james@core.example.net
We could rewrite this in our SSH config file so that all we'd need to type ssh core
to start a new session, in which case our config file would look as follows:
Host core
HostName core.example.net
User james
Port 9898
ForwardAgent yes
It's as simple as that!
We can now connect using:
ssh core
The SSH client loads configuration in particular order. Command line arguments take precedent over user and system configuration. This can come in useful if you want to override an argument for a specific use case.
Let's say you wanted to connect on a slightly different port, you can run:
ssh -p 7878 core
Which will use the configuration from our SSH config file, but override the port to use 7878
instead of the 9898
declared in the config file.
The Details
It's worth pointing out that an SSH config file will work with ssh
, scp
and sftp.
Configuration File Order Precedence
SSH takes the first value it finds for each parameter. Command line arguments take precedent over a user's config file which takes precedence over the system config file and within a configuration file earlier entries take precedent over later entries.
In the below example the user will issue the command ssh core
, and the port will be set to 9898
(as defined in Host core
) and the later matching entry (Host co*
) is ignored:
Host core
HostName core.example.net
User james
Port 9898
ForwardAgent yes
Host co*
Port 7878
Given that earlier entries take precedent it's important to put host-specific configuration towards the top of your config file, and leave more generic configuration that uses wildcards towards the bottom.
Jump Hosts
A common security practice when working with SSH access to private networks is to access servers by a bastion host. The bastion host acts as a single entry point to the network. Once you've SSH'd into the bastion you can then SSH into any host within the network.
SSH provides you with some provisions that allow you to SSH easily into one host via another.
In the following examples we'll run ssh web1.cloud
to connect to our web server. Behind the scenes SSH will ssh into core.cloud.example.net
before SSHing into web1.cloud.example.net
ProxyJump
In OpenSSH 7.3+ the ProxyJump command was introduced. We can use this to tunnel our SSH traffic to web1.cloud.example.net
via core.cloud.example.net
:
Host web1.cloud
HostName web1.cloud.example.net
Host *.cloud
ProxyJump james@core.cloud.example.net:9898
ForwardAgent yes
User james
ProxyCommand
If you're running an older version of OpenSSH (7.2 and earlier), you can use ProxyCommand
to achieve the same thing:
Host web1.cloud
HostName web1.cloud.example.net
Host *.cloud
ProxyCommand ssh -p 9898 core.cloud.example.net nc -q0 %h %p 2> /dev/null
ForwardAgent yes
ProxyJump james@core.cloud.example.net:9898
User james
With this configuration I can still run ssh web1.cloud
to login to the web server via core.cloud.example.net
which acts as our SSH bastion.
Multiplexing for slow connections
Sometimes it can be useful to re-use an existing SSH connection with multiplexing. This can work will in poor connectivity situations where you want to avoid the overhead of authenticating new SSH connections.
If you're working with an SSH bastion, multiplexing can also be helpful for speeding up the connection time to private servers behind the bastion, as the connection to the bastion is recycled between individual SSH connections from your machine to the private network.
Host core.cloud
ForwardAgent yes
ControlPath ~/.ssh/control-path/%r@%h:%p
ControlMaster auto
ControlPersist 10m
Multiple Configuration Files
Finally, it's worth noting that in OpenSSH 7.3+ the Include
directive was introduced that allows you to split SSH configuration over multiple files.
For example, your main ~/.ssh/config
could read as follows:
Include config.d/*
You could then put configuration into separate files, for example:
~/.ssh/config.d/home
~/.ssh/config.d/work
Host desktop
Port 6565
Host web1.cloud
HostName web1.cloud.example.net
Host *.cloud
ProxyJump james@core.cloud.example.net:9898
ForwardAgent yes
User james
Using SSH configuration files can be a great way of reducing the complexity of your SSH commands. ProxyJump
and ProxyCommand
are also indispensable in environments where you are using an SSH bastion or a more complex setup that involves jumping through hosts. A good set of SSH configuration files will make you less dependant on your shell history for finding the right command for the right host.