Linux Server Security: Part 1
A beginners how-to guide for hardening a Linux server.
Introduction
This year I decided to level up my passion for data science and analytics by building a home analytics lab. Largely, my goal here is to experiment with building machine learning pipelines, though I’m not looking to build a fully functional production environment (…yet). At this stage, it’s more of an educational and exploratory exercise — but it also gives me an opportunity to repurpose some defunct laptops I have kicking around the place.
In pursuing this goal, I decided to build the lab in a Linux environment and have now got Ubuntu 20.04 LTS up and running on an old laptop. I’ll admit, even getting to this point wasn’t without it challenges. Between work commitments and just getting the sever up and running, it’s taken me some time to understand and navigate the intricacies of server setup and management. One of the more critical aspects I’ve encountered on this journey is ensuring my Linux server is actually secure.
As a guiding principle I wanted to adopt best practices right from the start and avoid shortcuts that could create technical issues down the line. After some research — and a lot of trial and error — I think I’ve landed on a solid set of actions anyone can take to secure their Linux server. Good practice is also about creating good documentation for processes and workflows, so I thought I’d document the steps I’ve taken here, so anyone who’s interested can follow along.
So, if you’re new to Linux and server administration — like me — I hope this blog provides some useful insights and guidance. For the initiated among you, much of this may be old news, though I’d be interested to hear your thoughts on server hardening in the comments below.
Just before we dive in, I had originally intended to write this as a self contained article but it just became too long. So instead I have broken everything out into separate parts:
- Part 1: Security Updates & Limited Users
- Part 2: SSH Key-pair Authentication
- Part 3: Disable Password Authentication
- Part 4: Create a Firewall
Finally, Part 1 (this post) assumes you are currently logged in as a root user. However, these steps can be still implemented at a later stage using another user account that has root privileges.
Update & Upgrade Packages
The first step is to update and upgrade all packages. If you’re running Debian, or a Debian-based distribution like Ubuntu, package management is undertaken using the Advanced Package Tool (APT).
On the command line APT is invoked by calling apt
along with the update
and upgrade
commands. Each can be executed by running the following commands:
root@<your-server-ip>:~$ apt update
root@<your-server-ip>:~$ apt upgrade
Let’s just quickly break these commands down.
First, let’s look at update
. Despite its name, update
doesn’t actually update the packages; rather, the update
command updates the local package index. The package index is a database of available packages along with their current version information. When you run apt update
it retrieves the latest version information from the package repositories that are specified in the software sources configuration file. All this command does is refresh the package index and ensure all package information is current.
You can now probably guess what the upgrade
command does. When this command is run, it consults the local package index to see which packages have upgrades available. If any are available it will install the latest versions of those packages. Be aware that you will be asked whether you want to upgrade the packages, so some interactivity is expected. However, you can automate this by running update
along with the option -y
like so:
root@<your-server-ip>:~$ apt -y upgrade
Conveniently, the -y
option automatically answers “yes” to any prompt that may come up during the upgrade process, thereby saving you some decisional anguish.
One final note before we move on; above I called update
and upgrade
in two separate steps; however, it’s quite common to see these steps expressed in a single line like this:
root@<your-server-ip>:~$ apt update && apt -y upgrade
What the &&
operator does here is allow commands to be run sequentially, though the second command is only executed if the first command executes successfully. So, in the example above, upgrade
will only get executed once upgrade
exits with a zero status code. This is particularly useful because it ensures the package index is fully updated before any upgrades are made.
Enable Automatic Updates
Okay, so the step above wasn’t actually a security step per se — but it’s important to get into the habit of updating and upgrading packages. That, along side security upgrades, helps ensure your server is up to date and has the necessary patches. However, this can create a bit of an administrative overhead — what if you miss a patch?
So, the first actual step toward strengthening your server’s security is by enabling automatic updates. This alleviates the need to manually install security patches and upgrades, and ensures you don’t miss anything critical. Thankfully, there is a handy little package called unattended-upgrades
that takes care of this. To install the package run the following command:
root@<your-server-ip>:~$ apt install unattended-upgrades
You’ll see a bit of activity in the terminal while the install completes. Once the install has completed you’ll then need to run the following command:
root@<your-server-ip>:~$ dpkg-reconfigure –plow unattended-upgrades
Let’s break this down a bit. First, let’s just be clear that we have already installed unattended-upgrades
so we’re actually altering the settings of a installed package. That’s what the dpkg-reconfigure
part of the command is all about. But what exactly are we changing?
Well, this is determined by the options passed to dpkg-reconfigure
. In this case, the option is the -p
flag which is short for --priority
. What this setting controls is the priority level for the questions asked during the reconfiguration process. Here, the priority is being set to “low” which generally means that fewer questions require a direct response from you (i.e., less interactivity). However, if you wanted to have more control over how the package is configured, you’d need to up the priority, which in turn increases overall interactivity. For our purposes, having the priority set to low is just fine.
Before moving on, a cautionary note: it’s not a good idea to enable automatic updates on production systems. For development and home environments like mine, this is perfectly fine. However, for production environments, it’s best to schedule defined maintenance windows for security patching and upgrades — but only once you’ve tested how the updates will affect deployed products in a controlled development, or test, environment.
Limited User Account
At this stage we have been using the root account to do these administrative tasks, which in general is a bit of a no-no. The issue is that the root user has zero restrictions and can execute any command — even commands that could accidentally disrupt your server. Instead, what we want to do is set up a limited user account, but allow this user to have root privileges. For certain administrative tasks that require root permissions, this user can temporarily elevate their privileges by using the sudo
command.
We’ll start by first creating a new user called admin
using the command below:
root@<your-server-ip>:~$ adduser admin
You’ll then be asked to create a user password, so go ahead and do that. You can add some additional details if you wish, but this is not strictly necessary.
Next, let’s give our admin
user root privileges. This is done by simply adding admin
to the sudo
group, like so:
root@<your-server-ip>:~$ adduser admin sudo
With admin
added to the sudo
group, this user should now be able to execute commands that require root privileges. So let’s check this out by first opening a fresh terminal and logging into the server using the admin
account:
ssh admin@<your-server-ip>
Once logged in you should notice a change in the terminal prompt with it now prepended with the logged in user:
admin@<your-server-ip>:~$
instead of:
root@<your-server-ip>:~$
We can now take those root privileges for a spin!
As a bit of a test, first try and run the command below:
admin@<your-server-ip>:~$ apt -y upgrade
You should get an error message that looks something like this:
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?
Basically, this is saying that admin
doesn’t have the necessary permissions to upgrade any installed packages. But…we gave admin
root privileges, so what’s going on here? Yes — it’s true that admin
has root privileges, but the issue here is that they haven’t invoked those privileges.
Remember, when the upgrade
command was executed earlier on you were logged in as the root user, and this user has no restrictions whatsoever. The root user doesn’t need to do anything special to execute root commands. But that’s not the case for a limited user with root permissions. No — now that we’re using a this limited account certain commands cannot be run without first elevating your permissions. This means that this user can’t just run amok and freely execute any command.
To elevate permissions all you need to do is prepend sudo
to the command you wish to run, like so:
admin@<your-server-ip>:~$ sudo apt -y upgrade
Now you should be back in business!
That’s it for Part 1!
In the next instalment we’ll cover how to bolster login security by using key-pair authentication. In the meantime, I hope you found something useful in this post. I’m hoping that in sharing my learnings it might help others who are on a similar journey. However, I’m still on the learning curve myself, so I’m keen to hear from the more experienced of you out there.
Catch you in the next one!
Hey there 👋
Thank you so much for stopping by and reading my content! Your support means a lot to me 😊
If you enjoyed this post and would like to stay up to date then please consider following me on Medium. This will ensure you don’t miss out on any new content ⏰
If you’d like unlimited access to all my content consider signing up for a Medium subscription. When Medium members read, listen, and engage with my stories, writers like me receive a portion of your membership dues, so it’s your subscription that helps me keep doing what I do 🙏
If you want to keep tabs on what I’m doing, you can follow my socials: