Tools: How To Forward Ports through a Linux Gateway with Iptables

Tools: How To Forward Ports through a Linux Gateway with Iptables

Source: DigitalOcean

NAT, or network address translation, is a general term for mangling packets in order to redirect them to an alternative address. Usually, this is used to allow traffic to transcend network boundaries. A host that implements NAT typically has access to two or more networks and is configured to route traffic between them. Port forwarding is the process of forwarding requests for a specific port to another host, network, or port. As this process modifies the destination of the packet in-flight, it is considered a type of NAT operation. Two key operations make this possible: DNAT (Destination NAT), which rewrites the destination address of incoming packets, and SNAT (Source NAT), which rewrites the source address of outgoing packets so that replies can route back correctly. In this tutorial, you will learn how to use iptables to forward ports through a Linux gateway using NAT techniques, including DNAT and SNAT rules in the PREROUTING and POSTROUTING chains. This is useful if you’ve configured a private network but still want to allow certain traffic inside through a designated gateway machine. You will set up IP forwarding at the kernel level, configure the firewall’s packet filtering rules, and write NAT table entries to route port 80 traffic to an internal web server. Note: This tutorial was originally written for Ubuntu 20.04 and has been validated on Ubuntu 22.04 and Ubuntu 24.04 LTS. The iptables commands, kernel forwarding parameters, and netfilter-persistent service used in this guide work the same way across all current Ubuntu LTS releases. If you are running a different Ubuntu version, the steps will still apply as long as the iptables and iptables-persistent packages are installed. To follow along with this guide, you will need: If you are new to iptables, reviewing the iptables essentials guide will help you become familiar with common firewall rules and commands before proceeding. The server on which you set up your firewall template will serve as the firewall and gateway for your private network. For demonstration purposes, the second host will be configured with a web server that is only accessible using its private interface. You’ll be configuring the firewall machine to forward requests received on its public interface to the web server, which it will reach on its private interface. Before you begin, you need to know what interfaces and addresses are being used by both of your servers. To get the details of your own systems, begin by finding your network interfaces. You can find the interfaces on your machines and the addresses associated with them by running the following: The highlighted output shows two interfaces (eth0 and eth1) and the addresses assigned to each (203.0.113.1 and 10.0.0.1 respectively). To find out which of these interfaces is your public interface, run this command: The interface information from this output (eth0 in this example) will be the interface connected to your default gateway. This is almost certainly your public interface. Find these values on each of your machines and use them to follow along with the rest of this guide. To make things clearer, we’ll be using the following empty address and interface assignments throughout this tutorial. Please substitute your own values for the ones listed in the following: Web server network details: Firewall network details: Begin connecting to your web server host and by logging in with your sudo user. The first step is to install Nginx on your web server host and lock it down so that it only listens to its private interface. This will ensure that your web server will only be available if you correctly set up port forwarding. Begin by updating the local package cache: Next, use apt to download and install the software: After Nginx is installed, open up the default server block configuration file to ensure that it only listens to the private interface. Open the file using your preferred text editor. Here we’ll use nano: Inside, find the listen directive. It should be listed twice in a row towards the top of the configuration: At the first listen directive, add your web server’s private IP address and a colon before the 80 to tell Nginx to only listen on the private interface. We’re only demonstrating IPv4 forwarding in this guide, so you can remove the second listen directive, which is configured for IPv6. Next, modify the listen directives as follows: Save and close the file when you are finished. If you used nano, you can do this by pressing CTRL + X, then Y, and ENTER. Now test the file for syntax errors: If there are no errors in the output, restart Nginx to enable the new configuration: At this point, it’s useful to verify the level of access you have to your web server. From your firewall server, try to access your web server from the private interface with the following command: If successful, your output will result in the following message: If you try to use the public interface, you’ll receive a message that says it cannot connect: These results are expected. Now you will work on implementing port forwarding on your firewall machine. The first thing you need to do is enable traffic forwarding at the kernel level. By default, most systems have forwarding turned off. To turn port forwarding on for this session only, run the following: To turn port forwarding on permanently, you will have to edit the /etc/sysctl.conf file. You can do this by opening the file with sudo privileges: Inside the file, find and uncomment the line that reads as follows: Save and close the file when you are finished. Then apply the settings in this file. First run the following command: Then run the same command, but replace the -p flag with --system: Next, you will configure your firewall so that traffic flowing into your public interface (eth0) on port 80 will be forwarded to your private interface (eth1). The firewall you configured in the prerequisite tutorial has your FORWARD chain set to DROP traffic by default. You need to add rules that will allow you to forward connections to your web server. For security’s sake, you’ll lock this down fairly tightly so that only the connections you wish to forward are allowed. In the FORWARD chain, you’ll accept new connections destined for port 80 that are coming from your public interface and traveling to your private interface. New connections are identified by the conntrack extension and will specifically be represented by a TCP SYN packet as in the following: This will let the first packet, meant to establish a connection, through the firewall. You’ll also need to allow any subsequent traffic in both directions that results from that connection. To allow ESTABLISHED and RELATED traffic between your public and private interfaces, run the following commands. First for your public interface: Then for your private interface: Double check that your policy on the FORWARD chain is set to DROP: At this point, you’ve allowed certain traffic between your public and private interfaces to proceed through your firewall. However, you haven’t configured the rules that will actually tell iptables how to translate and direct the traffic. Next, you will add the rules that will tell iptables how to route your traffic. You need to perform two separate operations in order for iptables to correctly alter the packets so that clients can communicate with the web server. The first operation, called DNAT, will take place in the PREROUTING chain of the nat table. DNAT is an operation that alters a packet’s destination address in order to enable it to correctly route as it passes between networks. The clients on the public network will be connecting to your firewall server and will have no knowledge of your private network topology. Therefore, you need to alter the destination address of each packet so that when it is sent out on your private network, it knows how to correctly reach your web server. Since you’re only configuring port forwarding and not performing NAT on every packet that hits your firewall, you’ll want to match port 80 on your rule. You will match packets aimed at port 80 to your web server’s private IP address (10.0.0.1 in the following example): This process takes care of half of the picture. The packet should get routed correctly to your web server. However, right now, the packet will still have the client’s original address as the source address. The server will attempt to send the reply directly to that address, which will make it impossible to establish a legitimate TCP connection. On DigitalOcean, packets leaving a Droplet with a different source address will actually be dropped by the hypervisor, so your packets at this stage will never even make it to the web server (which will be fixed by implementing SNAT momentarily). This is an anti-spoofing measure put in place to prevent attacks where large amounts of data are requested to be sent to a victim’s computer by faking the source address in the request. To configure proper routing, you also need to modify the packet’s source address as it leaves the firewall en route to the web server. You need to modify the source address to your firewall server’s private IP address (10.0.0.2 in the following example). The reply will then be sent back to the firewall, which can then forward it back to the client as expected. To enable this functionality, add a rule to the POSTROUTING chain of the nat table, which is evaluated right before packets are sent out on the network. You’ll match the packets destined for your web server by IP address and port: SNAT vs MASQUERADE: In this guide we use SNAT because we have a static private IP address on the firewall. If your gateway’s IP address is dynamically assigned (for example, via DHCP), use the MASQUERADE target instead. MASQUERADE automatically uses the outgoing interface’s current IP address, but it is slightly slower than SNAT because it must look up the address for every packet. For static IPs, SNAT is the better choice. Once this rule is in place, your web server should be accessible by pointing your web browser at your firewall machine’s public address: Your port forwarding setup is now complete. Now that you have set up port forwarding, you can save this to your permanent rule set. If you do not care about losing the comments that are in your current rule set, use the netfilter-persistent command to use the iptables service and save your rules: If you would like to keep the comments in your file, open it up and edit manually: You will need to adjust the configuration in the filter table for the FORWARD chain rules that were added. You will also need to adjust the section which configures the nat table so that you can add your PREROUTING and POSTROUTING rules. The contents will resemble the following: Save and close the file once you’ve added the content and adjusted the values to reflect your own network environment. Next, test the syntax of your rules file: If no errors are detected, load the rule set: Now test that your web server is still accessible through your firewall’s public IP address: This should work the same as it did before. When configuring iptables port forwarding on a Linux gateway, you should follow these security best practices to keep your network protected: Restrict forwarded ports to specific services. Only forward the ports that are strictly necessary. Each forwarded port creates an entry point into your private network, so avoid opening ports you don’t need. Limit source IP addresses when possible. If you know which external IP addresses need access, add a source filter to your PREROUTING rule. For example, to allow only 198.51.100.0/24 to reach your web server through port 80: Regularly review your rules. Use iptables -L -v -n and iptables -t nat -L -v -n to list and audit your firewall rules periodically. Stale or overly permissive rules can leave your network exposed. Keep iptables up to date. Run sudo apt update && sudo apt upgrade regularly to apply security patches. For a broader look at firewall strategies, read How To Choose an Effective Firewall Policy to Secure Your Servers. If your port forwarding is not working as expected, work through the following checklist to identify the problem. 1. Verify IP forwarding is enabled: This should return 1. If it returns 0, IP forwarding is disabled. Re-enable it using the steps in the “Enabling Forwarding in the Kernel” section above. 2. Check your NAT rules are loaded correctly: Look for your PREROUTING and POSTROUTING rules. Make sure the destination IP, port, and interface names are correct. 3. Inspect the FORWARD chain: Confirm that your FORWARD rules appear before the default DROP policy. Rules in iptables are evaluated top to bottom, so ordering matters. 4. Verify the backend service is running: If this times out from the firewall machine, the problem is with the web server, not the firewall rules. Check that Nginx is running and listening on the correct private IP address. 5. Check for cloud firewall conflicts: If you are running on DigitalOcean or another cloud provider, external cloud firewalls may be blocking traffic before it reaches your Droplet’s iptables rules. Make sure your DigitalOcean Cloud Firewall (if configured) allows inbound TCP traffic on port 80 to your firewall server’s public IP. 6. Watch traffic in real time with tcpdump: To see whether packets are arriving at your firewall’s public interface: If you see incoming SYN packets but no forwarded traffic on eth1, the issue is likely in your FORWARD or NAT rules. Starting with Debian 10 (Buster) and Ubuntu 20.10, the Linux ecosystem has been transitioning from iptables to nftables as the default packet filtering framework. On Ubuntu 20.04, 22.04, and 24.04 LTS, the iptables command still works because Ubuntu provides iptables-nft, a compatibility layer that translates iptables syntax into the nftables backend. This means the commands in this tutorial will work on all current Ubuntu LTS releases without modification. Here is a quick comparison: If you want to write the same port forwarding rules using native nftables syntax, it would look like this: For most Ubuntu LTS users, the iptables commands shown in this guide remain fully supported through the compatibility layer. If you are setting up new infrastructure or planning a migration, learning native nftables syntax is worth the investment. For more on managing firewall rules, see UFW Essentials: Common Firewall Rules and Commands, which covers the UFW frontend that sits on top of iptables/nftables. When running your Linux gateway on a cloud provider such as DigitalOcean, there are additional networking considerations to keep in mind. VPC and private networking: On DigitalOcean, private networking between Droplets is provided through VPC (Virtual Private Cloud). Your Droplets must be in the same VPC to communicate over private IP addresses. When setting up port forwarding, make sure both your firewall and web server Droplets are in the same VPC and region. Cloud firewalls and iptables: DigitalOcean Cloud Firewalls are applied at the hypervisor level, before traffic reaches your Droplet. This means cloud firewall rules are evaluated before your iptables rules. If you are using both, make sure: Anti-spoofing: As mentioned earlier, DigitalOcean’s hypervisor drops packets with source addresses that don’t match the Droplet’s assigned IP. This is why the SNAT rule in the POSTROUTING chain is essential. Without it, your web server’s responses (with the client’s original source address) would be dropped by the hypervisor before leaving the network. Floating IPs: If your firewall Droplet uses a DigitalOcean Reserved IP (formerly Floating IP), the public traffic arrives on a special anchor interface. You may need to adjust your PREROUTING rule’s -i interface accordingly. Check your interfaces with ip addr to identify the correct one. DNAT (Destination NAT) changes the destination IP address of an incoming packet. It is used in the PREROUTING chain so packets arrive at the correct internal server. SNAT (Source NAT) changes the source IP address of an outgoing packet, and it is used in the POSTROUTING chain so that reply packets route back through the gateway instead of being sent directly to the client. In a port forwarding setup, you typically need both: DNAT to redirect the incoming request and SNAT to ensure the response returns through the firewall. For a deeper understanding of how packets traverse the iptables chains, see A Deep Dive into Iptables and Netfilter Architecture. IP forwarding is the kernel-level feature that allows a Linux machine to pass packets between its network interfaces. Without it enabled (net.ipv4.ip_forward=1 in /etc/sysctl.conf), the kernel will drop any packet that arrives on one interface and is destined for another. Since port forwarding means receiving a packet on the public interface and sending it out through the private interface, IP forwarding must be turned on for the process to work. You can forward multiple ports by adding separate DNAT, SNAT, and FORWARD rules for each port. Alternatively, use the multiport extension to match several ports in a single rule. For example, to forward both ports 80 and 443: You can also specify port ranges using the format 8000:9000. For more examples of common iptables rules, see Iptables Essentials: Common Firewall Rules and Commands. Yes. The rules are similar, but you replace -p tcp with -p udp and remove the --syn flag (since UDP is connectionless). For example, to forward UDP port 53 (DNS) to an internal server: The conntrack module tracks UDP “connections” based on the source/destination address and port pair, so established and related rules still apply for return traffic. While nftables is the newer framework and has been the default backend since Debian 10, iptables is not fully deprecated. Ubuntu LTS releases (20.04, 22.04, 24.04) ship with iptables-nft, which translates iptables commands into the nftables kernel API. This means you can continue using the familiar iptables syntax without issues. However, for new projects, learning nftables is recommended because it offers better performance, a simpler unified syntax, and atomic rule updates. By now, you should be comfortable with forwarding ports on a Linux gateway with iptables. The process involves three main steps: enabling IP forwarding at the kernel level, configuring FORWARD chain rules to allow traffic between interfaces, and setting up DNAT and SNAT rules in the NAT table so that packets are routed and translated correctly. You also learned security best practices for port forwarding, how to troubleshoot common issues, and how iptables compares to the newer nftables framework. This approach works across Ubuntu 20.04, 22.04, and 24.04 LTS, giving you a reliable method for controlling how traffic flows through your gateway firewall machine. For related learning, explore these resources: Want to simplify your networking? DigitalOcean Cloud Firewalls let you define inbound and outbound rules at the infrastructure level without managing iptables on each server. Combined with VPC for private networking and Droplets for scalable compute, you can build secure, private networks with minimal configuration. Get started with a free DigitalOcean account and try it today. Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases. Learn more about our products I help Businesses scale with AI x SEO x (authentic) Content that revives traffic and keeps leads flowing | 3,000,000+ Average monthly readers on Medium | Sr Technical Writer @ DigitalOcean | Ex-Cloud Consultant @ AMEX | Ex-Site Reliability Engineer(DevOps)@Nutanix This textbox defaults to using Markdown to format your answer. You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link! Excuse me,but I have a question.Is is a proxy server.If not,how are they different? so, this is a lot of info. I would like to offer a shorter bit of info that might help people. In order to forward incoming http connections from port 80 (default) to port 5000 (which was the port my react app was serving on) I did the following: sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 5000
sudo /sbin/iptables-save Nice blog. Thanks for putting this up. I was facing traffic issues in AWS environment having one private subnet, and another subnet connected through VPN to my company network. The packets were not being sent in either direction even after setting ip_forward=1 and all the iptables rules mentioned in this blog. One thing I realized I had to do was to set the private IP of NAT server as default router in my web server. Just thought of mentioning this - in case someone faces similar problems in future. You change the client ip address to the internal ip address of the firewall which is 192.0.2.15 with the following command: sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 192.0.2.2 -j SNAT --to-source 192.0.2.15 My question, how can the packet be returned back to the client, since the destination ip address only reach the internal ip address of the firewall? I think the above command does not necessary, as long as the web server has a proper gateway. thanks. Is this same rule for allow rtp port to asterisk server? If I have two virtual external NIC in my firewal with two IP @,
I want to forward each one to a server on port 80
How I can do this Thanks for the guide, it did work for me. However, my gateway is also doing IP masquerading/NAT and after applying these rules, I lose all egress from the web server. After the forwarding port, How can I get network usage on the forwarded port(in this tutorial 80)?
Is it possible with iptables?
I try it :
sudo iptables -A FORWARD -p tcp --dport 80 -j DROP,
sudo iptables -A FORWARD -p tcp --dport 80 -m quota --quota 100000 -j ACCEPT,
but it doesnt work. This post save my life!! Perfect tutorial! Thanks! Please complete your information! Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation. Full documentation for every DigitalOcean product. The Wave has everything you need to know about building a business, from raising funding to marketing your product. Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter. New accounts only. By submitting your email you agree to our Privacy Policy Scale up as you grow — whether you're running one virtual machine or ten thousand. Sign up and get $200 in credit for your first 60 days with DigitalOcean.* *This promotional offer applies to new accounts only.