loading...

SSH Config Tips and Tricks

cpu profile image Daniel McCarney ・4 min read

Here's a quick tour through some of my favourite ~/.ssh/config options starting with the more common to the less common.

Friendly server names

Often when I spin up a new server with a cloud provider I don't want to bother with giving it a domain name. However it becomes annoying to type the IP address over and over in ssh commands. Thankfully ~/.ssh/config has a solution: Host and Hostname.

For example if I have a test droplet that was given the IP address 10.11.12.13 I can add an entry to my ~/.ssh/config like:

Host testDroplet dropletA
  Hostname 10.11.12.13

Now I can run ssh testDroplet or ssh dropletA and don't have to remember the IP address. I usually indent the lines after Host to show they're settings for that host. Let's add some more customized settings to this server.

Non-standard ports

To avoid SSH brute force attacks I often run sshd on a port other than 22 (e.g. 9999). That can be annoying if you have to remember to add -p9999 to the ssh command every time.

I can add a Port option to the same ~/.ssh/config host to avoid this:

Host testDroplet dropletA
  <snipped>
  Port 9999

Strict authentication

Passwords are a relic of the 70s and one of the worst ways to authenticate a user. Because of that I always set up SSH key based authentication for my servers. I know I never want to use password authentication for certain hosts so why not disable it outright?

Host testDroplet dropletA
  <snipped>
  PasswordAuthentication no

Visual Host Keys

You might be familiar with SSH showing you "Host Key Fingerprints". Usually the output is something like:

$> ssh dropletA
Host key fingerprint is SHA256:IqtYCzrIVi385SzZvoLuQlfSMQRqneh66RFAB/CZYTA

I don't know about you, but I don't find encoded SHA256 hashes very memorable. Thankfully there's an option for the more visually minded called VisualHostKey:

Host testDroplet dropletA
  <snipped>
  VisualHostKey yes

Now the fingerprint output is visual!

$> ssh dropletA
Host key fingerprint is SHA256:IqtYCzrIVi385SzZvoLuQlfSMQRqneh66RFAB/CZYTA
+---[ECDSA 256]---+
|E++oo.           |
|.+=+.o           |
|.++o. o          |
|o. . o           |
| .o = . S        |
|.. B + o         |
|* B = *          |
|+X = = +         |
|+.Bo  +o.        |
+----[SHA256]-----+

Local Port Fowarding

What if the droplet is running a test service local to the server on port 1234 that doesn't have a firewall rule to allow inbound traffic? Usually I would access this by running ssh testDroplet -L8888:localhost:1234 to make a local port forward for 1234 on the droplet to 8888 on my local machine.

Why not make that automatic too by adding a LocalForward to the ~/.ssh/config!

Host testDroplet dropletA
  <snipped>
  LocalFoward 8888 localhost:1234

(Be careful here, the syntax is slightly different than on the command line)

Dynamic Port Forwarding

Sometimes you don't know what host/port you want to forward through the server. This is called dynamic port forwarding. On the command line using ssh -D 5555 dropletA would make a SOCKS5 proxy on local port 5555 that would forward through dropletA. Of course there's a ~/.ssh/config equivalent to -D too:

Host testDroplet dropletA
   DynamicForward 5555

Jump/Bastion Proxies

If you've worked in high security environments you might be familiar with the "bastion" (or jumpbox) design pattern. Imagine if we had three more servers, dropletB, dropletC, and dropletD and only wanted to allow SSH access through the jumpbox, dropletA. That would mean I would have to run two ssh commands to access dropletC: ssh dropletA and then ssh dropletC. Annoying!

If you're using a modern ssh (7.3 or newer) you can do this all in one command (ssh dropletC) using the handy ProxyJump feature in your ~/.ssh/config for each of the servers behind the jump host:

Host dropletA
  <snipped>
Host dropletB
  ProxyJump dropletA
Host dropletC
  ProxyJump dropletA
Host dropletD
  ProxyJump dropletD

If you're using an old ssh (I believe macOS is too old by default) you can fake the ProxyJump config with ProxyCommand:

Host dropletB
  ProxyCommand ssh -W %h:%p dropletA

Because ProxyJump is so much easier I'll let you read man ssh config to figure out the ProxyCommand arguments if you're curious.

Persistent SSH Connections

I live in a remote area and sometimes have to use extremely slow internet. Sometimes I'll start working on a droplet (ssh dropletA) and later will want to run another command in a different shell (running ssh dropletA again). That's two separate SSH connections by default and if your internet is as slow as mine you'll definitely notice the time it takes to connect once more.

Thankfully SSH has a great feature that lets you use the first connection as a persistent "control master" and have all other SSH connections multiplex on top of it.

I use the following in my ~/.ssh/config:

Host dropletA
  <snipped>
  ControlMaster auto
  ControlPersist 4800
  ControlPath ~/.ssh/control/%r.%h.%p.sock

The complicated looking ControlPath indicates where information about the connection master is stored on disk. Using patterns like %l and %p helps make sure that sshing as different users to different ports on the same server won't overwrite the control master since those should be different connections. With the above ControlPath when I run ssh daniel@dropletA a file in the path ~/.ssh/control/daniel.<dropletA server ip>.<dropletA ssh port>.sock appears. Running ssh daniel@dropletA a second time is lightning fast because it uses the existing connection.

Global Config

The last thing to note is that I often want to set some of these settings for all servers, not just dropletA. You can do that by adding the config under a special * wildcard host:

Host *
  User daniel
  VisualHostKey yes
  Compression yes
  PasswordAuthentication no
  ControlMaster auto
  ControlPersist 4800
  ControlPath ~/.ssh/control/%r.%h.%p.sock

Now for any host I ssh to I'll default to using username daniel, having visual host keys, compression (slow internet remember?), no password auth, and a control master.

Conclusion

I hope this brief tour of the SSH config was helpful to you! You can read further about each one of these options (and more) in the ssh config man page: man ssh config

Posted on by:

cpu profile

Daniel McCarney

@cpu

I live in the woods and help write the free software that powers Let's Encrypt.

Discussion

pic
Editor guide
 

Thanks, nice tips.

Just yesterday I was dealing with a "broken pipe" error message and disconnection problem because of inactivity, I needed to login again and again, then I read about adding the following line to the /etc/ssh/ssh_config file on my linux in order to avoid it:

Host *
ServerAliveInterval 120

 

That's another great tip, thanks for sharing it!

 

This was super helpful. Multiplexing is quite the neat feature.