How to Forward Ports With Iptables in Linux

January 12, 2023

Introduction

Port forwarding is a NAT technique that allows proxy firewalls to redirect communication requests from one IP address and port to another. On Linux systems, port forwarding is frequently set up with Iptables, a utility for configuring IP packet filter rules.

This tutorial teaches you how to forward ports using Iptables.

How to forward ports with Iptables in Linux.

Prerequisites

  • Two Linux systems with internet access and connected to the same private network.
  • Administrative privileges on both systems.

Iptables Port Forwarding

The proxy firewall plays an essential role in securing web application infrastructure. The application is installed on a proxy server with a dedicated public IP and acts as a gateway that protects the internal network from external threats.

The sections below describe the procedure for setting up a simple Iptables-based firewall that controls network traffic to and from a web server.

Step 1: Set up Web Server

The first step in configuring firewall-based network access is ensuring the web server accepts only the connections made over the private network. Follow the steps below to create an example Nginx web server that only allows access from a private IP address.

Gather Web Server Network Interface Details

Open the terminal on the web server and follow these steps:

1. Enter the following command to list the available IPv4 connections

ip -4 addr show scope global

The ip command output lists the available network interfaces and the assigned IP addresses.

Viewing available IPv4 interfaces on a web server.

The output shows the system's private (bond0.10) and public (bond0.3) network interfaces and IP addresses.

3. Write down the interface names and their respective IP addresses.

Set up Nginx

Follow these steps on your web server to install and configure Nginx:

1. Update the repository information on the web server using your Linux distribution's package manager. The tutorial uses APT.

sudo apt update

2. Install the Nginx web server package.

sudo apt install nginx
Installing Nginx with apt on Linux.

Type Y, press Enter, and wait for the installation to finish.

3. Use a text editor such as Nano or Vim to open the configuration file for the default Nginx server block.

sudo nano /etc/nginx/sites-enabled/default

4. Find the server section in the file. The contents should resemble the example below:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

5. Add the server's private IP address before the port number in the section's first line.

listen [web-server-private-ip]:80 default_server;

Delete the second line, as it relates to the IPv6 address not covered in this tutorial. The following example shows the server section after editing.

Editing Nginx configuration to limit the network traffic to the private network.

Save the file and exit.

6. Test the syntax of the Nginx configuration by typing:

sudo nginx -t

Nginx displays syntax errors if any. When there are no errors, Nginx displays the following output:

Testing Nginx configuration syntax.

7. Restart Nginx to apply the new configuration.

sudo systemctl restart nginx

Test Web Server Configuration

Confirm that the Nginx server works as intended with the curl command. Run this command from another computer on the same private network:

curl [web-server-private-ip]

The output shows the HTML data of the Nginx welcome page.

Using curl to test the private network connection with the web server.

To confirm the web server does not accept public network connections, use curl with the server's public IP address.

curl [web-server-public-ip]

Nginx refuses the connection because it is configured to accept requests only from the private network.

Using curl to test the public network connection with the web server.

Step 2: Set up Firewall

After setting up the web server, create a proxy firewall on another machine. The example below shows how to set up a firewall with basic Iptables rules.

Gather Firewall Network Interface Details

On the other machine that will act as a firewall:

1. View the available IPv4 network interfaces with this command:

ip -4 addr show scope global
Viewing available IPv4 interfaces on a firewall.

2. Identify and note the public and private network interfaces and the corresponding IP addresses. In our case, the public interface is bond0.2 with IP 131.153.158, and the private interface is bond0.10 with IP 10.3.0.11.

Install Persistent Firewall Package

1. Update the repository information on the firewall system.

sudo apt update

2. Install the iptables-persistent package.

sudo apt install iptables-persistent
Installing the iptables persistent package with apt on Linux.

Type Y and press Enter to start the installation.

3. When prompted, choose Yes to save the current iptables rules.

Saving Ipv4 rules.

Set up Basic IPv4 Rules

After installing the persistent firewall, edit the firewall server's configuration to set up basic IPv4 rules.

1. Open the rules.v4 file in a text editor to add the rules.

sudo nano /etc/iptables/rules.v4

2. Below is an example configuration, with an explanation of each section provided in the comments.

*filter
# Drop incoming and forwarding packets; allow outgoing packets
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Custom protocol-specific rules
:UDP - [0:0]
# Write UDP rules here
:TCP - [0:0]
# Write TCP rules here
:ICMP - [0:0]
# Write ICMP rules here

# Accept SSH TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT

# Acceptance policy
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT

# Drop a packet if it is invalid
-A INPUT -m conntrack --ctstate INVALID -j DROP

# Pass traffic to protocol-specific chains 
# Allow only new TCP connections established with new SYN packets 
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP

# Reject anything that reached this point
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable

# Commit the changes
COMMIT

*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT

*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT

Save the file and exit.

3. Check the syntax of the rules.v4 file by typing:

sudo iptables-restore -t /etc/iptables/rules.v4

If there are no syntax errors, the command returns no output.

4. Apply the firewall configuration with the following command:

sudo service netfilter-persistent reload
Reloading the netfilter persistent configuration.

5. Print the currently active rules to confirm that the changes have been applied successfully.

sudo iptables -S

The output shows the rules configured in the rules.v4 file.

Viewing the active Iptables rules.

Set up Basic IPv6 Rules

Iptables has an accompanying tool named Ip6tables for setting up IPv6 packet rules. Since this tutorial covers only the creation of an IPv4 firewall with Iptables, the following section shows how to block all traffic via IPv6.

1. Open the rules.v6 file in a text editor.

sudo nano /etc/iptables/rules.v6

2. Instruct Ip6tables to drop all the connections.

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT

*raw
:PREROUTING DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT

*nat
:PREROUTING DROP [0:0]
:INPUT DROP [0:0]
:OUTPUT DROP [0:0]
:POSTROUTING DROP [0:0]
COMMIT

*security
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT

*mangle
:PREROUTING DROP [0:0]
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
:POSTROUTING DROP [0:0]
COMMIT

Save the file and exit.

3. Check the configuration syntax.

sudo ip6tables-restore -t /etc/iptables/rules.v6

4. Apply the new IPv6 rules.

sudo service netfilter-persistent reload

5. List the rules with the following ip6tables command to confirm that the new configuration is active.

sudo ip6tables -S
Viewing the active Ip6tables rules.

Step 3: Set up Port Forwarding

Once you configure both the web server and the proxy firewall, you can create specific forwarding rules that will:

  • Accept traffic requests via the firewall's public IP address.
  • Forward the packets to the firewall's private interface.
  • Forward the packets further to the web server using the private network.
  • Accept and forward the traffic from the web server to the internet.

Enable Forwarding in Kernel

Before using packet forwarding, you must instruct the system to allow it. To enable forwarding for the current session, type:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Enabling packet forwarding for the current session.

Follow the procedure below to enable packet forwarding permanently.

1. Open the sysctl.conf file in a text editor.

sudo nano /etc/sysctl.conf

2. Find the line shown below:

# net.ipv4.ip_forward=1

3. Uncomment the line by removing the initial # symbol.

Enabling packet forwarding on Linux.

Save the file and exit.

4. Load the new file configuration with sysctl:

sudo sysctl -p
Activating packet forwarding.

5. Apply all the system changes.

sudo sysctl --system
Making the system changes to activate packet forwarding.

Packet forwarding now works on the system.

Provide Forwarding Rules

Specify the forwarding rules by adding them to the rules.v4 file. Alternatively, use the command line and the syntax below:

sudo iptables [rule]

Use the following rules to configure the firewall to forward packets to and from the web server properly:

1. Allow public interface connections to port 80 to be established and forward them to the private interface:

sudo iptables -A FORWARD -i [firewall-public-interface] -o [firewall-private-interface] -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT

With the parameters from our example, the rule looks like this:

sudo iptables -A FORWARD -i bond0.2 -o bond0.10 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT

Note: Issuing the Iptables commands via the command line produces no output.

2. Allow packet traffic marked as ESTABLISHED and RELATED to travel from the public to the private interface.

sudo iptables -A FORWARD -i [firewall-public-interface] -o [firewall-private-interface] -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

For example:

sudo iptables -A FORWARD -i bond0.2 -o bond0.10 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

3. Allow the same traffic to return from the private to the public interface.

sudo iptables -A FORWARD -i [firewall-private-interface] -o [firewall-public-interface] -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Using the example parameters:

sudo iptables -A FORWARD -i bond0.10 -o bond0.2 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Provide NAT Rules

NAT rules tell Iptables how to alter the packets to enable proper routing between networks. Simple port forwarding can be achieved with two NAT rules.

1. Alter the packet's destination address, i.e., change it from the firewall's public interface to the web server's private interface.

sudo iptables -t nat -A PREROUTING -i [firewall-public-interface] -p tcp --dport 80 -j DNAT --to-destination [web-server-private-ip]

The following is what the command looks like using the example web server data from the article.

sudo iptables -t nat -A PREROUTING -i bond0.2 -p tcp --dport 80 -j DNAT --to-destination 10.3.0.12

2. Alter the packet's source address to the private IP address of the firewall. This way, the web server sends the packet to the firewall, which forwards it to the source.

sudo iptables -t nat -A POSTROUTING -o [firewall-private-interface] -p tcp --dport 80 -d [web-server-private-ip] -j SNAT --to-source [firewall-private-ip]

The command looks like this with our example parameters:

sudo iptables -t nat -A POSTROUTING -o bond0.10 -p tcp --dport 80 -d 10.3.0.12 -j SNAT --to-source 10.3.0.11

3. Type the following command to save all the Iptables rules.

sudo service netfilter-persistent save

Test Firewall Configuration

To test the final firewall configuration, use curl on another machine to send a request to the public IP address of the proxy firewall.

curl [firewall-public-ip]

The output shows that the firewall successfully forwarded the Nginx page served by the web server.

Using curl to test the Iptables configuration.

Note: Bare Metal Cloud offers server instances that are ideal for firewalls. Read How to Set up a Firewall on s0.d1.small BMC Instance.

Conclusion

After reading this article, you should know how to create a simple Iptables-based firewall and use port forwarding to forward traffic to and from a web server.

If you are using Ubuntu, you may be interested in learning How to Set Up a Firewall with UFW, a user-friendly Iptables interface.

Was this article helpful?
YesNo
Marko Aleksic
Marko Aleksić is a Technical Writer at phoenixNAP. His innate curiosity regarding all things IT, combined with over a decade long background in writing, teaching and working in IT-related fields, led him to technical writing, where he has an opportunity to employ his skills and make technology less daunting to everyone.
Next you should read
Iptables Tutorial
January 28, 2020

Firewalls work by defining rules that govern which traffic is allowed, and which is blocked. The utility firewall developed for Linux systems is iptables.
Read more
How to Delete Iptables Rule
November 8, 2022

Iptables is based on chains that use rules to restrict or allow traffic to the machine. This tutorial will teach you how to list and delete iptables...
Read more
How to Open a Port in Linux
December 15, 2022

The port number is a virtual concept in computer networking that provides a network identifier for a service or application.
Read more
How to Set Up a Firewall with UFW on Ubuntu
December 1, 2022

UFW (Uncomplicated Firewall) is a user-friendly interface implemented on top of iptables. It provides a simple way to configure...
Read more