Have you ever hosted a server (game or web) on your home computer and shared your IP address with friends, but no one could connect?
The issue lies in your router, which hides connected devices behind its own IP address. Everything within the router is a local network, while everything outside is a global network. However, there is no direct mediator between them, only a barrier preventing external connections.
The solution is port forwarding, a technology that directs external requests to an internal device and vice versa. In Linux operating systems, the iptables utility is used for this purpose, which will be the focus of this article.
The commands shown in this guide were executed on a Hostman cloud server running Ubuntu 22.04.
Port forwarding (also known as port mapping) redirects network traffic from one port to another, either through a router (hardware-level) or a firewall (software-level).
With port forwarding, devices within a local network become accessible from the global network. Without it, external requests cannot reach internal devices.
Common scenarios where port forwarding is needed:
For example, if a server in a local network operates on port 8080, port forwarding allows it to be accessed from the global network through port 80.
Example Setup:
This setup allows us to redirect incoming traffic from the global network to the local network.
Linux has built-in tools for handling incoming and outgoing traffic. These tools act as a packet filtering and modification pipeline.
Port forwarding in Linux is based on NAT (Network Address Translation), configured using the iptables system utility.
NAT (Network Address Translation) is a technique that converts external requests from the global network into internal requests within the local network (and vice versa).
Technically, NAT modifies IP addresses and ports in data packets. It is not a standalone utility but a concept or approach.
There are two main types of NAT:
While NAT protects the local network from external access, it requires port forwarding for incoming connections.
Iptables is a Linux utility used to configure NAT (and more) by modifying tables with rule chains that control traffic.
Iptables has five main rule chains:
Iptables has five tables, each using specific rule chains:
The rule chains act as hooks in the packet processing pipeline, allowing iptables to implement port forwarding in Linux.
Port forwarding in iptables follows a standard packet processing flow based on three possible directions:
Incoming Packets (INPUT) Processing Order
Outgoing Packets (OUTPUT) Processing Order
Forwarded Packets (FORWARD) Processing Order
General Processing Order of Tables:
raw
mangle
nat
filter
security
Common types of port forwarding include:
Each type of port forwarding is implemented using a specific set of rules in the iptables tables.
In most Linux distributions, the iptables utility is already installed. You can check this by querying its version:
iptables --version
If iptables is not installed, you need to install it manually. First, update the package list:
sudo apt update
Then, install it:
sudo apt install iptables -y
By default, Linux uses the ufw firewall, which automatically configures iptables. To avoid conflicts, you must stop the ufw service first:
sudo systemctl stop ufw
Then, disable it:
sudo systemctl disable ufw
The basic syntax of the iptables command is as follows:
iptables [TABLE] [COMMAND] [CHAIN] [NUMBER] [CONDITION] [ACTION]
In each specific command, only some of these parameters are used:
The -t
flag specifies the table to operate within:
For filter
:
iptables -t filter
For nat
:
iptables -t nat
For mangle
:
iptables -t mangle
For raw
:
iptables -t raw
For security
:
iptables -t security
If the -t
flag is not specified, the default table is filter
. The security
table is rarely used.
We can perform different operations on rules within each chain:
Add a rule to the end of a chain (-A
):
iptables -A INPUT -s 192.168.123.132 -j DROP
This rule blocks incoming connections from the specified IP address.
Delete a rule by its number (-D
):
iptables -D OUTPUT 7
Insert a rule at a specific position (-I
):
iptables -I INPUT 5 -s 192.168.123.132 -j DROP
Replace a rule (-R
):
iptables -R INPUT 5 -s 192.168.123.132 -j ACCEPT
This replaces a previously added blocking rule with an allow rule.
Flush all rules in a chain (-F
):
iptables -F INPUT
We can also perform operations on entire chains:
Create a new chain (-N
):
iptables -N SOMENAME
Delete a chain (-X
):
iptables -X SOMENAME
Rename a chain (-E
):
iptables -E SOMENAME NEWNAME
Set default policy for a chain (-P
):
iptables -P INPUT DROP
This blocks all incoming connections to the server.
Reset statistics for a chain (-Z
):
iptables -Z INPUT
Each rule can have conditions for its execution:
Specify the protocol (-p
):
iptables -A INPUT -p tcp -j ACCEPT
This allows incoming connections using the TCP protocol.
Specify the source address (-s
):
iptables -A INPUT -s 192.168.123.132 -j DROP
Specify the destination address (-d
):
iptables -A OUTPUT -d 192.168.123.132 -j DROP
Specify network interface for incoming traffic (-i
):
iptables -A INPUT -i eth2 -j DROP
Specify network interface for outgoing traffic (-o
):
iptables -A OUTPUT -o eth3 -j ACCEPT
Specify the destination port (--dport
):
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
Specify the source port (--sport
):
iptables -A INPUT -p tcp --sport 1023 -j DROP
Negate a condition (!
):
iptables -A INPUT ! -s 192.168.123.132 -j DROP
This blocks all incoming connections except from the specified IP address.
Each table supports different actions:
For the filter
table:
For the nat
table:
To redirect local traffic from one port to another:
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80
To remove the rule:
sudo iptables -t nat -D PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80
To forward port 8080 from interface eth0 to port 80 on eth1
:
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.100:80
Then, allow packet forwarding:
sudo iptables -A FORWARD -p tcp -d 10.0.0.100 --dport 80 -j ACCEPT
To forward incoming packets to a remote server:
Enable packet forwarding in the system settings:
echo 1 > /proc/sys/net/ipv4/ip_forward
Add a port forwarding rule:
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80
Allow forwarded packets to be sent out:
sudo iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.100 --dport 80 -j MASQUERADE
It should be noted that iptables is not the only tool for traffic management. There are several popular alternatives.
nftables is a more modern tool for managing traffic in Linux. Unlike iptables, it does not have predefined tables, and its syntax is more straightforward and concise.
Additionally, this utility uses a single command, nft, to manage all types of traffic: IPv4, IPv6, ARP, and Ethernet. In contrast, iptables requires additional commands such as ip6tables, arptables, and ebtables for these tasks.
firewalld is a more complex traffic management tool in Linux, built around the concept of zones and services. This allows network resources to be assigned different levels of security.
The configuration of firewalld is broader and more flexible. For example, instead of manually defining rules for each port, we can specify specific services.
Additionally, firewalld provides a more interactive command-line interface, allowing real-time traffic management.
While there are alternatives, iptables remains the primary tool for traffic control in Linux. It provides a structured way to filter, modify, and forward packets, making it a powerful solution for managing network traffic.