Basics of securing a new server

//

steve

What is a server?

It’s a word we use everyday but I think people might struggle to define it. Essentially a server is just a computer. In fact almost any computer can be a server. There’s different types of servers such as web serversfile serversemail serversgaming serversDNS serverscloud servers and plenty more. A single computer can host many services depending on the resources it has available e.g. CPU, RAM, GPU (usually necessary if doing complex tasks with data or AI), disk space etc.

Let’s look at what a web server is and how it works. A web server listens for http traffic which typically runs on port 80. Generally a client such as a browser will request a path such as “/” (which would be the root of the site) this request is bundled up by the browser in a special way and sent to the server which looks at the routeheaders and sometimes a payload and then responds appropriately with say an HTML page. The client recieves this and then the browser renders it accordingly.

The route is the site path e.g. “/about” this is important as the web server needs to know what part of the site we’re talking about.

Headers are attached to each request whether GET or POST and they include information such as the type of text to accept, user-agent string (a string which your browser automatically sends to websites informing them about your operating system, browser and browser version) and cookies can be sent through headers too.

The payload is generally used for POST request data which contains form data or something you wouldn’t want to encode into a URL. For instance running a GET request on “/login?user=bob&password=myverysecurepassword” would be a very bad idea so we send data to “/login” (or wherever) instead as a POST request and then this is sent separately to the server.

GET requests are simply requests to a URL with some headers and generally nothing else. Any data such as form data that the server recieves would have to be encoded in the URL somehow if the server is to retrieve it.

POST requests however are different. They send their data as a payload to the server and the data is not included in the URL. This is useful for things like a login page where you wouldn’t want the username and password being included in the URL. We’ll speak about this when we mention MITM (Man In The Middle) attacks later on. For now note that POST itself isn’t inherently secure and TLS (Transport Layer Security) which is used by the https protocol is still required for this to be secure. Of course this doesn’t eliminate vulnerabilities but it prevents MITM attacks which we’ll cover later.

There are other types of requests such as PUTOPTIONSDELETE and more but you don’t need to know about these for now. Additionally GET requests can technically have a body/ payload but this is almost unheard of and should never be done.

If you open your browser developer tools you can see requests going to and form the web page. This is the best way to get an understanding how these work so if the theory above didn’t quite click then don’t worry.

Quick rundown on what a protocol is

Simply put a protocol is a set of standards which dictate how information is handled. This includes how it’s sent and how it’s recieved. Protocols are great! For instance the Simple Mail Transfer Protocol (SMTP) is a set of rules and instructions explaining how we package up emails and send them to an email server. The protocol also explains to the email server how to unpackage the data, verify it’s integrity and what to do in different scenarios. This is an abstraction of course but the benefit of this is that Google Mail and Outlook can both communicate via the SMTP protocol without being the same platform. We love that!

Email is decentralised meaning that unlike something like WhatsApp you can choose from an infinite number of email providers or even create your own. They can all communicate with each other without a central server. This structure is something I am very fond of as it allows for more freedom; if you don’t like Gmail because of the way it looks or the fact they used to scan your emails to advertise to you, or maybe the fact they used to put fake emails at the top of your inbox that were actually adverts then you can create your own email and it can look and behave however you like. There’s no vendor lock-in here.

UDP and TCP magic?

You don’t really need to know much about this but I mention it lightly throught this guide to if you’re interested then here’s an explanation.

To keep things simple, there are pretty much only two types of network traffic: UDP and TCP. These are packets (or chunks) of data which are sent around the internet.

I won’t get into what TCP and UDP traffic is too deeply but essentially they’re different protocols which tell to computer who to send and recieve data UDP traffic isn’t guaranteed to arrive. It’s used for things like VoIP (Voice over IP, or WiFi calling) or Facetime where packets can be dropped without much consequence. Typically traffic with low-latency and real time goes through UDP. TCP on the other hand is for things like text, http/s, ssh, etc where you don’t want to be losing data. In fact TCP carries out checks to ensure data integrity – this is part of the TCP protocol where the client sends over the packets (basically chunks of data with headers such as the order and stuff) and then the when they’re recieved there’s a check to ensure they’re all there. UDP and TCP can get very complicated though and there’s not much need to get bogged down with it if you don’t need to.

What’s all this speak about ports?

Well when we send traffic to and from a server we generally send it via a specific port. This is useful because then when the traffic is recieved it knows where to go. Let’s assume you were running an SSH server on port 22 (the default SSH port) and a web server on port 443 – the default https port. If we were to send a request to the computer it wouldn’t know whether it was for SSH or the web server. This would be very confusing. As a result we generally have one service running on a single port when it comes to TCP traffic, UDP traffic is slightly different. This does get more complicated later but that’s the general idea.

If you’re still struggling to understand it then see the diagram below. Imagine each piece of traffic being a boat carrying different types of cargo e.g. food, clothing, technology, etc. Each boat gets it’s own berth (we’ll call this a port) which it can dock in and out of. The clothing boat goes to the clothing port at the harbour so that it’s contents can be put straight onto a lorry which takes them to various clothing stores. If we had all the boats coming into the same port then this would be so confusing because we wouldn’t know what each boat was coming for and how to process it when it arrives.

Docking port for boats

Firewall shinanigans

Your computer (and your servers operating system) will likely have many, many services running on lots of different ports. You won’t even know about lots of them. If we expose your VPS (your main server not just a web server running on it) to the internet then anyone can connect to your machine and interact with these ports.

Inbound and outbound

You might here this come up, essentially inbound connections are others connecting to your machine and outbound connections are ones your machine makes. Most often we don’t care too much about outbound connections but we very much care about connections coming into our machine. When you run sudo ufw allow 22 for instance this allows all inbound connections through port 22. Note that By default UFW doesn’t block any outbound connections.

How do firewalls work?

Let’s say your Postgres database is running on port 5432 on your machine. In this scenario clients never need to connect to the database directly. When they make a request to say “/dashboard” the backend server automatically picks up the JWT (more on this later) from the server to authenticate the user, internally contacts the Postgres database to grab the user data and then sends it back to the client. As you can see only the backend server needed to communicate with Postgres. If anybody was able to communicate with Postgres then they could do some pretty bad stuff right? Especially if you used weak credentials or default ones. They could just go to your server’s IP address and contact it directly. What if there was a vulnerability in a service running on your machine or even in Postgres? This could mean that the attacker can communicate with it in a specific way to access things they shouldn’t. This could mean accessing your entire operating system and everything running on it! We don’t want this!

A firewall is perfect to prevent this. It has a set of rules which dictate what traffic comes in and what comes out. Most devices and routers run firewalls by default. Firewalls run on an operating system or firmware and monitor all traffic coming in and out and only allow it to come through if it meets the rules set by the systems administrator. If we setup a firewall which only allows access to port 443 (the https port) then even if there is a Postgres database running on port 5432 it won’t be able to communicate with anything outside of the local network, keeping it safe. Fortunately our web application running on port 443 will still be accessible to the world.

Most routers run firewalls. This means that even if devices have exposed ports, the router will stop them being accessible. Your router gives you access to the internet. It routes traffic. You most likely have one at home with Sky, BT or another Internet Service Provider. This means if you wanted to run a web server which is accessible to the world you’d need to expose port 443 (or whichever port you’re running the web server on) on your server and then additionally expose it on your routers firewall. Most VPS’s you rent will not have a router firewall so you need to be very careful and make sure your VPS itself is running one.

Note that it’s okay to expose some ports but we want to minimise the amount of “holes” in our system to reduce to attack surface. The less we give attackers the harder it is to get in. Think of it as reducing the amount of doors and windows in a building. If we have lots of different doors and windows surrounding our building then there’s so many more opportunities for attackers or bad actors to exploit issues with the doors such as the hinges being on the outside, letterbox being open, lock being easy to crack etc. By reducing it to one or two doors we can keep a good eye on what’s happening with those doors and focus on ensuring they’re secure.

The Swiss Cheese model

A nice analogy used in various fields is the Swiss Cheese model. In Cyber Security it relates to the amount of holes in our system and how reducing them reduces attack vectors.

Swiss Cheese model diagram

Setting up a firewall

The simplest firewall and most widely used firewall on servers is called UFW it stands for “Uncomplicated Firewall”. On Ubuntu live (the most popular operating system for servers) this is installed but not enabled by default. If it’s not installed just run sudo apt install ufw on debian based distributions or sudo pacman -Syu ufw on Arch based distros. To enable it so it’s running and listening for traffic run sudo ufw enable. This will run on boot. You can see the current firewall rules by running sudo ufw status or even see them listed as numbers with sudo ufw status numbered – you’ll see why this is useful later on.

Let’s allow port 22 for SSH by running sudo ufw allow 22. I personally prefer sudo ufw allow 22/tcp which only allows TCP traffic.

We can also delete rules using UFW with sudo ufw delete 1. This will delete the first rule. Hopefully now you can see why the sudo ufw status numbered command is useful as it allows us to see the position of a rule in the list which we can later use for things like deleting. You can also reset it with sudo ufw reset but please note this will deactivate it and you’ll need to run sudo ufw enable again to reinstate it.

That’s the basics of UFW 😀

Stop running as root! PLEASEEEE

Okay so you want to run something on your machine. WHY ARE YOU RUNNING IT AS ROOT! Root is the administator, it has pretty much full access to the entire system, the firewall, users, files, packages, everything! It has full control over everything! If you run something as root and it happens to get compromised then it’s possible that an attacker could have full access to your entire machine. Nevertheless it’s very bad practice. If you’re running as root then you might accidentally do something that could harm your system, running sudo makes you think twice. Nonetheless it’s messy! If you have lots of things running as root in the root directory then it’s a nightmare. Also…all those programs are running as root so they have access to every file on the system, read, write and execute permission!

Hmm, these users and groups sound pretty good

We can create users and assign them specific priveledges. We tend to assign these using groups. For example users added to the “sudo” or “wheel” group (depending on your configurations) will have super priveledges. In Linux everything is a file. Commands are no different, they’re executable files. You can even create your own command which takes arguments, it can be a bash/ shell script, a binary or something else. You can add it to /usr/local/bin and then it will become globally available in your terminal. Main programs are stored in /usr/bin but it’s good practice to put any binaries you make in the usr/local/bin folder. Regardless it is just a file. Files can have readwrite and execute permissions such as “Only root can run this” or “Only users in the whatever group can read this (but not execute or write/ modify)”. In Linux you can create a group and call it anything you like but there are some predefined ones which tend to come out of the box like sudo or wheel.

Creating a user

To create a new user we need to run useradd -m -G sudo bob – run this with something like sudo if you’re not root. The useradd command adds a user. The “-m” flag creates the user a directory in the home folder – in this case it would be “/home/bob” – this is important because if you suddenly tried to switch to bob you wouldn’t even be able to run ls to list the files in the current working directory. This is because at this stage almost every file on this system is owned by root and only root has read, write and execute access . It also gives bob permission to access this folder. The “-G” flag stands for “group” and in this case adds the user to the sudo group so they can access sudo. Finally the users name “bob” is added.

Great so we’ve created bob but how do we login to bob? Well first I think it would be good to give bob a password. To do this run passwd bob. You’ll then be prompted to enter bob’s new password twice. This command can also be run if bob forgot their password which would allow root (or another user with super priviledges) to change bob’s password for them.

To login to bob run su bobsu stands for “switch user”. You might be prompted to type in the password to bob depending on various things. If you wanted to return to root (or the user you were before) you could simply run exit or su root. If you ever forget root’s password or don’t have it then you can always run sudo su which will switch the user to root.

Now what?

Well your server is hopefully a lot more secure now than it was when it first booted. We’ll look at secure SSH, reverse proxies and containorisation next to ensure everything you decide to run on your machine stays safe and secure.