Protect Ubuntu server with firewall – Custom server (part 3)

In previous articles, I guided you to set up a server using nginx-proxy and Docker. While the server is now operational, it’s essential to be aware that leaving ports open can potentially grant unrestricted access to your server to anyone.

Check out previous articles here:

In this tutorial, I will show you how to secure your server using firewall. Ubuntu has a package named UFW which allows you to deny or allow requests to specific ports and from specific IPs. UFW is installed by default on Ubuntu. You can reinstall if it’s missing using this command:

sudo apt install ufw

Step 1: Setup default policies

By default, you should deny all incoming connections and allow all outgoing connections

Run these commands to set

sudo ufw default deny incoming
sudo ufw default allow outgoing

Note: Do not restart UFW service since you need to open SSH port first otherwise you will lose access to your server.

Step 2: Enable SSH connections

SSH is the way for you to control the server, you will need to allow SSH connections

# Check if SSH is allowed
sudo ufw app list
# Allow SSH connection
sudo ufw allow ssh

Its defaults enable SSH from all IPs, If you have a static IP, I highly recommend you allow it only from your location

sudo ufw allow ssh 203.0.113.111

Also, recommend you change your default SSH port. That’s quick and easy

  1. Open /etc/ssh/sshd_config and locate the line
    #Port 22
  2. Then uncomment it and change the value to an appropriate port. example 2200
    Port 2200
  3. Restart SSH server:
    systemctl restart sshd

Then allow the new port in UFW

Step 3: Allow other Connections

You can allow any ports or services that you need. Common are HTTP and HTTPS ports. Sometimes you need to open the database port to modify your data from the local IDE but you shouldn’t leave it open but restrict it to your IP instead

# Enable http connections
sudo ufw allow 80
# Enable https connections
sudo ufw allow 443

Step 4: Enable UFW and testing

sudo ufw enable

Check if it works

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
2200/tcp                   ALLOW       Anywhere                  
80/tcp                     ALLOW       Anywhere                  
443/tcp                    ALLOW       Anywhere                                    
2200/tcp (v6)              ALLOW       Anywhere (v6)             
80/tcp (v6)                ALLOW       Anywhere (v6)             
443/tcp (v6)               ALLOW       Anywhere (v6)  

Now you can see, that you can’t SSH to your server using port 22, and from other IP addresses if you did allow only your static IP.

You still can access your API via domain using HTTP and HTTPS.

All good now! but somehow you still can access your API server using ServerIP:3000 which shouldn’t be since we already deny all connections?

The problem is Docker write directly to iptables of the system that allows connections to go to docker containers directly without being filtered by UFW.

There are 2 solutions to fix that:

  1. Prevent docker from modifies iptables – Works but may result in docker services being unable to reach the internet.
  2. Using docker-ufw – Works but has some drawbacks

I will show you how to setup docker-ufw as it works better than solution #1
Checkout full document in GitHub repo

Install docker-ufw

sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker

Run install command, it will default deny all connections to docker services

ufw-docker install

Now you can see, you no longer have access to ServerIP:3000 and all other ports

You should only allow connections to ports 80 and 443 of docker

Run this command to allow all ports of service nginx-proxy

ufw-docker allow nginx-proxy

Run this command to check if you have set it correctly

ufw-docker status
172.18.0.2 443/tcp         ALLOW FWD   Anywhere                   # allow nginx-proxy 443/tcp travis-server_default
172.18.0.2 80/tcp          ALLOW FWD   Anywhere                   # allow nginx-proxy 80/tcp travis-server_default

Now you can access your server normally.

Drawbacks: There is one drawback of this way is every time you re-deploy or restart servers which causes the internal IP of service to change you need to allow it again which automatically removes old IPs and add new ones. You can find or write a script to automate that!

That’s all! See you in the next articles.

References:

https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu

https://thuanbui.me/khac-phuc-loi-ufw-khong-hoat-dong-khi-su-dung-docker/

https://www.ubuntu18.com/ubuntu-change-ssh-port