I recently migrated some of my personal projects from running on Vercel and Netlify onto a self managed Ubuntu Server VM on Oracle Cloud.
Because this is a shift from application platforms that abstracts away the underlying infrastructure to setting up and managing everything myself, one of the things I had to do was opening the VM instance's ports to accept traffic on 80 and 443.
This was not something I was familiar with, and the solution I stumbled onto was to modify the netfilter rules directly.
sudo vi /etc/iptables/rules.v4Here are the lines I had to add to the rules that allow tcp traffic on port 80 and 443.
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPTThe end result is a rules.v4 file that looks like this:
# Generated by iptables-save v1.8.10 (nf_tables) on Sat Nov 22 02:20:23 2025
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [197:22391]
:InstanceServices - [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A OUTPUT -d 169.254.0.0/16 -j InstanceServicesOnce modified, I ran:
sudo netfilter-persistent reload
sudo netfilter-persistent saveOne important note is that the ordering of each line is important. The two new lines we added must come before the -A INPUT -j REJECT --reject-with icmp-host-prohibited line to take effect. This was something that I ran into - even though I had added the two new rules opening port 80 and 443 towards the bottom of the file, they were never evaluated because the new rules appeared below the pre-existing REJECT rule. The mis-ordering caused my curl <my-instance-ip>:80 command to showing the following error:
* Failed to connect to <my-instance-ip> port 80 after 78 ms: Couldn't connect to serverIf you run into a similar error, check to see if there's a REJECT rule that's taking precendence. The rules are evaluated from top to bottom, and the first applicable rule will take precedence.
Also, another note for my future self is that after this was all said and done, I'd learn that there are more modern utilities like ufw that provides a more ergonomic way of configuring netfilter. But I'm glad to have done it my way, just for the learning experience!