It's very common for all servers (virtual/cloud and physical) connected to the internet to be scanned and logins attempted. There are a few steps you can take to secure your SSH installation. It's important to note that it's impossible to be 100% guaranteed secure, but there are lots of steps you can take to make it almost there...

The following are in order of difficulty for you when then trying to access them. All are described in terms of an Ubuntu 16.04 instance, but should work on most other distributions too.

We have also written an update to this guide from an Ubuntu 18.04 perspective, so if you are running that version you can get updated information there.

1. Install fail2ban

This piece of software is great - it simply monitors the SSH authentication log files for failed attempts and bans connecting IP addresses that have 3 failed attempts for 10 minutes (by default). As these requests often are just sent in huge batches, it stops them after three attempts for a while, making them more likely to give up rather than wait infinite years for their attempts to succeed. There's lots of information online about fail2ban but a simple installation is just:

sudo apt update
sudo apt install fail2ban

And that's it! If you want to tweak settings you can have a look at the files in /etc/fail2ban.

2. Non-standard port

The simplest thing you can do is to simply configure sshd to not listen on port 22. You do this by editing /etc/ssh/sshd_config and changing the line:

Port 22

to be a new choice of port (some people use 2222, but because this is so common it's now often attempted along with the default one anyway):

Port 2234

After doing this you need to restart your SSH daemon with service ssh restart.

Now when you SSH from the command line you can either specify the port with:

ssh -p 2234 root@your.ip.address.here

Or you can edit a file on your local machine called ~/.ssh/config and put a section like:

Host your.ip.address.here
  Port 2234

3. Disable Root Logins

When hackers try to brute force entry to your SSH daemon, they often try the OS's default users (ubuntu, debian, etc) or root. So if you have a non-root user with sudo permissions that you use to connect with, you can disable the root login via SSH completely. To do this edit the /etc/ssh/sshd_config file on the instance again and change the line:

PermitRootLogin yes

to be:

PermitRootLogin no

And again restart your ssh with service ssh restart. NOTE: If you only have a root user on the server, you'll lose access to your instance by doing this - forcing a rebuild and 100% data loss on the instance.

4. Firewall SSH

You can use either a custom Civo firewall from your dashboard or your distributions built-in firewalling to only allow TCP connections to your SSH daemon to a specific IP address (your office's fixed IP address). This is really secure, but it doesn't help if you're on vacation and an instance has a problem. Read more about firewalling instances.

5. Port knocking

This is going to be the most hasslesome method, but is really clever. What you do is completely firewall SSH off from being accessed and setup a daemon that listens on a number of ports and when it receives a connection of them in the right order, it then opens up the firewall to SSH for the IP address that made the sequence of port connections. Let's install it and work through an example:

The first step is to setup some default rules using iptables:

# Accept all local traffic (from the same machine)
sudo iptables -A INPUT -i lo -j ACCEPT

# Allow any already established connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# If you have any other rules add them now, e.g. HTTPS:
# sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Finally drop anything that we haven't specified
sudo iptables -A INPUT -j DROP

That's locked your box down, but because of the ESTABLISHED,RELATED item your current SSH connection won't drop (DON'T exit the connection yet now though).

Now we should make these rules exist between reboots with:

sudo apt update
sudo apt install iptables-persistent
sudo service iptables-persistent start

Now we're ready to install Knockd, which is a really nice piece of software to listen on configured ports and run commands when it receives connections in the right order:

sudo apt install knockd

Now we can configure the daemon by editing /etc/knockd.conf

[options]
        UseSyslog

[openSSH]
   sequence = 6001,6003,6007
  seq_timeout = 5
  command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
  tcpflags = syn

[closeSSH]
  sequence = 6007,6003,6001
  seq_timeout = 5
  command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
  tcpflags = syn

This is configured now so that if you knock on ports 6001, then 6003 and then 6007 in that order it will open iptables to allow your current IP's connection. If you knock in reverse order it will close it again. We'd recommend that you not use the ports above though, pick three (or whatever) ports of your own choosing, above 1024 and less than or equal to65535. Now you've got to enable the daemon and start it. Edit the file /etc/default/knockd and change the line:

START_KNOCKD=0

to be:

START_KNOCKD=1

And start the service with:

sudo service knockd start

Now you're ready to try it (hopefully you're doing this for the first time on a test instance):

Open a new terminal (tab) and install the knock client (or you can use netcat or something similar) using apt install knock or brew install knock (for Linux and Mac OS X respectively, a Windows client is also available).

knock your.ip.address.here 6001 6003 6007
ssh your.ip.address.here

And then you should be connected to your server. When you've finished with it, you can exit your SSH connection and knock in revers order to close it again:

knock your.ip.address.here 6007 6003 6001