SSH, or Secure Shell, is the most common way of connecting to Linux servers for remote administration. Although connecting to a single server via the command line is relatively straightforward, there are many workflow optimizations for connecting to multiple remote systems.
OpenSSH, the most commonly used command-line SSH client on most systems, allows you to provide customized connection options. These can be saved to a configuration file that contains different options per server. This can help keep the different connection options you use for each host separated and organized, and avoids having to provide extensive options on the command line whenever you need to connect.
In this guide, we’ll cover the structure of the SSH client configuration file, and go over some common options.
To complete this guide, you will need a working knowledge of SSH and some of the options that you can provide when connecting. You should also configure SSH key-based authentication for some of your users or servers, at least for testing purposes.
Each user on your system can maintain their own SSH configuration file within their home directory. These can contain any options that you would use on the command line to specify connection parameters. It is always possible to override the values defined in the configuration file at the time of the connection by adding additional flags to the ssh
command.
The client-side configuration file is located at ~/.ssh/config
– the ~
is a universal shortcut to your home directory. Often, this file is not created by default, so you may need to create it yourself. The touch
command will create it if it does not exist (and update the last modified timestamp if it does).
- touch ~/.ssh/config
The config
file is organized by hosts, i.e., by remote servers. Each host definition can define connection options for the specific matching host. Wildcards are also supported for options that should have a broader scope.
Each of the sections starts with a header defining the hosts that should match the configuration options that follow. The specific configuration items for that matching host are then defined below. Only items that differ from the default values need to be specified, as each entry will inherit the defaults for any undefined items. Each section spans from one Host
header to the following Host
header.
Typically, for organizational purposes and readability, the options being set for each host are indented. This is not a hard requirement, but a useful convention that allows for interpretation at a glance.
The general format will look something like this:
Host firsthost
Hostname your-server.com
User username-to-connect-as
IdentityFile /path/to/non/default/keys.pem
Host secondhost
ANOTHER_OPTION custom_value
Host *host
ANOTHER_OPTION custom_value
Host *
CHANGE_DEFAULT custom_value
Here, we have four sections that will be applied on each connection attempt depending on whether the host in question matches.
It is important to understand the way that SSH will interpret the file to apply the configuration values. This has implications when using wildcards and the Host *
generic host definition.
SSH will match the host name provided on the command line with each of the Host
headers that define configuration sections.
For example, consider this definition:
Host devel
HostName devel.example.com
User tom
This host allows us to connect as tom@devel.example.com
by typing this on the command line:
- ssh devel
SSH starts at the top of the config file and checks each Host
definition to see if it matches the value given on the command line. When the first matching Host
definition is found, each of the associated SSH options are applied to the upcoming connection.
SSH then moves down the file, checking to see if other Host
definitions also match. If another definition is found that matches the current hostname given on the command line, it will consider the SSH options associated with the new section. It will then apply any SSH options defined for the new section that have not already been defined by previous sections.
This is an important point. SSH will interpret each of the Host
sections that match the hostname given on the command line, in order. During this process, it will always use the first value given for each option. There is no way to override a value that has already been given by a previously matched section.
This means that your config
file should follow the rule of having the most specific configurations at the top. More general definitions should come later on in order to apply options that were not defined by the previous matching sections.
Let’s look again at the example from the previous section:
Host firsthost
Hostname your-server.com
User username-to-connect-as
IdentityFile /path/to/non/default/keys.pem
Host secondhost
ANOTHER_OPTION custom_value
Host *host
ANOTHER_OPTION custom_value
Host *
CHANGE_DEFAULT custom_value
Here, we can see that the first two sections are defined by literal hostnames (or aliases), meaning that they do not use any wildcards. If we connect using ssh firsthost
, the very first section will be the first to be applied. This will set Hostname
, User
, and IdentityFile
for this connection.
It will check the second section and find that it does not match and move on. It will then find the third section and find that it matches. It will check ANOTHER_OPTION
to see if it already has a value for that from previous sections. Finding that it doesn’t, it will apply the value from this section. It will then match the last section since the Host *
definition matches every connection. Since it doesn’t have a value for the mock CHANGE_DEFAULT
option from other sections, it will take the value from this section. The connection is then made with the options collected from this process.
Let’s try this again, pretending to call ssh secondhost
from the command line.
Again, it will start at the first section and check whether it matches. Since this matches only a connection to firsthost
, it will skip this section. It will move on to the second section. Upon finding that this section matches the request, it will collect the value of ANOTHER_OPTION
for this connection.
SSH then looks at the third definition and find that the wildcard matches the current connection. It will then check whether it already has a value for ANOTHER_OPTION
. Since this option was defined in the second section, which was already matched, the value from the third section is dropped and has no effect.
SSH then checks the fourth section and applies the options within that have not been defined by previously matched sections. It then attempts the connection using the values it has gathered.
Now that you have an idea about how to write your configuration file, let’s discuss some common options and the format to use to specify them on the command line.
The first ones we will cover are the minimum settings necessary to connect to a remote host. Namely, the hostname, username, and port that the SSH server is running on.
To connect as a user named apollo
to a host called example.com
that runs its SSH daemon on port 4567
from the command line, you could run ssh
like this:
ssh -p 4567 apollo@example.com
However, you could also use the full option names with the -o
flag, like this:
ssh -o "User=apollo" -o "Port=4567" -o "HostName=example.com"
You can find a full list of available options in the SSH manual page.
To set these in your config
file, you have to choose a Host
header name, like home
:
Host home
HostName example.com
User apollo
Port 4567
So far, we have discussed some of the options necessary to establish a connection. We have covered these options:
Host
header. This option is not necessary if the Host
definition specifies the actual valid address to connect to.22
.There are many other useful options worth exploring. We will discuss some of the more common options, separated according to function.
ServerAliveInterval
: This option can be configured to let SSH know when to send a packet to test for a response from the server. This can be useful if your connection is unreliable and you want to know if it is still available.
LogLevel
: This configures the level of detail in which SSH will log on the client-side. This can be used for turning off logging in certain situations or increasing the verbosity when trying to debug. From least to most verbose, the levels are QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG1, DEBUG2, and DEBUG3.
StrictHostKeyChecking
: This option configures whether ssh SSH will ever automatically add hosts to the ~/.ssh/known_hosts
file. By default, this will be set to “ask” meaning that it will warn you if the Host Key received from the remote server does not match the one found in the known_hosts
file. If you are constantly connecting to a large number of ephemeral hosts (such as testing servers), you may want to turn this to “no”. SSH will then automatically add any hosts to the file. This can have security implications if your known hosts ever do change addresses when they shouldn’t, so think carefully before enabling it.
UserKnownHostsFile
: This option specifies the location where SSH will store the information about hosts it has connected to. Usually you do not have to worry about this setting, but you may wish to set this to /dev/null
so they are discarded if you have turned off strict host checking above.
VisualHostKey
: This option can tell SSH to display an ASCII representation of the remote host’s key upon connection. Turning this on can be a useful way to get familiar with your host’s key, allowing you to recognize it if you have to connect from a different computer sometime in the future.
Compression
: Turning compression on can be helpful for very slow connections. Most users will not need this.
With the above configuration items in mind, we could make a number of useful configuration tweaks.
For instance, if we are creating and destroying hosts very quickly at a cloud provider, something like this may be useful:
Host home
VisualHostKey yes
Host cloud*
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel QUIET
Host *
StrictHostKeyChecking ask
UserKnownHostsFile ~/.ssh/known_hosts
LogLevel INFO
ServerAliveInterval 120
This will turn on your visual host key for your home connection, allowing you to become familiar with it so you can recognize if it changes or when connecting from a different machine. We have also set up any host that begins with cloud* to not check hosts and not log failures. For other hosts, we have sane fallback values.
One common use of SSH is forwarding connections, either allowing a local connection to tunnel through the remote host, or allowing the remote machine access to tunnel through the local machine. This is sometimes necessary when you need to connect to a remote machine behind a firewall through a separate, designated “gateway” server. SSH can also do dynamic forwarding using protocols like SOCKS5 which include the forwarding information for the remote host.
The options that control this behavior are:
LocalForward
: This option is used to specify a connection that will forward a local port’s traffic to the remote machine, tunneling it out into the remote network. The first argument should be the local port you wish to direct traffic to and the second argument should be the address and port that you wish to direct that traffic to on the remote end.
RemoteForward
: This option is used to define a remote port where traffic can be directed to in order to tunnel out of the local machine. The first argument should be the remote port where traffic will be directed on the remote system. The second argument should be the address and port to point the traffic to when it arrives on the local system.
DynamicForward
: This is used to configure a local port that can be used with a dynamic forwarding protocol like SOCKS5. Traffic using the dynamic forwarding protocol can then be directed at this port on the local machine and on the remote end, it will be routed according to the included values.
These options can be used to forward ports in both directions, as you can see here:
# This will allow us to use port 8080 on the local machine
# in order to access example.com at port 80 from the remote machine
Host local_to_remote
LocalForward 8080 example.com:80
# This will allow us to offer access to internal.com at port 443
# to the remote machine through port 7777 on the other side
Host remote_to_local
RemoteForward 7777 internal.com:443
This is especially useful when you need to open a browser window to a private dashboard or another web application running on a server that is not directly accessible other than over SSH.
Along with connection forwarding, SSH allows other types of forwarding as well.
You can forward any SSH keys stored in an agent on your local machine, allowing us to connect from the remote system using credentials stored on your local system. You can also start applications on a remote system and forward the graphical display to our local system using X11 forwarding. X11 is a Linux display server and is not very intuitive to use without a Linux desktop system, but can be very useful if you are using both a remote and a local Linux environment.
These are the directives that are associated with these capabilities:
ForwardAgent
: This option allows authentication keys stored on our local machine to be forwarded onto the system you are connecting to. This can allow you to hop from host-to-host using your home keys.
ForwardX11
: If you want to be able to forward a graphical screen of an application running on the remote system, you can turn this option on.
If you have SSH keys configured for your hosts, these options can help you manage which keys to use for each host.
IdentityFile
: This option can be used to specify the location of the key to use for each host. SSH will use keys located in ~/.ssh
by default, but if you have keys assigned per-server, this can be used to specify the exact path where they can be found.
IdentitiesOnly
: This option can be used to force SSH to only rely on the identities provided in the config
file. This may be necessary if an SSH agent has alternative keys in memory that are not valid for the host in question.
These options are especially useful if you have to keep track of a large number of keys for different hosts and use one or more SSH agents to assist.
As long as you keep in mind the way that SSH will interpret the values, you can establish rich sets of specific values with reasonable fall backs.
If you ever have to use SSH over a very poor or intermittent connection such as airplane Wi-Fi, you can also try using mosh, which is designed to make SSH work under adverse circumstances.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Great tutorial. I think that worth noting would be that OpenSSH 7.3p1 and up supports Include directive, which allows us to organize config files. Eg. adding
Include config.d/*
in ~/.ssh/config will load all config files from ~/.ssh/config.d assuming that directory exists as well as config files in it. I use this to separate my private and work SSH settings whilst on same account. Source of info: superuser.comThank you !!! Amazing tutorial, just what i needed. Until now i have used local bash_profile and zshrc file to keep ssh connections as aliases, but now i have moved them to separated file in ~/.ssh/config
Another benefit of storing data in ~/.ssh/config file is that i moved that file to my Dropbox, and created soft link, so i have stored connections in the cloud and available to all my computers :)
Here is how simple is it:
// move config file to dropbox folder sync/ssh mv ~/.ssh/config ~/Dropbox/sync/ssh
// make soft link ln -s ~/Dropbox/sync/ssh/config ~/.ssh/config
One more note, if you get bed permissions error, you should execute this command chmod 600 ~/.ssh/config
Or use: nssh
Very helpful! Very clearly explained!
This was a great article! I have been wanting to create/learn how to do something like this for some time now. For what ever reason today is the day I started to research how. After looking over a few articles I found this one and was able to setup my config file in minutes. WHAT a time saver! Thank you for having this out as a resource.
Great article, exactly what i expected in order to get my ultime ssh config file for production !
Came in handy, thanks!
very helpful!