Stop Making Shell Aliases for SSH!
Stop me if you’ve had this problem before. You need to ssh into a server, but it has some horribly complicated rules, so your SSH command looks something like
ssh -p 9999 myuser@complicated.hostname.com
Then you add public key authentication (you are using pubkey authentication right?), only to discover that because you used a nonstandard key name, you have to pass the keyfile to SSH. So now your SSH command looks like
ssh -i ~/.ssh/myspecialkey -p 9999 myuser@complicated.hostname.com
and typing it out is really starting to get painful.
So you try for a while, but eventually you get tired of all this typing, and add
the following line to your ~/.bashrc
:
alias sshcomplicated="ssh -i ~/.ssh/myspecialkey -p 9999 myuser@complicated.hostname.com"
and all is well and good.
Right?
All is not well and good #
First off, I’d like to applaud you for reaching this solution: given the choice, it is almost always better to use an automated solution to avoid lots of repetitive typing. Unfortunately, in this case, a shell alias is the lowest level of automation, and it suffers from quite a few nasty issues:
- You have to make an alias for each host you want to visit. If you only have one host, this is fine. If you have 5 hosts, maybe fine. If you have 20 or 30 hosts you want to SSH into, this becomes a mess to keep track of.
- What about other remote access services? What if you want to use rsync, scp, sftp, or even mosh or the VSCode Remote Plugins? Do you need to now make aliases for each of these programs? What if you combine this with the previous problem? If you assume a modest 10 machines and 5 services, you now have 50 aliases you have to write.
- What if your weird SSH port changes for one set of your SSH machines, but not another? (For example, one organization changed the SSH port but the rest are keeping the default). Do you have to manually pick your way through your 50 aliases to find the ones you need to change?
It seems like what we need is some sort of way of storing our SSH information that:
- Can easily store lots of different host info without being too complex (solves problem 1)
- Can be read + understood by many different programs (solves problem 2)
- Can store information hierarchically, that is, some information is automatically applied to multiple entries at once (solves problem 3)
Fortunately, it turns out there’s already a file that does this for us: the SSH Config
The SSH Config File: Overview #
Let’s take a look at a basic SSH config entry in ~/.ssh/config
:
Host unicorns
Hostname prettyhorses.company.org
User myuser
Port 3355
IdentityFile ~/.ssh/myspecialkey
This sets the Hostname
, User
, Port
, and IdentityFile
entries for the
host unicorns
. Now, if I go to the command line and type ssh unicorns
, SSH
will know to apply certain options: it’s functionally equivalent to if I typed
ssh -i ~/.ssh/myspecialkey -p 3355 myuser@prettyhorses.company.org
Now, on it’s own, this may not seem like much savings over a simple shell alias. What gets really good is that scp knows how to interpret this file as well. So if I type
scp ~/myfile unicorns:myfile
scp
will know to apply the options it finds for Host unicorns
in the SSH
config file, and it’s the same as if I typed
scp -i ~/.ssh/myspecialkey -P 3355 ~/myfile myuser@prettyhorses.company.org:myfile
In fact, many (I might go as far as to say most) Unix programs that access remote computers can understand the SSH Config file format. This makes it easy to write your config exactly once, then forget about it.
Advanced Config: Match Clauses #
So now you’re setting up your SSH config, but you have a lot of computers
from this one organization that all have the same settings. For example, let’s
say you’re part of the Institute for Silliness (IS) and you always use the
same settings there: the username is sillyuser
, the keyfile is your sillykey
,
and all the systems have SSH on port 3000 as a matter of protocol.
You can set up a match clause in your SSH file that will apply settings to all hosts that meet a certain criteria. It might look something like this:
Host clowns
Hostname clowns.silly.institute.edu
Host balloon
Hostname balloon-animals.silly.institute.edu
Host strings
Hostname silly-string.silly.institute.edu
# etc. etc.
Match host *.silly.institute.edu
User sillyuser
Identityfile ~/.ssh/sillykey
Port 3000
Now all your hosts that have silly.institute.edu
will have the special
settings applied at once. Even better: if the Institute for Silliness ever
changes its settings, you only have to edit a few lines to change everything
over!
Conclusion #
This is far from the total power of SSH Config files: you can go nuts with options like proxy hosts, allowing/disallowing certain ciphers on some hosts, automatially running commands once you log in to a certain host–in general, if you can run an SSH command to do something, you can usually encode it into the SSH config so that it does that every time.
Hopefully I’ve convinced you that setting up an SSH config is definitely worth your time. If you want to just what these things can do, there are some great tutorials out there on the internet!