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?
Hello,
Thanks for this very readable tutorial. Personally I would like to see how to run a remote x session over SSH as I want to connect to a machine on my LAN from remote locations. I’ve been experimenting with VNC but I don’t think it is very secure (not sure!). Apparently there’s a third option which is to tunnel VNC through SSH … confusing!
My SSH server (a raspberry pi) didn’t like the
cat ~/.ssh/id_dsa.pub | ssh hostname “cat >> ~/.ssh/authorized_keys”
command, consequently I had to transfer the public key to the Pi by other means. It took me several minutes of flailing around and more Googling to discover/realize that the key had to be *appended* to a file named authorized_keys. I think it would be worth explicitly stating that as I initially thought that authorized_keys was a folder where I had to put my keys. In theory I might have been able to work that out but the syntax as given is rather cryptic.
Thanks so much for taking the time!
// Simon
Glad that it could help you. I’ve added a note to that section clarifying what the command is doing.
Thanks for your tutorial, I just want to comment that in my computer running Ubuntu 12.04 I had to specify the HostName in config file for it to work:
Host my_alias
HostName myhost.com
User my_very_long_user_name
ServerAliveInterval 240
My ssh version is:
penSSH_5.9p1 Debian-5ubuntu1.1, OpenSSL 1.0.1 14 Mar 2012
Regards,
Juan
Thanks for a clean tutorial i was searching for ssh authentication key and now i know it
Regards,
Rath
Thanks for tutorial!
Very informative. I’ve just installed Linux Mint (after Windows), and investigate applet SSL-launcher:
http://cinnamon-spices.linuxmint.com/applets/view/93
Sources:
https://github.com/tiborsomodi/cinnamon-sshlauncher/blob/master/sshlauncher%40sotiwin/applet.js
And now I understand what is ssl/config file.
Any idea from this output what my problem might be?
Nathans-iMac:.ssh nathanmoses$ ssh -v oxygen
OpenSSH_6.2p2, OSSLShim 0.9.8r 8 Dec 2011
debug1: Reading configuration data /etc/ssh_config
debug1: /etc/ssh_config line 20: Applying options for *
debug1: Connecting to oxygen [198.105.254.23] port 22.
debug1: connect to address 198.105.254.23 port 22: Operation timed out
debug1: Connecting to oxygen [198.105.244.23] port 22.
debug1: connect to address 198.105.244.23 port 22: Operation timed out
ssh: connect to host oxygen port 22: Operation timed out
Looks like your system or network isn’t resolving the oxygen hostname to an IP. Thus, it’s checking the DNS system. Either your router’s or your ISP’s DNS configuration is set to connect unknown hosts to a search result page provided by Search Guide Inc, the company that owns the IP that your SSH request is trying to connect to.
You’ll either need to supply the IP rather than the hostname to the ssh command, fix your network config to properly resolve local hostnames to IP addresses, add an entry in your system’s host file that explicitly sets the IP that oxygen should point to, or add an SSH config file for your user that tells SSH what IP address to map the oxygen name to. The last link is to a document about Linux, but I believe that the information applies to OS X as well.
[…] Linux: https://chrisjean.com/ssh-tutorial-for-ubuntu-linux/ […]
I’m doing independent research on openssh and found your blog while googling. While its a great intro article, and I realize it was written sometime in 2013, you might want to put in a note saying that DSA has been deprecated and suggest using RSA or one of the ECs.
Thanks for the good writeup.
Thanks for the reminder to update the post Matthew. You are quite right about the DSA issue.
I’ve updated the post to have better formatting and to freshen the content. The update includes changing creation of a DSA key to creation of an RSA key with a high bit count. I also note that I prefer to use ed25519 keys these days.
This tutorial is seriously great, Thanks a lot