This series has already covered a few basics about ~/.ssh/config in terms of how to simplify the usage of ssh tunnelling. In order to  round this up a bit more, I will add some information you should be  aware of about ~/.ssh/config. This is only intended to be a quick reminder about how it is done right and some useful hints you might not have heard about.

The following uses examples with pure ssh connection commands, but it is also applicable to establish tunnels with ssh as they all read the same configuration file.

Article seriesSSH tunnelling for fun and profit

  1. Local vs Remote
  2. Tunnel options
  3. AutoSSH
  4. SSH Config


Nope, this time you need to read it all.

Structure of SSH Config

Probably the most important part which is widely overlooked is the order of definition blocks in ~/.ssh/config and accordingly /etc/ssh/ssh_config in terms of generalization and specialization.

You can basically categorize blocks into three stages:

  1. Most specific (without any wildcards)
  2. Some generalization (with wildcard definitions)
  3. General section (which applies to all).

Let’s define a basic ~/.ssh/config containing the examples above and see what it does:

Wrong way

No, what many people do wrong is to define the general stuff at the  top. Let’s do this for a second and see what the outcoming ssh  connection string will be:

Host *
    User root
    Port 22
    PubkeyAuthentication no
    ServerAliveInterval 30

Host c*
    User black
    Port 22
    PubkeyAuthentication yes
    IdentityFile ~/.ssh/id_rsa_black

Host c1

Host c2

If you want to ssh connect to c1 (ssh c1), the file is read as follows:

  1. Find section Host *
  2. Apply User: root
  3. Apply Port: 22
  4. Apply PubkeyAuthentication: no
  5. Apply ServerAliveInterval: 30
  6. Find section Host c*
  7. Ignore User (already defined above)
  8. Ignore Port (already defined above)
  9. Ignore PubkeyAuthentication (already defined above)
  10. Apply IdentityFile
  11. Find section Host c1
  12. Apply HostName:

The final connection string that will be made internally will look like this:

ssh root@ -p 22 -i ~/.ssh/id_rsa_black -o PubkeyAuthentication=no -o ServerAliveInterval=30

Now this is totally not what you intended to do!

Right way

Let’s restructure the ~/.ssh/config into the right order and check the resulting connection string:

Host c1

Host c2

Host c*
    User black
    Port 22
    PubkeyAuthentication yes
    IdentityFile ~/.ssh/id_rsa_black

Host *
    User root
    Port 22
    PubkeyAuthentication no
    ServerAliveInterval 30

The important part to keep track of is the Host section  (aligned to the left). Notice here that the general definitions are at  the very top and more wildcarded definitions (using the asterisk *) are followed below.

If you want to ssh connect to c1 (ssh c1), the file is read as follows:

  1. Find section Host c1 and use its corresponding HostName (
  2. Find more general section Host c* and use their values (User, Port, etc).
  3. Find most general section Host *
  4. Don’t use User as it has already been defined for this connection in c*
  5. Don’t use Port as it has already been defined for this connection in c*
  6. Don’t use PubkeyAuthentication as it has already been defined for this connection in c*
  7. Use ServerAliveInterval as there is no previous definition.

So from that you must always remember that whenever a specific value  has been found, it cannot be overwritten by values defined below. It is a  first come first server here. The final connection string that will be  made internally will look like this:

ssh black@ -p 10022 -i ~/.ssh/id_rsa_black -o PubkeyAuthentication=yes -o ServerAliveInterval=30

Now this is how you intended to connect. So always remember:

  1. Specific definitions at the top
  2. General definitions at the bottom

Why use SSH config anyway?

Simpler usage

Imagine you have a couple of dozens or even hundred servers you have  to take care of. Each of them is having different login options such as:  some still use passwords, others use rsa keys, others ed25519 keys,  lots of different initial users to use for the connection and much more.  Wouldn’t it be much more simple to define everything into a file and  don’t care about the rest anymore?

You could for example use a naming convention for clouded vs. dedicated hosts as so:
c1, c2, c3, …, d1, d2, d3

Or you use hosts per customer:
google1, google2, google3, …, apple1, apple2, apple3

All those hosts might have completely different settings even different ports and you simply need to

$ ssh c1
$ ssh d2
$ ssh google1
$ ssh apple3

Other applications make use of it too

Most programs that make use of ssh can use the same alias specified in ~/.ssh/config with the same options, simply by specifying the alias inside this program.
For example on OSX I am using Sequel Pro to manage all my MySQL connections. Instead of having to specify host,  user, port and certificate (in the ssh tunnel section), I simply only  specify the ssh alias and it will auto-grab all details from my ~/.ssh/config.

I am sure there are many other programs out there that are also able to make use of it.

On top of that, if you need to alter settings of one server, you do  it in a central place and it will have an effect on all tools instantly.


You will have autocompletion (at least under bash or zsh) for every  host and every alias defined. This is true for hosts and even IP  addresses. When I type ssh 1 and hit tab:

$ ssh 1

Note: I have replaced the IP addresses with internal once.


$ ssh c
c1                                        c4                    c16                    
c10                                       c5                   c17                    
c11                                       c6                   c18                    

Note: I have replaced the domains with once.


Within the most general configuration section you can define settings that must be applied for every ssh ... you type.

So hopefully the ~/.ssh/config has raised your attention by now.

What your mother never told you about ~/.ssh/config

Identity leak via ssh keys

If you are a big fan of ssh keys in combination with ssh-agent,  then you should be aware that once you connect to any ssh server, all  of your public keys that are hold by your ssh-agent, are sent to this  server.

You can check which keys are stored inside your ssh-agent via ssh-add.

$ ssh-add -l
4096 SHA256:111_SSH_HASH_111 /home/black/.ssh/id_rsa_black (RSA)
256  SHA256:111_SSH_HASH_111 /home/black/.ssh/id_ed25519_black

By default, if you do not manually add any keys via ssh-add, all defaults (no custom name) for rsa, dsa ecdsa and ed25519 (usually id_rsa, id_dsa, id_ecdsa and id_ed25519) are added to the ssh-agent (once they are created).

So this means, if you have created one default rsa key simply by typing ssh-keygen, you will have this key ~/.ssh/id_rsa and this key will also be added to your ssh-agent by default.

This means if you connect a lot to many untrusted ssh servers, they  might log your keys (just like websites track you via cookies) and might  be able to identify.

The problem has been address by which can identify your github name.

Test if your ssh client settings are vulnerable to github identity leak:

$ ssh

This is the example from:, make sure to visit this github page.

What FiloSottile recommends is to turn off public key  authentification in general and explicitly turn it on per host (where u  need it):

# Turn on pubkey auth per specific HOST
Host c1
    PubkeyAuthentication yes
    IdentityFile ~/.ssh/id_rsa_specific

# Turn off pubkey auth for all hosts
Host *
    PubkeyAuthentication no
    IdentitiesOnly yes

Securing known_hosts

Let’s look at a line of a typical ~/.ssh/known_hosts file:, ssh-rsa AAAA1234.....=

Space separated fields in order of occurance
1. [optional] markers
2. hostnames (comma separated)
3. Bits, exponent and modulus
4. [optional] comment (not used)

This file is pretty talkative and can tell all the hosts you have  visited so far and therefore has some implications. You can read more  about the problems here: Protecting SSH from known_hosts Address Harvesting

So in order to only store hashes of the hostnames inside ~/.ssh/known_hosts, you will need to alter ~/.ssh/config:

Host *
    HashKnownHosts yes

The hashed version for the file will look like this:

|1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa AAAA1234.....=

Note 1: Keep in mind that the hashing will start from now on and previous entries will not be hashed.

Note 2: With hashing you will loose the autocompletion feature from known_hosts, but when you use aliases, you still have the alias based autocompletion described above.

Multiple connections inside a single one

SSH needs some time establishing a connection. This time grows as you  use stronger/bigger private/public key-pairs. However, if a server  receives a lot of connections, this time might matter and fortunately  there is a way to reduce it by multiplexing multiple ssh connections  over a single one from the same host/user by re-using an already  established connection.

So how can this be established? Again, you can configure this behavior inside your ~/.ssh/config globally as the following example shows:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

OptionDescriptionControlMasterTell SSH to re-use an existing connection (if there is already an established one) without having to authenticate again.ControlPathThis is the path of the socket for open SSH  connections. Every new connection will hook into this socket and can use  the already established connectionControlPersistKeep the master (the first) SSH connection open for X  seconds after the last connection has been closed. This means you have X  seconds to connect again without authentification after all connections  have been closed to this host.

Where does this matter?


If your nagios server does multiple SSH checks (check_ssh)  against one server, it is recommended to setup the nagios’ servers ssh  client to re-use existing ssh connections in order to speed up those  checks.


If you do a lot of work with git very frequently like pushing, using  the autocomplete feature (which requires some remote connection to  upstream), etc you are probably also a candidate to re-use existing SSH  connections.

I am myself are not a fan of enabling the whole thing globally  (except for the nagios server), but rather for specific use cases.
So If you want to enable this for specific hosts only you could do it like that:

# For some host
Host c1
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

# For github usage
    User git
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

Private ssh key leak

Have you heard about the recents cve’s about possible private key leaks via ssh to a malicious SSH server: CVE-2016-0777 and CVE-2016-0778.

In order to avoid this possible vulnerability add the following undocumented setting to your ~/.ssh/config at the bottom inside the general section:

Host *
    UseRoaming no

Useful tools

As I have lots of ssh hosts configured in my ~/.ssh/config and it would be impossible for me to remember which domain is hosted on  which server (especially if a single server is having more than 20  separate domains), I am using a little helper script, that will search  my ssh configuration file for a given domain or any other keyword and  will present me the server it is hosted on.

For example, If I want to know on which server is hosted I can simply type:

$ sshf everything

So it told me, that there are two domains on server c1 including the one I was looking for (which will be auto-highlighted via grep --color). No I can simply go there via:

ssh c1

So if you find this useful, you can find the script at github: