I touched on this topic in my First Day with Ubuntu at the Office post under Accessing Remove File Systems; however, I thought that this deserved its own topic.

For those that don’t know SSH stands for Secure SHell. In very non-technical terms, SSH allows you to access a system running a SSH server over a network. This other system can be another computer in your home or a remote system on the other side of the planet. SSH will allow you to connect to that other system and communicate with it securely. All the data passed back and forth is encrypted, so you don’t have to worry about people sniffing your passwords or valuable data.

You may be asking what all of that means to you. What it means is that you can connect to and control a computer that is somewhere else with the computer that is sitting right in front of you. If you have a remote web server running Linux, SSH will let you install software, edit files, change the server configuration, access the database, and more. Did you forget a file on your computer at home? No problem, just SSH into your home computer and send the file to your email account or copy it directly to your office computer.

Hopefully those quick examples of what you can do is enough to whet your appetite.

Making SSH Work for You

When working on a Linux system, connecting to other Linux systems via SSH becomes so easy. Everything you need is bundled directly into the OS. All you need to do is load up the terminal and run something that looks like the following:

[chris@home ~]$ ssh remoteuser@host
remoteuser@host's password:
[remoteuser@host ~]$ 

So, if this is so easy, you might wonder what could make this any simpler. While the process I just described is definitely easy, there is always some server out there that requires a ssh command that is just difficult enough to be annoying. For example, imagine having to type the following each time you wanted to connect:

[chris@home ~]$ ssh -p 2222 -2 -c blowfish-cbc,aes256-cbc really_long_username@locutus.borg.domain.com

While it’s possible to remember this, who wants to?

Host-Based Config Options

Fortunately, ssh has a way to store options for each host. The default location for this file is at ~/.ssh/config. The file accepts config entries with the following format:

Host hostname
    option value
    option value

Taking the long ssh command example from above, we can create the following config entry:

Host locutus.borg.domain.com
    User really_long_username
    Port 2222
    Protocol 2
    Cipher blowfish-cbc,aes256-cbc

After adding this to ~/.ssh/config, I can connect to the host using just the following:

[chris@home ~]$ ssh locutus.borg.domain.com
really_long_username@locutus.borg.domain.com's password:
[really_long_username@locutus.borg.domain.com ~]$ 

Easy cheesy.

There are a large variety of options available for the host-based config. For a full list of these options, run man ssh_config from terminal.

Creating Hostname Aliases

Given the previous example, the hostname is locutus.borg.domain.com. That’s quite a bit to type, and it isn’t easy to remember how to spell locutus properly. Fortunately, the config file comes to the rescue again.

We can update our previous host definition to the following:

Host locutus.borg.domain.com locutus borg loc domain.com 192.168.1.105
    Hostname locutus.borg.domain.com
    User really_long_username
    Port 2222
    Protocol 2
    Cipher blowfish-cbc,aes256-cbc

Now I can easily connect to the system using any of the following commands:

[chris@home ~]$ ssh locutus.borg.domain.com
[chris@home ~]$ ssh locutus
[chris@home ~]$ ssh borg
[chris@home ~]$ ssh loc
[chris@home ~]$ ssh domain.com
[chris@home ~]$ ssh 192.168.1.105

Simply set up all the alias names you’d like to have after “Host” while separating each one with a space. I always keep the original hostname in the list and add an additional alias to is easy to remember and type.

Keep the Connection Alive

Due to issues either caused by certain routers’ NAT firewalls or due to odd server configurations, I have found that my SSH connections will die if I leave then idle for too long. This is very annoying as it leaves me with a frozen session that I can’t do anything with. Fortunately, config comes to the rescue again. On each and every one of my host options in my config files, I have a ServerAliveInterval option that tells ssh to send a small keep-alive packet to the server at an interval that I specify.

For example:

Host domain.com
    User chris
    ServerAliveInterval 10

This tells ssh to send a keep-alive packet every 10 seconds. Now the only thing that terminates my connection is an actual loss of internet connection.

Using Keypairs to Increase Security

SSH has the ability to use security keypairs to authenticate your session with the server. A security key can replace the need to supply your password when connecting to your server.

If you have access to modify your server’s SSH daemon settings, you can use your authentication key to disable password authentication. This means that an attacker would have to break your key’s encryption in order to connect rather than just having to guess your password.

Another great feature of keys is that you can use the same key for multiple server accounts. Since the private part of your key only resides on your local system, using the same key for multiple systems doesn’t decrease security in the same way that using the same password on multiple servers can. For example, if someone broke into one of your server accounts, they could only get your public key, and an attacker cannot use your public key to gain access to other servers.

What This Means for Shared Servers

If your server is a shared host where you don’t have access to root, you typically can’t disable password authentication; however, keys can still greatly increase your security. Since you won’t need to supply your user’s password each time you connect since the key is doing the authentication, you can change your user’s password to something extremely strong and complex. This will make it very difficult for anyone to break into your account using brute-force methods.

Generating an SSH Authentication Key

Update: This guide originally instructed on how to create a DSA key. DSA keys are now considered to be too weak for reliable security use. This section has been updated to create an RSA key using options that, as of early 2016, are considered to be in keeping with the current best practices.

I also like using Ed25519 keys; however, not all servers support authentication with this method. So, I typically have both RSA and Ed25519 keys on each of my systems and only use the RSA key if the server doesn’t support Ed25519. You can generate an Ed25519 key as follows:

[chris@home ~]$ ssh-keygen -t ed25519 -o -a 100

Generating an SSH authentication key is very simple. Most major distributions have all the software you need already installed. To generate your key, run the following command in terminal:

[chris@home ~]$ ssh-keygen -t rsa -b 4096 -o -a 100
Generating public/private rsa key pair.
Enter file in which to save the key (/home/chris/.ssh/id_rsa):
Enter passphrase (empty for no passphrase): strong password
Enter same passphrase again: strong password
Your identification has been saved in /home/chris/.ssh/id_rsa.
Your public key has been saved in /home/chris/.ssh/id_rsa.pub.
...
[chris@home ~]$ 

This command will create a strong, 4096 bit RSA key that uses a storage format that has added resistance against brute-force attacks on the key’s password.

Supplying the password is optional. If you simply press enter without supplying a password, your key won’t require a password to use. While this simplicity is tempting, I highly recommend using a strong password for the following reasons:

  • Unlike some password protection methods where the password is easily cracked, your key’s password is an integral part of the key. Without your password, the key is useless.
  • If your key does not have a password, anyone who manages to gain access to your private key will have the ability to connect to every server your key is authenticated for without any password or other authentication required.
  • Many desktop Linux distros will offer to remember your key’s password for as long as your user is logged in, thus giving you a nice balance of security and simplicity.

As you can see, there are great benefits to using a password on your key. There really aren’t any good reasons to not put a password on the key since many distros will remember it for you.

By now, you should have generated your key. If you accepted the default location, you should have two new files in your ~/.ssh directory: id_rsa and id_rsa.pub.

The ~/.ssh/id_rsa file is your private key. Keep this file safe and secure on your system and do not reuse it for other systems.

The ~/.ssh/id_rsa.pub file is your public key. The public key does not need to be kept secret. In fact, it is meant to be shared as your public key is what is added to a server in order for your key to authenticate you on that server.

The permissions on the ~/.ssh/id_rsa file should be automatically set up correctly by ssh-keygen. I like to make sure however as the wrong permission settings can cause the key to be ignored when authenticating. You can set the correct permissions by running:

[chris@home ~]$ chmod 0600 ~/.ssh/id_rsa
[chris@home ~]$ 

Now it’s time to set up the server.

Setting Up Your Server

Now you need to log into the server you want to use your key to authenticate with.

You will need to create a ~/.ssh folder if one doesn’t already exist:

[chris@home ~]$ mkdir -p ~/.ssh
[chris@home ~]$ 

The -p will prevent an error from being thrown if the folder already exists.

Exit out of your server connection. We’re going to do a slick command from our Ubuntu terminal to add our public key to the server.

From the desktop’s terminal (not the server’s command line), run the following:

[chris@home ~]$ cat ~/.ssh/id_rsa.pub | ssh hostname "cat >> ~/.ssh/authorized_keys"
username@hostname's password:
[chris@home ~]$ 

Replace hostname with the hostname that you use to connect to your server with. I’m assuming that you followed my instructions earlier and set up your ~/.ssh/config file to not require anything more than a hostname to set all the options needed to connect. If you haven’t done this, make sure you specify the port number (if other than 22), username, and any other necessary options to make the connection.

Note: The above command is to append the public SSH key to the end of a file located at ~/.ssh/authorized_keys on the server. If the file does not already exist, a new file will be created to add the content to.

Testing

Now we just need to connect to the server again and see what happens.

[chris@home ~]$ ssh hostname
Enter passphrase for key '/home/chris/ssh/id_rsa':
[username@hostname ~]$ 

If your key has a password, you will either get a new window that pops up and asks for your key’s password or get a text prompt for the key’s password as shown above. After supplying the correct password, you should be logged into the host.

If your key does not have a password, you should instantly log into the host without any password prompts.

If you are asked for the host user’s password (such as receiving the username@hostname's password: prompt), your authentication key was either not recognized, had improper permissions, or was not able to match with the server’s public key setting. A good way of checking on a potential problem is to run:

[chris@home ~]$ ssh -v hostname

This will cause a large amount of verbose debug data to be printed during the connection phase. If the key is used properly, you should see the lines listed:

debug1: identity file /home/chris/.ssh/id_rsa type 2
...
debug1: Authentications that can continue: publickey,keyboard-interactive
debug1: Next authentication method: publickey
debug1: Offering public key: /home/chris/.ssh/id_rsa
...
debug1: Authentication succeeded (publickey)

If you don’t see that the server can see the publickey authentication method or if that method isn’t the first one, your server isn’t set up to do key authentication. Contact your hosting provider and ask them if they can add this as it will increase server security.

If you can’t figure out the problem, please let me know. You can put the output of your ssh -v hostname command in Pastebin and put a link to it in a comment. I’ll do my best to help you out.

My .ssh/config File

For those that may wonder, here is what my ~/.ssh/config file looks like (sanitized of course).

# Generate keys:
#ssh-keygen -t ed25519 -o -a 100
#ssh-keygen -t rsa -b 4096 -o -a 100


### Global ###

HashKnownHosts yes


### Local Servers ###

Host vm-docker
	Hostname 192.168.56.150

Host vm-dev
	Hostname 192.168.56.151


### Personal Computers ###

Host juiz
    Hostname example.com
    Port 2222

Host router
    Hostname 127.0.0.1
    User root
    Port 7102

Host tenshi
    Hostname example.com


### Personal VPS Servers ###

# https://manager.linode.com/
# Dallas, Texas
# $25/month - Xen, 2 shared cores, 2GB RAM, 48GB SSD, 3TB/month@250mbps, 1 IPv4, 1 IPv6, includes automated backups
Host linode
    Hostname example.com

# https://my.vultr.com/
# Dallas, Texas
# $5/month - KVM, 1 shared core, 768MB RAM, 15GB SSD, 1TB/month@1gbps, 1 IPv4, 1 IPv6
Host vultr
    Hostname example.com
    Port 5167


### Office Servers ###

Host dominix
    Hostname example.com

Host incursus
    KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1
    Hostname example.com
    User user1

Host tristan
    Hostname 127.0.0.1
    User root

Host navitas
    Hostname 127.0.0.1

Host velator
    Hostname 127.0.0.1
    User user1
    Port 4785


### Global Host Config ###

Host *
    AddressFamily inet
    Compression yes
    ServerAliveInterval 10
    ControlMaster auto
    ControlPersist 3600
    ControlPath ~/.ssh/socket-%r@%h:%p

    # https://cipherli.st/
    KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-ripemd160-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,umac-128@openssh.com
    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr

    # http://www.openssh.com/txt/release-7.1p2
    UseRoaming no

The Host * section applies default options to every connection. These default options are overridden by individual host settings and by options given on the command line.

AddressFamily inet forces SSH to use an IPv4 address when connecting. The default is AddressFamily any which would allow for either IPv4 or IPv6 addresses to create the connection. I forced IPv4 as I have to tunnel to use IPv6, so if the IPv6 address is used, additional latency is added to my connections.

Compression yes forces all my connections to use compression. Compression can greatly speed up the transmission of large amounts of text. It can add some latency, so it’s not for everyone. It works well for me, so I use it.

The Control* options allows a master connection to each host to be stored and shared. This means that other connections to the host will use the master connection rather than creating new connections, making each additional connection to that host connect much faster. If an hour elapses with no connections to that host, this master connection will automatically terminate.

The KexAlgorithms, MACs, and Ciphers options enforce the use of strong ciphers, increasing the security of the connection. Since not all the hosts that I connect to support the limited set of ciphers, some of the hosts have custom cipher sets listed to ensure that I can connect to them. This typically occurs with servers running older distro releases such as older versions of CentOS.

Conclusion

I hope that I helped you use ssh more efficiently and make your servers more secure at the same time. However, I’ve just scratched the surface on this topic. There are dozens of ways to use SSH in ways that I haven’t touched on.

Here are just a few additional things that you can do with SSH:

  • Log into a visual desktop remotely by tunneling X
  • Secure FTP alternative: use scp to easily transfer files between systems
  • Mount remote file systems as local mount points
  • Browse securely on insecure networks or bypass network restrictions to browse freely
  • Easily run a command on remote servers directly. This is great for scripting status programs.

Did I help you? Send me a tip.