This guide is mostly a reference for myself as it’s a workflow that I find myself following whenever I set up a new Linux machine. I’m sharing it here as I’m sure many will find this useful, and it will save me from looking up each distinct step in the future.

I also took the opportunity to add some bonus network configuration tips to get the most out of the setup.

SSH 101

SSH at its core is a means to connect to another machine remotely. One of the most fundamental uses of this is to log into another machine’s terminal, but it also provides functionality to open tunnelling ports and run GUI apps over a secure connection.

SSH connections require two components; a server running on the machine you want to connect to, and a client running on the machine you want to connect from.

Secure, passwordless connections are facilitated by way of private/public key pairs. Think of a public key as a lock that you can replicate and give to other machines and services, and the private key is the only way to unlock those locks. So it should go without saying that you never give out your private key.

Some of my favourite things to do with SSH are:

  • The obvious one, administering a machine remotely through the terminal
    • With an SSH client such as ConnectBot, you can even manage a machine from your phone.
  • SFTP - using SSH you can expose the filesystem of a machine using the SFTP protocol.
  • VS Code Remote Development - With the Remote - SSH extension for VS Code, you can run VS Code locally while developing on a remote machine (I’m doing this right now). But why? Well, in my case I’m editing the files directly on my web server (bit naughty), but in other cases you may want to offload the hard work of building, testing etc to a remote machine, freeing up resources on your working machine, or to centralise your working environment so that you can use any machine to do the work without losing your place.

Initial server setup

Install the SSH Server

Ensure the server is installed on the machine you intend to connect to. The package is typically called openssh-server, don’t be surprised if it’s already installed. You can check if it’s running with:

$ systemctl status sshd

Enable the SSH Server

If it isn’t running automatically, just enable it.

$ sudo systemctl enable sshd

Client setup

Install the SSH Client

Again, the client will probably already be installed on the machine you want to connect from. If not, the package is typically called openssh-client.

Create Private/Public Key Pair

For secure, passwordless connections, you’ll want to create a public/private key pair.

$ ssh-keygen

The defaults are usually fine and random enough. This will create two files in your home’s .ssh directory, id_rsa (your private key, keep it private) and id_rsa.pub (your public key, for sharing).

Set Up Connection Profiles

Create a new file in ~/.ssh called config. Below is an example file with two connection profiles.

Host compy
	HostName compy-386
	User strongbad
    Port 1234
    X11Forwarding yes

Host tandy-400
    HostName 192.168.0.11
    User strongbad

With this in place, I could connect to the computer compy-386 on a custom port with the specified user and X11 forwarding support by simply entering

$ ssh compy

Copy Public Key to Server

Assuming the config has been set up, you can copy the generated public key to the server with:

$ ssh-copy-id compy

Improving Server Security

Change the SSH Port

You probably noticed in that first config profile that the port was specified. By default, SSH listens on port 22, but you can make it a bit more secure by making it harder to guess.

$ sudo nano /etc/ssh/sshd_config

Not far from the top you will see a line with

# Port 22

That hash (#) symbol is a comment, remove it and change the 22 to something else, taking care not to use a port number reserved for a service you will be using.

On Fedora there are some extra steps, run the following:

$ sudo systemctl edit sshd.socket

Add the following between the lines the file tells you to edit, substituting 1234 with the port you’re using for SSH (the empty value entry is necessary to clear all previous settings):

[Socket]
ListenStream=
ListenStream=1234

Save and close the file. Next, add the port to SELinux’s SSH policy, substituting 1234 to reflect your chosen port:

$ sudo semanage port -a -t ssh_port_t -p tcp 1234

Then open the firewall port, substituting 1234 to reflect your chosen port:

$ sudo firewall-cmd --permanent --service="ssh" --add-port "1234/tcp"
$ sudo firewall-cmd --reload

Finally, no matter what distro you’re on, reload the SSHD service’s config for the changes to take effect.

$ sudo systemctl reload sshd

Tidying up

Don’t forget to update your local config file if the port wasn’t specified before. Once you’ve confirmed a connection can be made with the port changes, remove the old port from the firewall config:

$ sudo firewall-cmd --permanent --service="ssh" --remove-port "22/tcp"
$ sudo firewall-cmd --reload

And remove the old port from SELinux’s SSH policy:

$ sudo semanage port -d -p tcp 22

Remove password access

Once you’ve confirmed that you can login without a password using a public key, you can turn off SSH password authentication altogether. This method requires a valid private key on the client machine to connect, you will no longer be prompted to enter a password. I would only recommend this if you have a way to access the machine either physically or through some kind of always available terminal (e.g. QEMU terminal in a web page) so that you can still access it if for some reason you don’t have any valid private keys to connect with.

Simply edit the SSHD config:

$ sudo nano /etc/ssh/sshd_config

Find the following line:

#PasswordAuthentication yes

Remove the comment character # and change the value from yes to no. Save and exit, then reload the configuration:

$ sudo systemctl reload sshd

Router Setup

If your machine is hosted on your home network, you can make it available publicly (hopefully secure by this point) for when you want to, y’know, run btop from the bus. I won’t go into too much detail about this as every router is different, but the principles are the same.

First, configure DHCP settings on your router, give your machine a static IP. This is necessary so that port forwarding rules will always point to the correct machine.

Next you need to configure Port Forwarding. This allows you to open up a public port and have it relay through to a certain network address (that’ll be the static IP you created earlier) and port (it doesn’t have to be the same port as the one exposed publicly).

With this in place you should be able to access your machine using the specified public port without being on the network, as long as you know the IP address of your home network.

But you can take this to the next level with Dynamic DNS. For this you will need your own domain and the ability to set your DNS settings. I use DNS-O-Matic for this, it updates the A record for a subdomain to point to my home network.

There are two parts to it; first you need to set up a DNS-O-Matic account and give it access to your domain service, and then set up Dynamic DNS in your router to update the service every time it establishes a new internet connection, ensuring your domain or subdomain always points to the correct IP address.