SSH Essentials

Sep 17, 2019

SSH, or Secure SHell, is a protocol that allows users to (securely) control remote computers over the Internet. With SSH, we can operate a shell on a remote computer as if we were in front of it.

Usually, the remote computer is called the server and the computer used to ssh into it is called the client. But the "server" can be anything: a router, a raspberry pie, some media center, a GPU cluster, your friend's laptop...

I use ssh daily to work with GPU clusters and powerful workstations from my laptop. Here is my minimal set of productivity tips for ssh.

SSH Configuration

Assuming the remote computer's IP address is 192.168.1.1 and you want to log into it using username user, the basic command-line call to start an SSH connection is:

$ ssh user@192.168.1.1

user@192.168.1.1 password: *****

SSH will then prompt for user's password. In the next sections, we will see how to speed the workflow and avoid typing the user name, server address and password.

Faster login with key-based authentication

Instead of using a password, we can configure a faster and more secure way to connect. It is faster because we don't have to type a password, and more secure because it eliminates the risk of a brute-force attack.

It's called key-based authentication. To use it, the first step is to generate a new RSA key. If the ~./ssh folder doesn't exist yet, you can create it with:

$ mkdir ~/.ssh && chmod 700 ~/.ssh

Then, generate a new key for your ssh session. You will be prompted for an optional password to protect the key.

$ ssh-keygen -f ~/.ssh/keyname

Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ~/.ssh/keyname.

Then, install the key on the remote session using ssh-copy-id:

$ ssh-copy-id -i ~/.ssh/keyname user@192.168.1.1

This will append your public key to the file .ssh/authorized_keys inside user's account on the server.

If everything's worked, you can now log into the remote session using key authentication. As we will see in the next section, we can do shorter using SSH config.

$ ssh -i ~/.ssh/keyname user@192.168.1.1

If it doesn't work, make sure the permissions are correct using the following command on the remote computer:

$ chmod 600 ~/.ssh/authorized_keys

Less typing with SSH config

You can use the file ~/.ssh/config to minimize your daily SSH related typing. If it doesn't exist, create it with:

$ touch ~/.ssh/config && chmod 600 ~/.ssh/config

Then, edit it and setup your remote session. The basic file structure is as follows:

~/.ssh/config
Host alias1
    SSH_OPTION value
    SSH_OPTION value

Host alias2
    SSH_OPTION value

Host *
    SSH_OPTION value

Here is how to configure our user@192.168.1.1 session using the key-based authentication and the dev alias.

~/.ssh/config
Host dev
    HostName 192.168.1.1
    User user
    Port 22
    IdentityFile ~/.ssh/keyname

Everything's pretty straightforward: the alias for this user@server pair is called dev. The server address is 128.178.198.16 the user for login is user and the connection port is 22 (you can omit this line if you don't need to specify a port). Last but not least, instead of using a password, we use the key ~/.ssh/keyname generated earlier.

With this config, we can log into the remote computer using the shorter command:

$ ssh dev

Tmux: an indispensable companion

If you close your local terminal window, or if you loose temporarily the internet connection, the SSH session and its running processes will be automatically closed by the server. This is really annoying when it happens in the middle of a long running task such as a software update/install or training your machine-learning model.

Tmux (Terminal MUltiplexer) allows to open a shell session and let it run even when the SSH session is closed. Using tmux, we can start a long running task on the server, close the SSH connection and come back at some later time. This is how I let the server train my neural-networks while being able to turn off my laptop.

Tmux quickstart

You can install it on the remote computer using (on Ubuntu at least):

$ sudo apt-get update && sudo apt-get install tmux

Once installed, you can create a new session using:

$ tmux new -s sessionName

This will give you some kind of terminal inside the terminal. At first glance, nothing new. What's great is that you can leave this session, close your terminal or disconnect from ssh and retrieve it later as you left it.

Once you SSH back into the remote computer you can list all opened tmux sessions:

$ tmux ls

Then attach to one using:

$ tmux attach -t sessionName

To attach to an existing session or create it if it doesn't already:

$ tmux attach -t sessionName || tmux new -s sessionName

When inside a tmux session, there are several useful shortcuts:

shortcut effect
(ctrl + b) d detach from current session
(ctrl + b) :new -s sessionName<CR> create new session sessionName.
(ctrl + b) s list all running sessions
(ctrl + b) [ activate scroll mode (use arrows to scroll)
q quit scroll mode
  • The notation (ctrl + b) + d mean press ctrl + b then type d.
  • Likewise (ctrl + b) :new means press (ctrl + b) then type :new.
  • <CR> means you hit the enter ↵ key.
  • (ctrl + b) is the default prefix to enter into tmux's command mode. Then, d, s or :new are the actual commands.
  • You can change the prefix if you don't like ctrl + b.

There are many more options and shortcuts to learn about tmux. See the cheat sheet here for instance.

Automatically start tmux when ssh-ing into a remote computer

Using the tips above, a typical ssh login will look like this:

$ ssh dev
$ tmux attach -t sessionName || tmux new -s sessionName

We can combine both using a bash function.

Edit the file ~/.bashrc and create the following function:

~/.bashrc
function ssht () {
    /usr/bin/ssh -t "$@" "tmux attach -t sessionName || tmux new -s sessionName";
}

Here's what it does:

  • ssh XXX -t "blah" runs the command blah on the remote computer designed by XXX ;
  • tmux attach -t sN || tmux new -s sN is the command we saw above ;
  • $@ represents the bash arguments passed to our newly defined function ssht.

So basically:

$ ssht dev

will translate into:

$ ssh -t dev "tmux attach -t sessionName || tmux new -s sessionName; bash -l"

which will open an ssh connection to the dev host and run the following command in it:

$ tmux attach -t sessionName || tmux new -s sessionName

Port Forwarding

If you run an application with a web interface on the server (e.g. jupyter notebook), you can usually access it from the server with a URL on localhost, for instance http://localhost:8000.

But if we use ssh to connect to the server, how can we securely connect to this local address without exposing it publicly ?

With ssh, we can forward a port on the client to a port on the server and connect to this address. Suppose that my Jupyter notebook is running on the server at address http://localhost:8000 and I want to be able to open it on the client at address http://localhost:9000, the command is:

ssh -N -L 9000:localhost:8000 user@192.168.1.1

Or, if you have defined the host dev in ~/.ssh/config:

ssh -N -L 9000:localhost:8000 dev

This can be automated in the config file as follows:

~/.ssh/config
Host dev
    HostName 192.168.1.1
    User user
    Port 22
    IdentityFile ~/.ssh/keyname
    LocalForward 9000 localhost:8000

And the forwarding will be enabled as soon as (and as long as) you ssh into dev. To forward several ports, you can have multiple lines with LocalForward.

Oh, and if you have an error that says "open failed: administratively prohibited", it could be a firewall issue, but oftentimes the message is misleading and you might want to make sure that the web-application is running on the server at the correct address. You can test it using this command on the server:

curl localhost:8000