The most common way how to connect to your server is using SSH.

We will open RPi to world and in that case we need to secure it a bit. Service, which takes care about SSH is called sshd. Where is it? It is run by systemd, so systemctl status sshd will show you more info. To reduce the brutal force attacks on root account (if was thousands of attempts every day on my little unimportant server), we will disable root login through SSH.

Getting a proper randomness

A lot of security algorithms relies on having a good source of (pseudo)randomness. Why? Take for example the password file from previous chapter. If you would generate the salt in some predictable way, an attacker would have much easier work to guess the passwords.

There are two special Linux devices which you can use for getting random data. Those random data are mostly generated from user interaction with e.g. mouse, keyboard or screen. That is the problem on headless Linux server as we can have, since they do not have such interfaces. Because of that, relaying on the basic source of randomness is insufficient. These devices are in /dev/random and /dev/urandom. The latter differs from the former in that manner that it will generate random data even though there is not enough entropy for ensuring sufficient randomness. Hence, use /dev/random/ instead.

If you don't want to invest to additional hardware which provide very high and true randomness by buying e.g. OneRNG, there is another solution which will definitely be enough for 99% of users. That solution is havege (respective it's daemon haveged). This is a clever algorithm which generates randomness based on time which processor spends during computing some instructions.

Installing and activating haveged cannot be easier. Go for:

$ pacman -S haveged
$ systemctl enable haveged
$ systemctl start haveged

and your /dev/random will be fed by haveged data since now.

SSH

If you haven't installed SSH yet, do it by pacman -S ssh.

Open the file /etc/ssh/sshd_config and edit/uncomment or add these lines as follows (left the rest untouched):

Port 1234
PermitRootLogin no
PubkeyAuthentication yes

Restart ssh service by systemctl restart sshd. Since now, you cannot login as a root by ssh and that's good. Also - we changed the port of ssh to 1234 (you are advised to change this number to something different of course). Think about port as a tunnel, which is used by some application. There are about 60 thousands of them and you can choose whichever you want. Default port for SSH is 22 and that is the port which is most widely abused by brutal force attacks. Changing it to something from this range just makes it several tenth thousands harder to guess the access...

Since now, using only ssh bob@ipadress to connect to server is not enough. You will have to add port which should be used. ssh -p 1234 bob@ip.address will do that for you.

Improving the security of SSH can be done basically by two approaches depending on your needs.

SSHguard

Shortly, sshguard is going to block recurring attempts of login and in case they are failing, it denies the access entirely for some specific time. Install it by pacman -S sshguard. For proper usage, we need to tweak Linux firewall app called iptables.

iptables

iptables are really just another layer of security often called as a firewall. It just specified what connections can come in and out. We need only simple configuration which can be done quite easily.

$ iptables -F
$ iptables -X
$ iptables -P INPUT ACCEPT
$ iptables -P FORWARD ACCEPT
$ iptables -P OUTPUT ACCEPT
$ iptables -N sshguard
$ iptables -A INPUT -j sshguard 
$ iptables-save > /etc/iptables/iptables.rules    

Personally I stopped to use sshguard, since just changing port what SSH use was enough to reduce uninvited connections. Furthermore, there is actually a safer method using only SSH keys.

SSH keys

This is the best you can do from the point of security. Open /etc/ssh/sshd_config and edit these lines as follows:

ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no

and again restart ssh. We just disabled the ability to connect to your server with password. But how else to login in? Using keys!

Creating a key pair

We now need to create a key pair. Two files will with public and private key will be created. Let's do it by this command: ssh-keygen -t ed25519 -f ~/.ssh/bobs_key (left passphrase empty).
One of created files is ~/.ssh/bobs_key.pub and that is the one (public key) you want to transfer to client - the computer from you are going to connect to the server. The second one is private key and you should never ever show any of the keys to anyone under any circumstances. It would basically imply your vulnerability, since anyone who possess public key and the username can connect to your server.

Copy the content of the public key to the clients ssh folder. Now you need to specify this file to connect by -i switch following the filename, e.g. ssh -p 1234 -i ~/.ssh/bobs_key.pub bob@yourrpiaddress.

Convenient settings

It is annoying still typing same username, port and filepath to the key when we want to connect to our server. On PC from which we are connecting (no RPi), edit ~/.ssh/config to this:

Host my_superpc
  HostName ipaddressofRPi
  IdentityFile /home/yourusername/.ssh/name_of_identityfile
  User bob
  port 1234

since now, when you want to connect to RPi, you can just type ssh my_superpc and it will take care about rest. Quite clever, isn't it?

Opening the server to the world

Because we now already know what port is and we have an application which uses them, we can take leverage of using them for security purposes. You have already seen that when we changed the default port from SSH. In the classic scenario when you have your server plugged into your router you wouldn't have to worry anyway, because the router wouldn't allow anyone to get to your server. So how to achieve this?

Port forwarding

You must first get your public IP address. That can be found e.g. here. There is another caveat - you might not have your own public IP, but rather some local from your provider and your provider has the one which is public. There is nothing you can do in to make your server visible from outer world unfortunately, except trying to negotiate with your provider.

In case you are not so unlucky, you have your own public IP which you can use to connect to your server. You will make a request to your IP on specific port, e.g. using ssh to connect on port 1234. This will get into the router first and router will decide where should be the request sent next. If the port isn't explicitly mentioned in the router lookup table, the request is thrown away. That is good - we don't want let the attacker give opportunity to do anything with our inner network. So enable only those ports which are necessary.

How to do a port forwarding differs based on the router and it's firmware. But you need to get into your router and change the settings. How to do that you might find e.g. here or use google for your router type.

To get into your router you need to set up port forwarding from some chosen port to the port you have chosen before for your SSH daemon (1234 in my case). You can choose the same even for the outer port, but you can choose different for that (let's say 8765), so your setting should be something like 8765 -> server.local.ip.address on port 1234. This will tell router to redirect requests on port 1234 to your server and specific port on that server.

Now you should be able to connect to your server using the port 8765, username bob and your public IP address. The syntax is exactly the same: ssh -p 8765 -i ~/.ssh/bobs_key.pub bob@YOURPUBLICIPADDRESS.