Internal Port Forwarding on Linux using the Firewall

Below are instructions for how to set up port forwarding on various Linux distributions using the firewall. The example uses port 5901 (default VNC port) as the destination and port 443 (default HTTPS port) as the source. This setup would let you connect to VNC over port 443 instead without changing the VNC configuration. 

Red Hat/CentOS 7 use firewalld as the default firewall application:

1)      Login to the root account

su -

2)      Install firewalld

yum install -y firewalld

3)      enable and start firewalld

systemctl enable firewalld
systemctl start firewalld

4)      add rule to allow port 22 for ssh

firewall-cmd --permanent --add-port=22/tcp

5)      add rule to forward port 443 to port 5901

firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=5901

6)      reload the firewall

firewall-cmd --reload

Ubuntu*/Debian systems can use ufw as a firewall for port

1)      Login to the root account
su -

2)      Make sure ufw is installed and enabled

apt-get install -y ufw
update-rc.d ufw enable
service ufw start

3)      Edit the /etc/ufw/before.rulesAdd the below lines to the top of the file and save the file

-A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 5901

5)      Allow connections on the needed ports in ufw (note 22 is for ssh and just included so you can ssh back to the server)

ufw allow 22
ufw allow 443
ufw allow 5901

6)      Enable ufw

ufw enable

7)      Reboot the server


*Note that Ubuntu 16 uses systemd so use systemctl to start/enable the firewall instead of the service command.

Distribution agnostic solution:

This solution uses iptables which is built into the Linux Kernel so is available on all distributions of Linux. Modern Distributions ‘mask’ iptables so you will not be able to save this port forwarding solution past your current session (so you would need to re-enter it every time you start/reboot the server, even with the iptables-save command), but this way you can see how to accomplish this on any system. You can also un-mask iptables if you want to use it instead of firewalld or other firewall applications.

 Login as root then enter the below two commands

iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 5901

 A breakdown of the command so you can modify it for other services/ports if you find the need. 

  • “iptables” This is a firewall/routing application that is built into the Linux kernel so is on every Linux system. It is a very complicated program and is not very easy to learn (at least for me and in comparison to modern firewall applications). So instead most modern distributions come with a firewall application that ‘masks’ iptables and has easier to use/mange commands that then adjust the iptables rules for you. Firewalld used above is one that is a part of the systemd stack and is standard for Red Hat/CentOS.
  •  “-t nat” This says you’re modifying the nat ‘table’. There are multiple tables that iptables can modify. Nat is for when new connections are made.

  •  “-A PREROUTING” This says to append the rule to the end of the PREROUTING chain. Appending just means you’re adding it without overwriting any existing rules. The PREROUTING chain is a list of rules to apply before routing new connections. Since we want to forward from one port to a new one, we need the rule to take effect before it has been routed.

  •  “-p tcp” This says we’re looking for tcp packets. There’s a few different types you can choose from (tcp or udp being the most common). VNC is a tcp connection so that’s what we need for this example.

  •  “--dport 443” Packets with destination 443 are the target.

    You can change this if you want to connect using a different port on your computer.
  •  “-j REDIRECT” stands for “jump REDIRECT” which means the action is a REDIRECT. So when a packet is found that matches port 443/tcp we are going to redirect it

  •  “--to-port 5901” Pretty autological. We are going to redirect it to port 5901. If you want to redirect to different service you can change this to whatever the normal port for that service is.

  •  “iptables-save” This just saves the configuration so it will persist through a reboot of the server. 

  • post-author-pic
    Terrence C

    Nice job on that!

  • post-author-pic
    Thomas H

    Awesome post, Sean.

  • post-author-pic
    Tadas P

    Nice one! Many thanks for shareing!

  • post-author-pic
    Azeh Valentine K

    Thanks for the sdetail information

  • post-author-pic
    Alexandru C

    Hey, nice job. I have a few questions.
    Lets say i have 1 application working on node.js and the default port for that is port 3000. Now i know you can modify it from the config files, but let's say i want to redirect that to port 80. How do i do that? I mean is there a possible way to do it without killing everything else that's working on the same server,on the same port 80? Like Apache, Nginx, Postgres Db etc. I had this problem and it took me 1 week to realize that i can modify the port from the app's config files.

  • post-author-pic
    Sean G

     @Hultanu  Generally you only want one application per port. 

    It may be possible to have multiple applications per port, but it adds a ton of complexity and can cause all sorts of problems if not done exactly right. 

  • post-author-pic
    Pierre D

    Great info.

    I'm currently stumped though on an issue on my router that uses iptables. I need a rule that will specifically target the tunnel's interface I’m trying to access on my home internal LAN. My home router is running both OpenVPN Client and Server so I remote into the VPN server on my router and can’t access an IP on my home internal LAN that is tunneling through my clientOpenVPN service running on that same router. If I use a more lenient policy rule setting in my router which doesn't require me to specifically target the destination interface, I'm able to access it. When I remotely VPN into my router (using VPN Server service), 'ifconfig' shows it as tun21 with a 10.8.0.x network. The internal client I'm trying to access at using the VPNClient service uses tun11. What nat table or forwarding rules do I need to put into my nat script that will allow me access to the client?

  • post-author-pic
    Michael M

    Thanks!  I needed that info,  guess it's time to learn firewalld...

  • post-author-pic
    Lethargos A

     @pdemassey You can easily push a route within the openvpn config file. For instance, if your network is, then simply add the following in /etc/openvpn/server.conf:

    push "route"
    Then, after connecting to openvpn, if you check your computer's routing table (the client you're connecting from, not the server), you're going to see the new route in your routing table.

  • post-author-pic
    Terrence C

    Nice guide!

  • post-author-pic
    Lethargos A

    [test for profile name]

  • post-author-pic
    Pablo P

    Is it possible to do an internal por forwarding without opening the redirect port to the internet? I mean without "ufw allow 5901". Thanks.

  • post-author-pic
    Sean G

     @pablopazos Yes, this should be possible if you only allow it on the internal network, but it becomes more complicated and I wanted to keep this pretty simple. 

    For ufw, you can specify an ip address range that is allowed. So for instance ufw allow from to any port 5901 would allow any devie on the subnet to connect to port 5901 on your server.

  • post-author-pic
    Pablo P

    Thanks, what I need to do is redirect 80 to 8080 internally and have only 80 open to the internet. This way needs 2 open ports. The same needs to be done for 443, ending with 4 open ports instead of 2 (80 & 443).

Looking For Team Training?

Learn More