===============
== bacardi55 ==
===============
ἕν οἶδα ὅτι οὐδὲν οἶδα

A clean ssh (client) configuration thanks to includes

- Permalink

This post could be resumed as “TIL: ~/.ssh/config can now include other files”, but in the end I opted for a longer version of that :).

Since I had to redo my full laptop setup from scratch, one thing I had to redo was my ssh configuration. First, creating the ssh keys, which is easy enough by using the ssh-keygen command (in my case, I used ssh-keygen -t ed25519).

But the second step was to use the ~/.ssh/config file. It isn’t mandatory, as you can simply write your ssh command with the right options each time, but using many different ssh keys for different usage, as well as prefering using the server name than the full hostname, the ~/.ssh/config file can be very useful. For the latest part, I used to manage it via /etc/hosts, but I think this is a cleaner way (very subjective).

I’m sure most people stumbling on this blog will know this, but here is an example of an entry in my config file:

Host <name>
    Hostname <hostname>
    User <user>
    IdentityFile ~/.ssh/<sshKeyForThisHostname>
    IdentitiesOnly yes
    AddKeysToAgent yes
    PreferredAuthentications publickey

It is just an example, there are more options but these are the one I used the most. In this example:

  • Hostname is the address of your server
  • IdentityFile contains the path to the ssh key to use
  • IdentitiesOnly will limit for this host this identiy, even if other are already unlocked via ssh-agent
  • PreferredAuthentications indicates the preferred order for authentication, in my case only public key
  • AddKeysToAgent add the key to the ssh-agent to avoid typing your password every time (see below)
  • User if you need to connect with a different user than the current one

Host can either be the server name or something more complex including a wildcard. For example, my sourcehut entry is Host *sr.ht, so that evey ssh/scp command for the sr.ht hostname or any subdomain will used this configuration (and thus the dedicated ssh key). In such case, the Hostname line can even be ignored:

Host *sr.ht
    IdentityFile ~/.ssh/sourcehut
    IdentitiesOnly yes
    AddKeysToAgent yes
    PreferredAuthentications publickey

For my local server that use only a local DNS (subdomain of bacardi55.local), a typical entry would look like below:

Host luffy
    Hostname luffy.bacardi55.local
    IdentityFile ~/.ssh/proxmox
    IdentitiesOnly yes
    AddKeysToAgent yes
    PreferredAuthentications publickey

I could potentially simplify this by using more advanced options with wildcard and hostname patterns like !, but I find it less clear and do prefer an entry per server / VM / Container.

Little by little, my ~/.ssh/config started to become very long… Too long for my taste… Granted it was also the case before, but adding so many entries in such a short amount of time in a large file really annoyed me. And after a quick search to see if it was possible, I learned that ~/.ssh/config can include other files! I should have known this as apparently is has been there for many years now… But I didn’t (old habits die hard). To do so, simply use Include path/to/file. The path needs to be relative to where the config file is. My config file is now much cleaner now and simply has 5 lines:

Include config.d/proxmox
Include config.d/local
Include config.d/work
Include config.d/sourcehut
Include config.d/digitalocean

As you can see, I now split per ssh key the configuration. All “subconfig” files are in ~/.ssh/config.d. The config.d/proxmox contains the configuration for all proxmox related hosts, VMs and containers, config.d/local contains other local servers (eg: my raspberry pi), and so on…

I could have simplified even more using a wildcard:

Include config.d/*

But I prefer manually including the files. It would allow me to stop including one without deleting the config if one day that is needed for any reason.

EDIT October 2025: To avoid your identity (keys) to all be tested when trying to connect to an ssh server not yet declared in your config, you should add at the top of the ~/.ssh/config file:

Host *
  IdentitiesOnly=yes

Read more about this here.

Now one last thing to avoid typing the password multiple time in a row while using the same key. For that I use the ssh-agent service included with systemd. I use it at the user level, not globally. To enable and start it, simply run:

systemctl --user enable ssh-agent.service
Created symlink /home/bacardi55/.config/systemd/user/default.target.wants/ssh-agent.service → /home/bacardi55/.config/systemd/user/ssh-agent.service.

systemctl --user start ssh-agent.service

This is the goal of the AddKeysToAgent yes option in the ssh config above, to add the key to the running ssh-agent and unlock your key only once.

To make it work, you also need your shell to be aware of the SSH_AUTH_SOCK that must contain the path to the socket. To do so, add the following either in your ~/.zshrc (or ~/.bashrc, …) or in your ~/.profile (I choose the former):

export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"

And that should be it, you should be able to unlock your ssh key for your entire session at its first use.


Contact

If you find any issue or have any question about this article, feel free to reach out to me via webmentions, email, mastodon, matrix or even IRC, see the About page for details.