I am using UFW to protect my network. How do I forward TCP HTTP port # 80 and 443 to an internal server hosted at and using UFW on Ubuntu Linux server?

UFW is an acronym for uncomplicated firewall. It is used for managing a Linux firewall and aims to provide an easy to use interface for the user. In this tutorial, you will learn how to forward incoming traffic to your server running ufw on port 80/443 to port 80/443 on another internal server hosted in your LAN/VLAN or Linux containers.
Tutorial details
Difficulty level Advanced
Root privileges Yes
Requirements Linux terminal
Category Firewall
Prerequisites ufw command
OS compatibility AlmaLinux Alpine Arch Debian Fedora Linux Mint openSUSE Pop!_OS RHEL Rocky Stream SUSE Ubuntu
Est. reading time 3 minutes

Our sample setup

Let us say you want to forward requests going to {80,443} to a server listening on{80,443}:

Fig.01: How to configure ufw to redirect http traffic to another IP:port

Fig.01: How to configure ufw to redirect http traffic to another IP:port

All request for port 80 and 443 need to redirect to another internal server.


If you have a server on your internal network that you want make available externally, you can use the -j DNAT target of the PREROUTING chain in NAT to specify a destination IP address and port where incoming packets requesting a connection to your internal service can be forwarded. The syntax is as follows for the iptables command:
# /sbin/iptables -t nat -A PREROUTING -i eth0 -p tcp -d {PUBLIC_IP} --dport 80 -j DNAT --to {INTERNAL_IP}:80
# /sbin/iptables -t nat -A PREROUTING -i eth0 -p tcp -d {PUBLIC_IP} --dport 443 -j DNAT --to {INTERNAL_IP}:443

Postrouting and IP Masquerading

To allow LAN nodes with private IP addresses to communicate with external public networks, configure the firewall for IP masquerading, which masks requests from LAN nodes with the IP address of the firewall’s external device such as eth0. The syntax is:
# /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# /sbin/iptables -t nat -A POSTROUTING -s ! -d -j MASQUERADE

How to configure ufw to setup a port forward

You need to edit /etc/ufw/before.rules file, enter:
$ sudo vi /etc/ufw/before.rules
Next configure ufw to redirect http traffic to another (LAN) IP:port. At the top file, append:

# forward  port 80 to
# forward  port 443 to
-A PREROUTING -i eth0 -d   -p tcp --dport 80 -j  DNAT --to-destination
-A PREROUTING -i eth0 -d   -p tcp --dport 443 -j  DNAT --to-destination
# setup routing

Save and close the file. Edit /etc/sysctl.conf:
$ sudo vi /etc/sysctl.conf
Set/edit as follows:


Save and close the file. Reload changes:
$ sudo sysctl -p
Finally, restart the firewall to enable routing using the systemctl command:
$ sudo systemctl restart ufw
Make sure port 80 and 443 is allowed, otherwise ufw will block the requests that are redirected to internal{80,443}:
$ sudo ufw allow proto tcp from any to port 80
$ sudo ufw allow proto tcp from any to port 443

Verify new settings:
$ sudo ufw status
$ sudo iptables -t nat -L -n -v

Finally, make sure your domain has DNS type ‘a’ set to

A note about lxd proxy protocol

Do you want to avoid typing all these iptables rules? LXD now supports proxy devices. It allows forwarding network connections between the LXD host and instance type container or VM. In other words, we can forward traffic hitting one of the LXD host’s IP addresses to an address inside the instance/container. Of course, you can also do the reverse and have an address in the instance/container connected through the host. The syntax is:

lxc config device add {container-name} {device_name_here} proxy listen=tcp:${src_IP}:${src_port} connect=tcp:${dest_ip}:${dest_port}

In this example redirect ssh traffic to container named ubuntu-nginx:

lxc config device add ubuntu-nginx ssh-reditect proxy listen=tcp: connect=tcp:


  • ubuntu-nginx – LXD container or instance vm name
  • ssh-reditect – Unique name per LXD container or instance vm name
  • listen=tcp: – Public or private IPv4/IPv6 and port to listen on
  • connect=tcp: – Forward traffic to this LXD instance’s IP:PORT

Also, check all our complete firewall tutorials for Alpine Linux Awall, CentOS 8, OpenSUSE, RHEL 8, Debian 12/11, Ubuntu Linux version 16.04 LTS/18.04 LTS/20.04 LTS, and 22.04 LTS.


In this tutorial, you learned how to configure UFW to forward tcp port 80/443 to internal hosts or Linux containers hosted by the LXD. See the ufw command manual page using the man command:
$ man ufw

🥺 Was this helpful? Please add a comment to show your appreciation or feedback.

nixCrat Tux Pixel Penguin
Hi! 🤠
I'm Vivek Gite, and I write about Linux, macOS, Unix, IT, programming, infosec, and open source. Subscribe to my RSS feed or email newsletter for updates.

16 comments… add one
  • Dof Feb 5, 2017 @ 16:47

    just a little error :
    /sbin/iptables -t nat -A PREROUTING -i eth0 -p tcp -d {PUBLIC_IP} --dport 443 -j DNAT --to {INTERNAL_IP}:443

    • 🛡️ Vivek Gite (Author and Admin) Vivek Gite Feb 5, 2017 @ 19:26

      Thanks for the heads up!

    • Dave Feb 8, 2021 @ 5:44

      Hi Vivek / Dof
      I tried this line and made sure it is correctly typed but I get the following message.
      multiple -d flags not allowed
      Any suggestions?
      Thank you for the great information in the article :-)

      • 🛡️ Vivek Gite (Author and Admin) Vivek Gite Feb 8, 2021 @ 9:18

        No, the correct syntax is:

        -d ip1,ip2
        -d ip/subnet,ip2,cidr4 
  • Harold Angulo Mar 16, 2017 @ 19:16

    How Can I do this using domains and subdomains instead public IP address?

    • 🛡️ Vivek Gite (Author and Admin) Vivek Gite Apr 16, 2017 @ 16:52

      You can’t. You need to use reverse proxy such as Nginx. It is much better.

  • Zinc Jan 24, 2021 @ 0:14

    Been trying to do this across NIC cards– from a 170.*.*.* network to a 192.168.1.* private network. Seems like requests get forwarded to the 170 network instead of the 192 network which isn’t accessible to the outside– can’t it be made to route *through* the server to the other network?

    • Bartek Feb 1, 2021 @ 9:37

      Hi Zinc,
      If you forward traffic from a 170.*.*.* network to a 192.168.1.*, please be sure that hosts on your 192.168.1.* network have Gateway set to
      In this example, is your router which you set NAT.
      When you sent traffic to your 192.168.1.* network, the traffic must be sent back the same way through your NAT router.

  • Ban Soo Jun 6, 2021 @ 19:18

    A kind and noble person, whoever you are, I thank you from the bottom of my heart for helping with ufw and port forwarding. Unfortunately, I lost days, and only your instructions worked on Debian 10 server. Please add a donation button so that we can support your hard work.

  • Artista Apr 14, 2022 @ 22:54

    I need to implement a NAT between two private networks (of different customers), one is on and the otrer one is on
    I have a debian machine with 2 interfaces; enu33 and enu36
    The target system is on
    I have the rules:

    -A PREROUTING -i ens33 -d -p tcp --dport 80 -j DNAT --to-destination
    -A POSTROUTING -s -o ens33 -j MASQUERADE

    But cant make it work. Please any suggestion to debug.

  • ravi kumar Jun 4, 2022 @ 7:09

    Vivek Gite,
    I have some problem and I want to redirect any port number on a specific IP_Address. please help me.
    ex- ip_add or
    Like this please help.

  • VeeDub Sep 12, 2022 @ 23:58

    Hello Vivek,
    I came across your post on how to forward ports to an internal server, as I am trying to forward a port to an LXC container.

    My scenario is different to your scenario. I have the LXC host on a private IP address and I have the LXC container on the same subnet with IP which is accessible via the bridge on

    I want to forward SSH to the container host, however as SSH is also being used on the container host. I want to forward the following port to

    So, I have made the following changes:

    /sbin/iptables -t nat -A PREROUTING -i eth0 -p tcp -d --dport 2222 -j DNAT --to

    I have not entered the masquerade rule, as in my case the container host and the container are on the same subnet. So, I don’t believe the masquerade rule is needed in this case.

    I’ve then added the following entries to /etc/ufw/before.rules

    # forward  port 2222 to
    -A PREROUTING -i eth0 -d -p tcp --dport 2222 -j DNAT --to-destination

    When I perform:

    sudo systemctl restart ufw

    I lose Internet access on the container host. I’ve checked that the default route is still in place, but I can no longer access the Internet.

    If I remove the above changes to ufw, then Internet access is restored.

    So, I’m doing something wrong here. Hopefully, you can see what the problem is.

    Thank you

    • 🛡️ Vivek Gite (Author and Admin) Vivek Gite Sep 13, 2022 @ 4:42

      Your case is different. What you need is DNAT inside your container itself. For example, log into the lxd with IP

      lxc exec {container-name-here} bash

      Then type as root on

      iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination
      iptables -t nat -A POSTROUTING -j MASQUERADE

      Then from host do it:

      ssh -p 2222

      This will redirect to Of course, you need to save those rules on HTH

      • VeeDub Sep 13, 2022 @ 6:25

        Hello Vivek,

        Thanks for responding.

        I tried adding the iptables commands on and I’m still not able to ssh to

        In other words ssh still times out.

        I’ve added port 2222 to ufw on

        From your instructions, I think you might think that is also a container, it is not. It is the lxd/lxc host.

        I have configured the lxc bridge to be on the same subnet as the host. From some discussions that I have had on other forums, prior to discovering your post, having the lxc bridge subnet on the same subnet as the host has been implemented by other posters. That being said, I just want to get this working, so I’m happy to reconfigure the bridge subnet if you believe that is necessary.

        However, I have been able to ping from external hosts without the need for any forwarding rules, other than allowing icmp through ufw on

        And as ping works, I was surprised that other ports didn’t just “work” once the routing was configured.

        • 🛡️ Vivek Gite (Author and Admin) Vivek Gite Sep 13, 2022 @ 17:53

          Indeed, I misunderstood your post. Sorry about that. You need a way to proxy connections between the host and containers. Right? In that case, there is an easier way. The syntax is:

          lxc config device add {container-name} ssh-reditect proxy listen=tcp:${src_IP}:${src_port} connect=tcp:${dest_ip}:${dest_port}
          lxc config device add c1 ssh-reditect proxy listen=tcp: connect=tcp:

          Test it:

          ssh -p 2222 user@

          Read docs here: https://linuxcontainers.org/lxd/docs/master/instances/#type-proxy

          • VeeDub Sep 13, 2022 @ 23:43

            Brilliant. Thanks!

Leave a Reply

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

Use HTML <pre>...</pre> for code samples. Your comment will appear only after approval by the site admin.