Since I joined Charm, I’ve been working and learning more about SSH, and I thought I would share a few quick tips and tricks with you.

Forward Yubikey Agent

If you use a Yubikey (you should), you can use it in your remotes by having the key in a SSH agent and forwarding it.

To manage the agent, I strongly recommend yubikey-agent.

You can then forward it in your ~/.ssh/config like the following:

Host example.org
  ForwardAgent true

And then, after SSHing you can check its working by running:

ssh-add -L

Which should list your key.

You might also want to add this to your ~/.tmux.conf, so the agent works properly on reconnect:

set -g update-environment "DISPLAY SSH_ASKPASS SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY"
setenv -g SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock

You’ll also need to create a ~/.ssh/rc with the following content in your target machine:

#!/bin/bash
if test "$SSH_AUTH_SOCK" ; then
  ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
fi

SSH runs this file when connecting, and it’ll override a local link to the agent socket, which we use as our actual SSH_AUTH_SOCK (see the tmux config above).

You can learn more about it by reading this blog post.

By the way, do not enable this to all hosts, as it might be considered insecure, especially if you are using a shared user. I only do this on a local server in my home network.

Reuse connections

If you connect and disconnect from some machines “a lot”, or, maybe, you’re using some sort of SSH application or API, you might benefit from keeping a connection open and reusing it.

You can do so by adding something like this to your ~/.ssh/config:

Host example.org
  ControlMaster    auto
  ControlPath      ~/.ssh/%r@%h:%p.sock
  ControlPersist   yes

This will create a Unix Socket at ~/.ssh/user@host:port.sock, and use that connection when it is available.

Eventually the server will close the connection (on its timeout), or you can force it by running:

ssh -O exit example.org

You can also force a given max time for a socket to be alive by setting ControlPersist to a duration instead of yes, e.g. ControlPersist 60s, so it’ll be kept open for at most 1 minute.

Also worth noting that its not very safe to do this in just about any server you have access to, especially if you set ControlPath to, say, /tmp.

SSH straight into tmux

If you work into a remote machine like I do, its likely you use a multiplexer as well, like tmux for example. If that’s the case, you might want to SSH directly into a predefined tmux session to speed things up.

You can do so by adding something like this to your ~/.ssh/config:

Host example.org
	RemoteCommand tmux new -A -s default

This will either attach to or create and attach to a session named default. This is what I use regularly, and it works like a charm.

Alias commonly used hosts

If you SSH into a host very often, you might want to have a shorter name for it.

A common way to go around that is with a shell alias, but you can also do so with pure SSH config.

For instance:

Host ex
  HostName example.org
  User foo
  Port 2223

Will allow you to, instead of typing:

ssh foo@example.org -p 2223

Type:

ssh ex

Instead.

I particularly use this in conjunction with some previous tips in my development server, so I can simply ssh dev and get into a tmux session, with my Yubikey SSH agent forwarded, with a simple command.

Do not add testing stuff to ~/.ssh/known_hosts

I develop some SSH apps using Wish, and I usually test them locally quite a bit. This might end up cluttering my ~/.ssh/known_hosts file, also leading to key checking errors.

I prevent that by disabling strict key checking and using /dev/null as the known hosts file on localhost:

Host localhost
	UserKnownHostsFile /dev/null
	StrictHostKeyChecking no

You can use globs in the Host part, so you can, for example, do the same for your company testing servers or something in that sense.

Make connections last longer

If the server has a short idle timeout, it might disconnect you sooner than you wish. You can prevent that by having your client ping the server every X time.

You can do so by adding something like this to your ~/.ssh/config:

Host *
	ServerAliveInterval 60

This will ping the server every 60 seconds for all hosts.

Canonicalize hostnames

If you access multiple machines in the same TLD, you might want to enable hostname canonicalization:

Host *
  CanonicalizeHostName yes
  CanonicalizeFallbackLocal yes
  CanonicalDomains mytld.foo.bar

That way, to SSH into host1.mytld.foo.bar, you can simply run:

ssh host1

It might be particularly useful for .local, so you can access other machines in your network with just their name, without the .local suffix.

Yubikey and GitHub, without touching it every time

If you find it a bit annoying that yubikey-agent asks you to touch it every time you do anything with Git, this might be helpful, although it is a bit against the principles of using a Yubikey.

In any case, here you go:

Host github.com
  ControlMaster        auto
  ControlPath          ~/.ssh/github.sock
  ControlPersist       10s
  ServerAliveInterval  0

This will use the ControlPersist tip we saw earlier, but instead of closing the connection after the server times it out, we explicitly tell it to last 30 seconds. We also disable the ServerAliveInterval feature.

So what happens is here:

  • when you do some remote git operation, it’ll open the socket, asking you to touch the Yubikey
  • if you do another operation in the next 10 seconds, it will reuse the same connection
  • 10 seconds after the initial connection, the socket will be closed, and you’ll have to authenticate again

It might be useful when you do a lot of git operations at the same time, e.g. update Vim plugins.

That’s it!

That’s what I wanted to share today. Let me know if you have more tips or tricks I forgot to mention or don’t know about, I’d love to learn them!

Cheers!