Port forwarding is simple to do with iptables in a Linux box which may probably already being used as the firewall or part of the gateway operation. In Linux kernels, port forwarding is achieved by packet filter rules in iptables.

Port forwarding

Port forwarding also called “port mapping” commonly refers to the network address translator gateway changing the destination address and/or port of the packet to reach a host within a masqueraded, typically private, network.

Port forwarding can be used to allow remote computers (e.g., public machines on the Internet) to connect to a specific computer within a private network such as local area network (LAN), sothat xternal hosts can communicate with services provided by hosts within a LAN. For example, running a public HTTP server (port 80) on a host within a private LAN, or permitting secure shell ssh (port 22) access to hosts within the private LAN from the Internet.

In Unix/Linux box where port numbers below 1024 can only be listened by software running as root, port forwarding is also used to redirect incoming traffic from a low numbered port to software listening on a higher port. This software can be running as a normal user, which avoids the security risk caused by running as the root user.


iptables is a very powerfull firewall which handles packets based on the type of packet activity and enqueues the packet in one of its builtin ‘tables’. In Linux box, iptables is implemented in Linux kernel as some kernel modules.

There are three tables in total: mangle, filter and nat. The mangle table is responsible for the alteration of service bits in the TCP header. The filter queue is responsible for packet filtering. The nat table performs Network Address Translation (NAT). Each tables may have some built-in chains in which firewall policy rules can be placed.

The filter table has three built-in chains:

  • Forward chain: Filters packets destined for networks protected by the firewall.
  • Input chain: Filters packets destined for the firewall.
  • Output chain: Filters packets originating from the firewall.

The nat table has the following built-in chains:

  • Pre-routing chain: NATs packets when the destination address of the packet needs to be changed.
  • Post-routing chain: NATs packets when the source address of the packet needs to be changed.
  • Output chain: NATs packets originating from the firewall.

Below is a brief view of how packets are processed by the chains:

 - nat (dst)   |           - filter      - nat (src)
               |                            |
               |                            |
              INPUT                       OUTPUT
              - filter                    - nat (dst)
               |                          - filter
               |                            |

Note: if the packet is from the firewall, it will not go through the PREROUTING chain.

We only look into the packets that requires port forwarding which is the topic of this post.

The packet entering the firewall is inspected by the rules in the nat table’s PREROUTING chain to see whether it requires destination modification (DNAT). The packet is then routed by Linux router after leaving the PREROUTING chain. The packet which is destined for a “protected” network is filtered by the rules in the FORWARD chain of the filter table. The it will go through the packet undergoes SNAT in the POSTROUTING chain before arriving at the “protected” network. When the destination server decides to reply, the packet undergoes the same sequence of steps.

Port forwarding using iptables

This section assumes you have already set up the the Linux host as the gateway and configured the POSTROUTING rules as shown in Setting Up Gateway Using iptables and route on Linux for SNAT.

A port-forwarded packet will pass the PREROUTING chain in nat table, FORWARD chain in filter table, POSTROUTING chain in nat table and other chains. We need to add rules to these chains.

Let’s use a senario to introduce how to configure iptables to do port forwarding. Suppose our gateway can connect to both the Internet ( and the LAN ( The gateway’s eth0 interface has a public IP while the eth1 has a LAN IP Now, suppose that we have set up a HTTP server on and we want to provides service to the Internet through the public IP. We need to configure iptables to forward packets coming to port 80 of to 8080 of in LAN.

Below is the network topology:


Normally we deny all incoming connections to a gateway machine by default because opening up all services and ports could be a security risk. We will only open the ports for the services that we will use. In this example, we will open port 80 for HTTP service.

First make sure that the IP forwarding is enabled on Linux following the “Enable Linux IP forwarding” Section in Setting Up Gateway Using iptables and route on Linux.

This is the rules to forward connections on port 80 of the gateway to the internal machine:

# iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j DNAT --to
# iptables -A FORWARD -p tcp -d --dport 8080 -j ACCEPT

These two rules are straight forward. The first one specifies that all incoming tcp connections to port 80 should be sent to port 8080 of the internal machine This rule alone doesn’t complete the job as described above that we deny all incoming connections by default. Then we accept the incoming connection to port 80 from eth0 which connect to the Internet with the publich IP by the second rule. From the process path in the “iptables” part, the packet will also pass the FORWARD chains. We add the second rule in FORWARD chain to allow forwarding the packets to port 8080 of

By now, we have set up the the iptables rules for forwarding the 80 port. For other service, the method is similiar with the HTTP service.

The conntrack entries

The “nf_conntrack_*” kernel modules enables iptables to examine the status of connections by caching the related information for these connections. A cat of /proc/net/nf_conntrack (in some old Linux kernels, the file is /proc/net/ip_conntrack) will give a list of all the current entries in the conntrack database.

A conntrack entry looks like this:

ipv4     2 tcp      6 431581 ESTABLISHED
src= dst= sport=53867 dport=80 packets=22 bytes=13861
src= dst= sport=8080 dport=53867 packets=14 bytes=3535
[ASSURED] mark=0 secmark=0 use=2

This entry contains all the information that the conntrack module maintains to know the state of a specific connection. We can find the version of ip protocal version and the decimal coding, the protocol and the normal decimal coding. After this, we get how long this conntrack entry should live. Next is the actual state that this entry is in at this present point of time. Then, we get the source IP address, destination IP address, source port and destination port. After that, we get the IPs and ports of both source and destination we expect of return packets.

In this entry we can find that the arriving connection is: -->

while the returning connection is: -->

which reflects the port forwarding which we have set.

About Eric Zhiqiang Ma

Eric Zhiqiang Ma is interested in operating systems and distributed computing and processing systems. Find Eric on Facebook, Twitter, LinkedIn and Google+. The views or opinions expressed here are solely Eric's own and do not necessarily represent those of any third parties.


  1. Pingback: Port Forwarding
  2. Thank you very much for this diagram of packet flow!! Before that I could understand iptables partially, but some things were still not clear to me. Once I saw this diagram everything became clearly understandable at one moment. This is the thing which most of the manuals really lack.

  3. Is it possible to forward the port on the same machine? for instance, suppose your server is your firewall and you want to login to ssh. But, you don’t want to expose port 22 to the web and can’t change the port in the ssh server. Can you forward, say port 2222 to port 22, on the same server box?

      1. The computer has 2 nics, 1 with a public ip and one with a local ip ( I tried but could not get it to work. But, that does not mean I did it right. how would you do it?

  4. I have a trouble to map to web server with this network topology:

    Internet———[router]——-[Linux firewall] eth0
    eth2 | eth1 —-|—
    | |
    | |
    LAN2 (Web/Mail Server) LAN1

    I did ACCEPT rules and MSQ to LAN1 for home PCs but can’t do work the webserver or mail server for http://www.mybloqdomain.com.

    I tryed with those rules for LAN2 but nothing happen:

    # iptables -A PREROUTING -t nat -i eth0 -p tcp –dport 80 -j DNAT –to
    # iptables -A FORWARD -p tcp -d –dport 80 -j ACCEPT

    Must does POSTROUTING and FORWARD from LAN2 to Internet TOO?

    any help please?

    1. The rules look good at my first glance. The Web/Mail server should be able to connect to the Internet through the Linux firewall and the router so that the client on the Internet can communicate with it.

  5. Helo ppl !!

    I have an issue with Debian Proxmox x2.3 with 2 bridged NICS, vmbr0 (public IP) and vmbr1 (

    There are 4 VMs going outside through NAT without any problem. All network is visible, all computers see all, etc. ‘Till here all fine ! !

    Now I want to forward some ports from the internet to internal VMs, but this is not working, and I’m not expert in this !

    I tried a lot of things without any success:

    iptables -t nat -A PREROUTING -i eth0 -p udp –dport 3389 -j DNAT –to-destination
    iptables -t nat -A PREROUTING -i vmbr0 -p udp –dport 3389 -j DNAT –to-destination
    iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 3389 -j DNAT –to-destination

    iptables -A PREROUTING -t nat -i eth0 -p tcp –source –dport 25 -j DNAT –to

    This is my interfaces file:

    # network interface settings
    auto lo
    iface lo inet loopback

    iface eth0 inet manual

    auto vmbr1
    iface vmbr1 inet static
    bridge_ports none
    bridge_stp off
    bridge_fd 0
    post-up echo 1 > /proc/sys/net/ipv4/ip_forward
    post-up iptables -t nat -A POSTROUTING -s ‘′ -o vmbr0 -j MASQUERADE
    post-down iptables -t nat -D POSTROUTING -s ‘′ -o vmbr0 -j MASQUERADE

    auto vmbr0
    iface vmbr0 inet static
    bridge_ports eth0
    bridge_stp off
    bridge_fd 0

    any tip ?

          1. Now worked, but same, nothing ….

            Could this work?

            iptables -t nat -A PREROUTING -d -p udp -m udp –dport 3389 -j DNAT –to-destination

            1. If you are using the UDP protocol, you should change the tcp to udp in the rule.

              And remember to set the rule in FORWARD chain. It may also block you connection. one example:

              iptables -A FORWARD -p tcp -d --dport 8080 -j ACCEPT

                1. You may also check whether the ports are blocked by other devices (e.g. the network gateway).

                  And also note that these rules only works for external IPs (not from the host or the VMs).

                  1. My friend, there’s nothing between the proxmox node and the VMs.

                    From the node, I can ping and see all internal LAN, from the VMs I see internet. And yes, I know this is only to pass the NAT from outside using the public proxmox node (vmbr0). Rest is OK and working without any issue.

                    This is a fresh Debian with latest proxmox.

                    Anyway, thanks for your help !

                    1. I see. By now, I can not figure out what’s the problem without working on your node. But I am curious to know how you fix it. Please share with us if possible.

      1. Ahh, sorry, I forgot the —

        But same problem, not working, and I don’t get any error entering the IPTABLES command :-?

  6. I struggled with this for many hours. Would have been nice to mention in this post that ip_forward option must be enabled.

    echo 1 > /proc/sys/net/ipv4/ip_forward

  7. Could you show us the content of iptables file. I just can’t make this work without POSTROUTING that you don’t mention and it would be nice to compare files .


  8. May i ask you to help me on this ?

    All UDP-packets going out should be changed to TCP-packets at the
    same port.

    1. TCP and UDP are different protocols. Simply changing from UDP to TCP may confuse the applications unless they are aware of the protocol changing. Even the applications are aware of the protocol changing, iptables may not be suitable for your purpose. You may need a “proxy” application that knows that application semantics.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>