If you have an internet-facing server, then you probably want to keep the connections to the server and the data on it as secure as possible. In order to do this, you have to tighten up security rules to secure your data. There are many great ways to "harden" your server against attacks, and most of them are very easy to implement. Below are 5 of the best ways to harden your servers. Enjoy!

#1: Configure and Use a Firewall

While it seems like a very simple thing to do, maintaining a good firewall is one of the most overlooked parts of server hardening. A firewall can ignore or drop connections to ports that you don't want to expose. On many Linux distributions, the firewall is installing but not active by default, so you have to manually enable it. On Ubuntu server the syntax is as follows:

NOTE: commands starting with "#" should be run as root or with "sudo"

# ufw allow Openssh
Rule updated
Rule updated (v6)

# ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)?
Firewall is active and enabled on system startup

Make sure to allow your SSH connection before enabling the firewall so you don't get locked out, because firewalls will ignore connections by default. Use ufw status to check the status of the firewall. On RHEL/CentOS/Fedora servers, the firewall can be managed through the built-in Cockpit utility. To access Cockpit, visit https://[serverip]:9090/ and you'll see a login page. Sign in to manage your server. Navigate to the Networking tab and click firewall. From here, you can add services and ports to allow through the firewall.

Configuring Firewall using Cockpit
Configuring Firewall using Cockpit

The firewall isn't something you can just set and forget, though. As you add or remove services, you must stay vigilant and add or remove those ports as well, so that you minimize the amount of exposed ports and prevent unwanted traffic. (At one point, my NC Server had so many unnecessary open ports that I just reset all the rules using ufw reset) Fortunately it is very easy to remove firewall rules in any Linux distribution.

#2: Regular or Automatic Security Updates

Oftentimes, security updates contain fixes to the Linux kernel or other important system utilities and services which are essential to the function of your server. Security updates may also contain things like microcodes, which are released to combat specific attacks, such as Spectre and Meltdown. Because security updates are so crucial, it's important to regularly install them manually, or even configure automatic security updates. To enable automatic security updates in Ubuntu, we use the apt unattended-upgrades package. To install it type the below commands:

# apt install unattended-upgrades
Check if it's running after installation
$ systemctl status unattended-upgrades

If it says the service is active/running, then you can continue to the next step. We need to enable automatic updates for the security repository. To do this, we need to edit the config file:

# nano /etc/apt/apt.conf.d/50unattended-upgrades
Then remove the // from the line ending in "security"
# nano /etc/apt/apt.conf.d/20auto-upgrades
Then edit the file so it looks like this:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Great! Now your Debian/Ubuntu server has automatic updates enabled. But what if you have a RHEL-based server OS? Well, it's even easier to do from the Cockpit management interface. Go to your Cockpit instance at https://[serverip]:9090/ and click on software updates in the left bar. Wait for a few seconds for it to refresh package information. Now you can select which updates to automatically install and what day of the week & time to install them.

Configuring automatic updates using Cockpit
Configuring automatic updates using Cockpit

Another thing you can do on Ubuntu systems to apply important kernel patches without a restart is to install Canonical Livepatch. To do this, visit their website and sign in to your Ubuntu One account. Then, get your livepatch token and keep it safe. Type the following commands to install and enable livepatch on your system.

# snap install canonical-livepatch
# snap list

Name                 Version      Rev    Tracking       Publisher   Notes
canonical-livepatch  9.5.5        95     latest/stable  canonical✓  -
core                 16-  9804   latest/stable  canonical✓  core
core18               20200724     1885   latest/stable  canonical✓  base
nextcloud            19.0.1snap3  22653  latest/stable  nextcloud✓  -

# canonical-livepatch enable [token]
(Replace [token] with your auth token from earlier)
Successfully enabled device. Using machine-token [token]

Your kernel livepatching should now be active.

#3: Securing Secure Shell (SSH) Connections

Using SSH Keys
Eny Setiyowati/Shutterstock.com

If you manage a server, it's likely that you remotely connect to its terminal over Secure Shell (SSH). SSH is inherently secure as it uses an encrypted connection, but there are still some things that should be tightened. Firstly, you should disable root login over SSH. The root user can be used to perform potentially dangerous tasks on your system, so you should block remote root login. To do this, we have to edit the SSH config file:

# nano /etc/ssh/sshd_config
Edit the line with "PermitRootLogin" so it says PermitRootLogin no
# systemctl restart sshd

Another thing you can do to tighten up SSH connections is to only use SSH keys. SSH keys are pairs of public and private keys which are used to authenticate SSH connections. They are much harder to brute force than passwords, so they provide a higher level of security. To use SSH keys, we first have to create the key pair on the client machine. On Linux/MacOS machines, simply type ssh-keygen -t rsa and follow the instructions. Then copy the public key to the server using ssh-copy-id user@serverip. On Windows (PuTTY), open PuTTYGen and click generate. Then move your mouse around to generate randomness. Save both keys in a safe location. To copy the public key to the server, open an SSH session and type the following:

# umask 077 && test -d ~/.ssh || mkdir ~/.ssh
# umask 077 && touch ~/.ssh/authorized_keys
# nano .ssh/authorized_keys
Paste the contents of your public key file here

You should be able to login with just your SSH keys now. If it doesn't work, you should make sure the line PubkeyAuthentication and AuthorizedKeysFile are uncommented in SSH config.

Another thing you can do to tighten up SSH security is installing fail2ban. Fail2ban refuses connections from brute-forcing ip addresses, making your server more secure from brute-force attacks. To install it on a Ubuntu/Debian system, type these commands:

# apt install fail2ban
# fail2ban-client status

|- Number of jail:      1
`- Jail list:   sshd

On a RHEL-based system, type the following to install fail2ban:

# yum install epel-relase
# yum install fail2ban
# systemctl enable fail2ban
# fail2ban-client status

|- Number of jail:      1
`- Jail list:   sshd

Now your servers are protected against brute-force SSH attacks.

#4: Use SELinux

SELinux Penguin

Security Enhanced Linux (SELinux) is a Linux security kernel module which controls access to different applications, processes, and files on a system. It uses security policies, which are a set of rules that tell SELinux what can or can’t be accessed, to enforce the access allowed by a policy. To learn more about SELinux, visit the Red Hat wiki. SELinux is included and enabled by default on the latest releases of RHEL/CentOS/Fedora systems. To install SELinux on Ubuntu/Debian systems, type the following commands:

# apt install selinux selinux-utils selinux-basics auditd audispd-plugins
# reboot
# sestatus

SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             default
Current mode:                   permissive
Mode from config file:          permissive
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     requested (insecure)
Max kernel policy version:      31
# setenforce 1 (to change mode from permissive to enforcing)

Now that SELinux is installed, we need to allow some services access. These are some common services and how to enable them with SELinux.

Allow web server httpd:
# setsebool -P httpd_unified 1

Allow samba server:
# setsebool -P samba_export_all_ro=1 samba_export_all_rw=1
# semanage fcontext -a -t samba_share_t "/path/to/share(/.*)?" (replace /path/to/share with your share path)

Allow Nextcloud server:
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/data(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/config(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/apps(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/.htaccess'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/.user.ini'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/3rdparty/aws/aws-sdk-php/src/data/logs(/.*)?'

restorecon -Rv '/var/www/html/nextcloud/'

Now, to permanently enable SELinux, type the following commands:

# nano /etc/selinux/config
Change to SELINUX=enforcing

Great! Now SELinux is installed and enabled on your server!

#5: Lynis Security Auditing

Even if you follow best practices and attempt to tighten security on every attack vector, you'll still leave some things open to attacks or exploits. Lynis is a tool that helps you see security vulnerabilities that you aren't able to spot on your own. Lynis performs an extensive health scan of your system to find possible security vulnerabilities and general optimizations for your system. To learn more about Lynis, visit Cisofy's website.

Lynis is available as a package for Debian and RHEL-based systems. To install on Ubuntu/Debian, type the following commands:

# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C80E383C3DE9F082E01391A0366C67DE91CA5D5F
# echo "deb https://packages.cisofy.com/community/lynis/deb/ stable main" | tee /etc/apt/sources.list.d/cisofy-lynis.list
# apt update
# apt install lynis

To install on RHEL-based systems, type the following commands:

# dnf update
# dnf install lynis

To check if it was successfully installed and to audit your system for the first time, run the following commands:

# lynis show version
# lynis audit system
[ Lynis 3.0.0 ]

[+] Initializing program
  - Detecting OS...                                           [ DONE ]
  - Checking profiles...                                      [ DONE ]

  Program version:           3.0.0
  Operating system:          Linux
  Operating system name:     CentOS Linux
  Operating system version:  8
  Kernel version:            4.18.0
  Hardware platform:         x86_64
  Hostname:                  hostname


  -[ Lynis 3.0.0 Results ]-

Warnings (1):
warnings will appear here

Suggestions (9000):
suggestions will appear here

Lynis security scan details:

  Hardening index : 68 [#############       ]
  Tests performed : 258
  Plugins enabled : 0

  - Firewall               [V]
  - Malware scanner        [X]

  Scan mode:
  Normal [V]  Forensics [ ]  Integration [ ]  Pentest [ ]

  Lynis modules:
  - Compliance status      [?]
  - Security audit         [V]
  - Vulnerability scan     [V]

  - Test and debug information      : /var/log/lynis.log
  - Report data                     : /var/log/lynis-report.dat

Security scan finished.

Lynis will divide its output into warnings, which are very important and should be dealt with immediately, and suggestions, which are less important but you should still consider implementing some of them to improve security.

Additional stuff

Another security measure you can implement is full-disk encryption with LVM. Full disk encryption can help protect important data from being breached even if the server is hacked, since the data can't be decrypted without the passphrase. Usually, you can choose this option when partitioning your disks on a fresh install. Below is an example in the CentOS installer:

Setting up full-disk encryption
Setting up full-disk encryption

A few other things to keep in mind are to frequently monitor access/usage logs to pick out unwanted traffic and to always have (working) backups in case of data loss from an attack. You can also only forward necessary ports on your router to provide network-wide security.

I hope you enjoyed this post! If you have any questions or comments, I have recently added a Disqus for this site, which you can access below. Be on the lookout for a server hardening video in the coming weeks. Thanks for reading!