Securing a VPS or web facing VM

Setting up a VM or VPS is easy but, you need to make it secure. Here we discover 2 of the basic tools UFW and Fail2ban. This is a post of how to set it up and the results.

Share
Securing a VPS or web facing VM
Photo by Luca / Unsplash

Initial step

Crete a small VPS on your favorite platform. You don't need more than 1 core and 2G disk and some RAM. We use Docker to host the device.

Replace <username> with a real username e.g., nalle.
apt update && apt upgrade -y
apt install duf btop
adduser --disabled-password <username>
nano /etc/sudoers.d/90-<ausername>

Paste in <username> ALL=(ALL) NOPASSWD

SSH setup

The following is a minimum

⚠️
Do not restart SSH or the server before all is set up!
PermitRootLogin no
PubkeyAuthentication yes
StrictModes yes
AllowUsers <username> 

Creating an SSH Key Pair

We need an SSH Key Pair for each server.
Generate a key pair using ed25519 on your local machine.
Then paste the public part to the VPS.

The key pair consisting of two files in your home directory under ~/.ssh.

  • id_ed25519
    • The private key shall be kept safe, like a password, and not passed on.
  • id_ed25519.pub
    • The public part is meant to be public, no need to be kept secret

Depositing the Public Key

mkdir -p /home/nalle/.ssh
nano /home/nalle/.ssh/authorized_keys
# paste the public key here and save the file 
chmod 600 /home/nalle/.ssh/authorized_keys
chown holu:holu /home/nalle/.ssh/authorized_keys

Example where <username> has been replaced with my name

Test for success

Open a new terminal window and type `ssh <user>@<your host>

Activating the new configuration

systemctl restart sshd

Install UFW

To set up a firewall we will use the program Uncomplicated Firewall (UFW), (an abstraction of iptables), because the rules can be managed much easier and more comfortable than with iptables directly. It simplifies the complex iptables configuration, making it accessible for users who may not be familiar with advanced firewall management.

Installation

The ufw package can be installed from the apt package manager.

sudo apt install ufw

First rule

Create a rule that blocks all incoming connections that are not explicitly allowed.

sudo ufw default deny incoming

Before we activate the firewall, we must of course release our SSH port, otherwise we lock ourselves out of the server. Use ufw allow ssh or use the port ufw allow 22/tcp

sudo ufw allow ssh 

Activate UFW

Activate the Uncomplicated Firewall with the command:

sudo ufw enable

With the command ufw status all created rules can be listed. This command must also be executed as root or using sudo.

Install Fail2ban

Install it and check your UFW status

sudo apt update && sudo apt install fail2ban
sudo ufw status verbose
systemctl is-enabled fail2ban
systemctl is-active fail2ban

Check fail2ban status

systemctl is-enabled fail2ban
systemctl is-active fail2ban

If it is enabled and active we need to shut it down

sudo systemctl stop fail2ban

Configure to ban through UFW

Do not edit the .conf files, they are overwritten at upgrades, create .local instead e.g., /etc/fail2ban/jail.local, they are not changed.

sudo nano /etc/fail2ban/jail.local

Add the following: Ban for 1 hour after 5 failures within 10 minutes using UFW instead of the default iptables.

[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
banaction = ufw

[sshd]
enabled = true
backend  = systemd

To note:

  • banaction – tells Fail2ban to use the ufw action that ships in /etc/fail2ban/action.d/ufw.conf, instead of its default iptables action. Bans become UFW rule
  • backend – For the SSHD jail. OpenSSH logs to the systemd journal, so the journal backend is the reliable way for Fail2ban to read failed logins.

Save the file.

Enable and start the service in one step:

sudo systemctl enable --now fail2ban

Confirm the jail is running:

sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	0
|  `- Journal matches:	_SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned:	0
   |- Total banned:	0
   `- Banned IP list:

Example output

Nothing is banned yet, which is expected. The Journal matches line confirms Fail2ban is reading SSH events from the journal.

Ban and Unban an IP

The subnet 198.51.100.0/24 is a reserved for documentation, so the address below is safe to run. You don't need to wait for a real attacker to confirm the integration works, it will be a short wait but, it's not safe to unban any attacker.

Ban an IP

sudo fail2ban-client set sshd banip 198.51.100.40

Unban an IP

sudo fail2ban-client set sshd unbanip 198.51.100.40

Results

Why do I need to run ufw and/or fail2ban on my web facing VM/VPS?
I created a VPS for testing and during the first day I got these results:

sudo fail2ban-client status sshd
    • Total failed: 1062
    • Total banned: 166

Actually, much lower results than expected. But, it's scary, isn't it.

Fail2Ban is one layer in a broader Linux security strategy, and works best with:

    • SSH key authentication
    • Properly configured firewall rules
    • Regular software updates
    • Strong access control policies


References

Fail2ban [1] UFW [2] About IPs [3]


  1. Fail2Ban on GitHub. FAQ, and HOWTOs to be found on fail2ban manpage, Wiki, Developers documentation and the website ↩︎

  2. Uncomplicated Firewall (UFW), has been available by default in all Debian installations since 10 homepage, getting started wiki, Git, wikipedia, man page ↩︎

  3. IPv4 Address Blocks for Documentation are by RFC 5737:
    TEST-NET-1 = 192.0.2.0/24, -2 = 198.51.100.0/24, -3 = 203.0.113.0/24 ↩︎