Featured image thumbnail for post 'First steps to begin securing your Linux server'

First steps to begin securing your Linux server

A brief introduction to best-practices when securing and hardening your Linux server.

Joey Miller • Last updated May 04, 2023

Although you might assume that your server is already secure, there are some simple practices you should be following to harden your server. In the event of a compromise, these practices will allow you to limit the damage that can be done by attackers.

Although this guide was written for Ubuntu Server 20.04 LTS (focal) this guide should be mostly transferable to other Linux distributions.

1. Get rid of the root account

In some scenarios, you are first given access to a Linux server via the root account. The first thing you should do is disable this account. You should be using sudo from another user account to execute privileged commands.

There are several reasons why this is beneficial, such as allowing for better auditing and accountability (since users now have to use sudo). Doing so also provides more safeguards and (in some cases) better protects you in the event of account compromises (since the user password will be required even if using private-key authentication over SSH).

First, we will create a new sudo-level user: ubuntu.

adduser ubuntu
usermod -aG sudo ubuntu
passwd --delete root

Setting an SSH key for the new user account

From our host computer, let's generate a key-pair, copy it to the server, and remove the temporary password:

Host computer

ssh-keygen -t ed25519 -f hostname-ubuntu-key.pem
ssh-copy-id -i ./hostname-ubuntu-key.pem.pub [email protected]
rm hostname-ubuntu-key.pem.pub

You can now log in to your server as the ubuntu user with our new private key:

ssh -i hostname-ubuntu-key.pem [email protected]

From now on we will be making all changes as the ubuntu user.

2. Update all packages

Ensuring your system is up-to-date is an important way of preventing vulnerabilities that allow attackers access to your server.

On Ubuntu apt is used to manage packages.

sudo apt update
sudo apt upgrade
sudo reboot

3. Tighten SSH security

Using SSH key authentication offers convenience (password-less login), while also offering better security than most passwords.

By making some changes to the SSH configuration we can disallow password authentication; empty or otherwise. This makes us rely on using the key we set up in Step 1. At the same time, we will disable root login over SSH. Since we deleted the root password earlier this is redundant, but doing so will ensure root login is never allowed should it return.

Use sudo to edit /etc/ssh/sshd_config and make sure the following are set:

  • PasswordAuthentication no
  • PermitEmptyPasswords no
  • PermitRootLogin no
  • PubkeyAuthentication yes

Lastly, we need to restart the SSH daemon:

sudo systemctl reload sshd

4. Enable the firewall

Running a firewall on your server is an additional line of defense that can help prevent illegitimate services from communicating with the outside world.

This is very simple thanks to ufw (Uncomplicated Firewall). We need to start by allowing OpenSSH (before enabling) or we will restrict ourselves from being able to access the server!

sudo ufw allow OpenSSH
sudo ufw enable

Allowing Nginx through the firewall

We can define additional custom applications to allow them through the firewall.

To create the application profile for Nginx, use sudo to create the file /etc/ufw/applications.d/nginx-service containing:

[Nginx HTTP]
title=Web Server 
description=Enable NGINX HTTP traffic

[Nginx HTTPS] \
title=Web Server (HTTPS) \
description=Enable NGINX HTTPS traffic

[Nginx Full]
title=Web Server (HTTP,HTTPS)
description=Enable NGINX HTTP and HTTPS traffic

Then enable the application profile that you need (either Nginx HTTP, Nginx HTTPS, or Nginx Full). In most cases this will be Nginx Full:

sudo ufw allow Nginx\ Full

5. Installing docker rootless (optional)

By default, Docker runs as the root user. Since the Docker containers and the Docker daemon are running as root, this can be a security risk. We wouldn't want to expose ourselves to any potential vulnerabilities that could allow attackers to break out of the containers (into the host system).

It is possible to run Docker daemon and containers as a non-root user.

First, let's install docker:

sudo apt install ca-certificates curl gnupg lsb-release
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce

Then, let's set up the Docker daemon to run as a non-root user

Note: Sometimes necessary XDG_RUNTIME_DIR and DBUS_SESSION_BUS_ADDRESS environment variables are not set properly in some cases, such as when using su to set up rootless docker for a different user. Make sure to set them as follows export XDG_RUNTIME_DIR=/run/user/$UID export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus

sudo apt install uidmap dbus-user-session

# Disable the system-wide Docker daemon (optional)
sudo systemctl disable --now docker.service docker.socket

dockerd-rootless-setuptool.sh install

# Enable the rootless docker daemon on startup (optional)
systemctl --user enable docker
sudo loginctl enable-linger $(whoami)

As reported the dockerd-rootless-setuptool.sh script, add the following to the bottom of your .bashrc:

export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///run/user/$UID/docker.sock

Allow rootless docker access to privileged ports

When running some services, like Nginx over HTTP/HTTPS, you will want to expose privileged ports (< 1024) on the host.

To enable privileged ports for the rootless docker running on the user, run the following commands:

sudo setcap cap_net_bind_service=ep $(which rootlesskit)
systemctl --user restart docker

Final thoughts

This guide is in no way comprehensive. This guide serves as a very brief introduction to the topic. There are endless guides and resources on the topic, including The Practical Linux Hardening Guide.

If you found this post helpful, please share it around: