Enabling the firewall

Note: Configuring a firewall can be a bit tricky for folks new to server management AND it can be very easy to get wrong. Just go slowly through this section and you’ll be fine. I try and keep things simple and only add a few rules.

Our server is pretty locked down at this point, but the bread-and-butter of any secured system is a really tight firewall policy – never letting IN unexpected traffic and some times not letting OUT unexpected traffic.

A good headspace to be in when setting up a firewall is one of “whitelisting” – namely, that everything is blocked and only things you specifically list are allowed.

Warning: Do not enable the firewall until you have it configured correctly – remember, you have likely moved SSH to a non-standard port already and unless you specifically allow connectivity to it.

The moment you enable the firewall you could lock yourself out of the server and be unable to reconnect.

So let’s go slow and double check our work.

Ok so with that big red warning out of the way, let’s get things configured!

Check what is currently running

You can use the following command to output to the terminal all the ports open and listening for connections:

netstat -tulpn

You should see a fairly short list, maybe 1 or 2 services listening (typically SSH on a port and DNS on port 53).

Tip: If you are going through this guide on a server that has a number of other services running, be sure to compensate for that as you are configuring the firewall rules below otherwise connections to them will be blocked as soon as we enable the firewall (e.g. FTP Server, HTTP Server, log server, etc.)

Configuring the firewall

The first and most important rule we need to get right before we start up the firewall, is allowing SSH through. It’s our only way of accessing the server (for the most part) and we don’t want to lock ourselves out of the house.

Going back to the step in the guide of moving SSH to a port other than 22, if you didn’t write down the port, you can quickly check the SSH Daemon configuration for it by doing the following:

cat /etc/ssh/sshd_config | grep Port

You should see output like the following if you’ve been following this guide so far:

#Port 22
Port 1234
#GatewayPorts no

Ok, it looks like we have the SSH Daemon running on Port 1234 in this example, so let’s remember that.

Adding the most important rule

Now that we know which port (1234) we need to leave open in the firewall. The good news on Ubuntu is it uses UFW (Uncomplicated Firewall) – so it’s pretty easy to add a rule:

$ sudo ufw allow 1234
Rules updated

Tip: The ORDER in which you execute the ufw allow/deny rules matters – UFW (iptables) has a “first match wins” policy. If you add a number of rules, you can see them in an ordered list UFW (iptables) will match against them with the command: sudo ufw status numbered

Now we can start up the firewall and really lock this server down!

(you may see a warning asking you to confirm)

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

Tip: We use enable here instead of restart because it does 2 things: (1) schedules the firewall to start as a system service on reboot and (2) reloads the firewall rules so they take effect.

If all went well and you got the configuration correct, your terminal session was NOT terminated and you are still connected to the server.

You can check the details of the running firewall with the following command (on Ubuntu):

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To                         Action      From
--                         ------      ----
1234                       ALLOW IN    Anywhere  

Excellent – we are blocking ALL INCOMING connections except the ones we need for SSH to make a connection and allowing ALL OUTGOING connections.

We can move on to the next section!

I want ALL the security!

Tip: Consider this section optional, unless you are familiar with firewalls and troubleshooting rules. If you aren’t, this section could cause you a LOT of headaches.

If you really want to get things locked down, blocking ALL OUTGOING connections from your server except ones needed for approved system operation certainly increases the safety of the server, but also becomes a bit more complex to manage which is why I didn’t bring it up as a required step.

The firewall’s current configuration is doing two things right now:

  1. Deny ALL INCOMING connections, except on Port 1234 (for SSH).
  2. Allow ALL OUTGOING connections.

As mentioned at the top of this section, it can be a good idea to consider blocking all OUTGOING connections (except key strategic ones you need) in case malware were to ever run on your server and not be able to get out with your data through a combination of strong user/group permission controls and network management.

Remember: Once you start block OUTGOING, unless you add exceptions for them, all sorts of operations like apt-get, git, ping and curl will hang/fail on this box – because they will be blocked. So don’t forget to open them back up if you need them.

To do this we will want to change the default OUTGOING policy to that of deny with the following command:

$ sudo ufw default deny outgoing
Default outgoing policy changed to 'deny'
(be sure to update your rules accordingly)

And as before, we will want to reload the firewall with the new policy in place:

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

Now let’s check the verbose status of our firewall to see if the change has taken effect:

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), deny (outgoing), disabled (routed)
New profiles: skip
To                         Action      From
--                         ------      ----
1234                       ALLOW IN    Anywhere 

Looking at the Default line we see our INCOMING and OUTGOING modes are both in deny mode and we have 1 INCOMING ALLOW exception for Port 1234 specifically (for SSH).

Excellent, you have got your server locked down like Fort Knox!

Whoops, too much! Let’s open a few things up…

As mentioned, right now you are blocking ALL OUTGOING connections from this server which means all sorts of system operations like using apt-get to update packages will hang & fail.

Unless you specifically re-enable those rules, the server might be locked down a bit too much to function effectively.

As mentioned above, the ORDER in which you add firewall rules is actually important; UFW (which wraps iptables) uses a “first match wins” policy, so seeing the order of the rules as we modify them is helpful.

You can do that with the following command:

$ sudo ufw status numbered
Status: active
     To                         Action      From
     --                         ------      ----
[ 1] 1234                       ALLOW IN    Anywhere 

In this case, we only have 1 rule so it’s pretty straight forward.

Let’s add some exceptions to the outbound rules to get some key system utils working again:

$ sudo ufw allow out http
Rule added
$ sudo ufw allow out https
Rule added
$ sudo ufw allow out 53
Rule added

Then reload the server and let’s print out the numbered rules again to see what we get:

$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
$ sudo ufw verbose numbered
Status: active
     To                         Action      From
     --                         ------      ----
[ 1] 1234                       ALLOW IN    Anywhere                  
[ 2] 80/tcp                     ALLOW OUT   Anywhere  (out)
[ 3] 443/tcp                    ALLOW OUT   Anywhere  (out)
[ 4] 53                         ALLOW OUT   Anywhere  (out)

Now let’s make sure some system utils, like apt-get and curl, are working:

$ sudo apt-get update
Hit:1 http://us.archive.ubuntu.com/ubuntu focal InRelease
Get:2 http://us.archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]
... SNIP ...
$ curl www.google.com
<!doctype html><html itemscope=""> 
... SNIP ...

We did it! WE DID IT!

You can sleep like a baby at night now.

Tip: You may need to live with this outbound blocking for a while before you realize all the services/things it’s blocking that you might need to unblock. Be sure to stay vigilant testing your services and watching their log files for connectivity errors.

If you’d like to dabble further with UFW, I found these links helpful: