Ryan S. Chiang

Iptables Rules for Nginx Reverse Proxy + Node.js Apps

Photo by Viktor Forgacs

Updated

8 min read

Using Nginx as a reverse proxy is common approach if you want to host multiple Node.js apps on the same VPS.

I was familiar with using ufw for my firewall, but on a new instance I'm running bitnami, which uses iptables instead.

So here's a quick guide on how to set up iptables rules for Nginx reverse proxy + Node.js apps.

Note: I'm not an iptables expert, so I'm not sure if these rules are the best way to do it, but they work for me.

Warning: Messing around with iptables can be dangerous. If you're not careful, you can lock yourself out of your server. I recommend creating a backup of your server and ensuring if you do get locked out you can still access your server via the console.

The Iptables Rules

Here are the rules I'm using:

bash# Make a backup of your current iptables rules
sudo iptables-save > ~/iptables-backup

# IMPORTANT STEP: Allow inbound traffic to SSH. Otherwise you'll get locked out of your server.
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Allow outbound SSH (e.g. for Git pull)
sudo iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT

# SAFELY set default policies to DROP (i.e. reject all traffic unless explicitly allowed)
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT DROP

# Allow HTTP and HTTPS traffic
sudo iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT

# Allow established and related connections (to maintain ongoing connections)
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

# Allow loopback traffic (for internal communication between apps)
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

# Allow inbound and outbound DNS traffic (e.g. for communicating with external APIs)
sudo iptables -A OUTPUT -p udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 53 -m state --state ESTABLISHED -j ACCEPT

# Allow outbound git traffic (git protocol uses port 9418)
sudo iptables -A OUTPUT -p tcp --dport 9418 -m state --state NEW,ESTABLISHED -j ACCEPT

# Allow related inbound git traffic (git protocol uses port 9418)
sudo iptables -A INPUT -p tcp --sport 9418 -m state --state ESTABLISHED -j ACCEPT

# Persist IPTABLES rules (this will give option to save)
sudo apt update
sudo apt-get install iptables-persistent

# If you make changes later, manually save rules
sudo iptables-save > /etc/iptables/rules.v4  # IPv4 rules
sudo ip6tables-save > /etc/iptables/rules.v6  # IPv6 rules (if applicable)

Explanation of the Rules

Here's a quick explanation of what each rule does:

1. Make a backup of your current iptables rules

bashsudo iptables-save > ~/iptables-backup

This saves a backup of your current iptables rules. You can restore your rules by running:

bashsudo iptables-restore < ~/iptables-backup

2. Allow inbound traffic to SSH

bashsudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

This allows inbound traffic to SSH. This is very important, otherwise you may get locked out of your server while making changes.

3. Allow outbound SSH traffic

bashsudo iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT

This allows outbound SSH traffic, which is necessary if you want to pull code from a Git repo.

4. SAFELY set default policies to DROP

bashsudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT DROP

Now that SSH is allowed, we can safely set the default policies to DROP. This means that all traffic will be rejected unless explicitly allowed.

5. Allow HTTP and HTTPS traffic

bashsudo iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT

This allows inbound and outbound HTTP (port 80) and HTTPS (port 443) traffic.

When using an Nginx reverse proxy, Nginx will listen on ports 80 and 443 and forward traffic to your Node.js apps (running on different ports, like 3000, 4000, etc.).

Since we're using a reverse proxy, we don't need to allow inbound traffic to the Node.js apps themselves.

However, if your setup is different, and you want to allow inbound traffic to your Node.js apps, you can do so by adding rules for each port, e.g.:

bashsudo iptables -A INPUT -p tcp --dport 3000 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --sport 3000 -m conntrack --ctstate ESTABLISHED -j ACCEPT
bashsudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

This allows established and related connections. This is necessary to maintain ongoing connections.

7. Allow loopback traffic

bashsudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

The loopback (lo) rules allow internal communication within the server itself, such as a service connecting to a local database or applications communicating via the loopback network interface (localhost). For example, a Node.js app can connect to a PostgreSQL database running on the same server via localhost.

8. Allow inbound and outbound DNS traffic

bashsudo iptables -A OUTPUT -p udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 53 -m state --state ESTABLISHED -j ACCEPT

This step allows inbound and outbound DNS traffic. This is necessary for communicating with external APIs because the server needs to be able to resolve the domain name to an IP address. For example, if you're using a third-party API like Stripe, your server needs to be able to resolve api.stripe.com to an IP address.

DNS uses both TCP and UDP, so we need to allow both. DNS requests are typically sent from a random high port, so we need to specify the source port (--sport) for inbound traffic to be port 53. Similarly, for outbound traffic, the destination port (--dport) needs to be port 53.

9. Allow git traffic

bashsudo iptables -A OUTPUT -p tcp --dport 9418 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 9418 -m state --state ESTABLISHED -j ACCEPT

Git protocol uses port 9418, so we need to allow outbound and inbound traffic on this port. I'm not entirely sure if this is necessary if you're using SSH to pull code from a Git repo, but I added it just in case.

10. Persist iptables rules

bashsudo apt update
sudo apt-get install iptables-persistent

# If you make changes later, manually save rules
sudo iptables-save > /etc/iptables/rules.v4  # IPv4 rules
sudo ip6tables-save > /etc/iptables/rules.v6  # IPv6 rules (if applicable)

Finally, we need to persist the iptables rules. This will give you the option to save the rules when you install iptables-persistent. If you make changes later, you can manually save the rules.

Wrapping up

I hope sharing my iptables setup helps! If you have any questions or ƒeedback, feel free to let me know.

I'm still learning about iptables, so if you have any suggestions on how to improve these rules, I'd love to hear them.

Ryan Chiang

Meet the Author

Ryan Chiang

Hello, I'm Ryan. I build things and write about them. This is my blog of my learnings, tutorials, and whatever else I feel like writing about.
See what I'm building →.

If you want an alert when I write a new blog post (not often), you can subscribe below:

0

Comments

Leave a Comment

Your email will not be published. Required fields are marked *

2024

2023

© 2024 Ryan Chiang