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".
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.
/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.