Port forwarding with iptables

By Jake Morrison in DevOps on Wed 16 May 2018

In order to listen on a TCP port less than 1024, an app traditionally needs to be started as root. Over the years this has resulted in many security problems.

A better solution is to run the application on a normal port such as 4000, and redirect traffic in the firewall from e.g. port 80 to 4000 using iptables.

Port forwarding with ufw

UFW is Ubuntu's "Uncomplicated Firewall".

Enable ufw

sudo ufw enable

Allow traffic to the app port

sudo ufw allow 4000/tcp

UFW doesn't have an easy command to do port forwarding, unfortunately, so we need to add a raw iptables rule.

Edit /etc/ufw/before.rules. At the top of the file, add the following:

*nat
:PREROUTING ACCEPT [0:0]
-A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 4000
COMMIT

Port forwarding with raw iptables

First, open up access to the app port:

sudo iptables -A INPUT -p tcp --dport 4000 -j ACCEPT

We can also open the port with rate limiting, useful for dealing with DDOS attacks. The following command allows five requests per minute from a single IP address, with a burst of 10:

sudo iptables -A INPUT -p tcp --dport 4000 -m state --state NEW \
    -m hashlimit --hashlimit-name HTTP --hashlimit 5/minute \
    --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-htable-expire 300000 -j ACCEPT

Finally, redirect port 80 to port 4000:

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 4000

You can see the rules with:

sudo iptables -L -n -v
sudo iptables -t nat -L -n -v

We need to make the rules persistent so that they will still be there when the machine is rebooted.

sudo apt install netfilter-persistent iptables-persistent
sudo netfilter-persistent save

Configuring iptables with Ansible

This example project for deploying Phoenix apps has Ansible tasks to set up iptables for port forwarding.

<< Back to blog index

Featured posts

Deploying an Elixir app to Digital Ocean with mix_deploy Port forwarding with iptables