Skip to content

Instantly share code, notes, and snippets.

@kimus
Created March 2, 2014 22:46
Star You must be signed in to star a gist
Save kimus/9315140 to your computer and use it in GitHub Desktop.
NAT and FORWARD with Ubuntu’s ufw firewall

UFW

I use Ubuntu’s Uncomplicated firewall because it is available on Ubuntu and it's very simple.

Install UFW

if ufw is not installed by default be sure to install it first.

$ sudo apt-get install ufw

NAT

If you needed ufw to NAT the connections from the external interface to the internal the solution is pretty straight forward. In the file /etc/default/ufw change the parameter DEFAULT_FORWARD_POLICY

DEFAULT_FORWARD_POLICY="ACCEPT"

Also configure /etc/ufw/sysctl.conf to allow ipv4 forwarding (the parameters is commented out by default). Uncomment for ipv6 if you want.

net.ipv4.ip_forward=1
#net/ipv6/conf/default/forwarding=1
#net/ipv6/conf/all/forwarding=1

The final step is to add NAT to ufw’s configuration. Add the following to /etc/ufw/before.rules just before the filter rules.

# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]

# Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# don't delete the 'COMMIT' line or these nat table rules won't
# be processed
COMMIT

Now enable the changes by restarting ufw.

$ sudo ufw disable && sudo ufw enable

FORWARD

For port forwardind just do something like this.

# NAT table rules
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Port Forwardings
-A PREROUTING -i eth0 -p tcp --dport 22 -j DNAT --to-destination 192.168.1.10

# Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# don't delete the 'COMMIT' line or these nat table rules won't
# be processed
COMMIT
@daBONDi
Copy link

daBONDi commented Jan 19, 2017

mhh for me its not working :-(

Tripple Check the files

i'm using Vagrant box ubuntu/xenial64 with a private and public network :-(

its like its not doing nat?
internet <-> router <-> Network Public <-> vagrant private
i can ping all ips in Network Public, but not in the internet or other subnets on the router

so i got double NAT should be normaly no problem :-(

@joebitcoinorg
Copy link

Please correct both lines that list
*nat
as
#Nat

It's meant to be a comment line, but it causes UFW to fail at startup.

@irgendwr
Copy link

irgendwr commented Jul 9, 2017

@joebitcoinorg nope, this selects the table and is not meant to be a comment
(I know the post I'm referring to is a few months old, just wanted to clarify in case someone reads this)

@bluebaroncanada
Copy link

Is there a way to do this without changing the default policy?

@drst0ck
Copy link

drst0ck commented Dec 22, 2017

You are my hero!

@bsimpson53
Copy link

bsimpson53 commented Sep 18, 2018

In case anyone else stumbles here (who doesn't deal with iptables much)...

Please correct both lines that list
*nat
as
#Nat

It's meant to be a comment line, but it causes UFW to fail at startup.

@joebitcoinorg nope, this selects the table and is not meant to be a comment
(I know the post I'm referring to is a few months old, just wanted to clarify in case someone reads this)

What's actually going wrong is documented in this bug report:

https://bugs.launchpad.net/ubuntu/+source/ufw/+bug/550976

There's a missing 'COMMIT' for the filter table in the base ufw config...

Which means you've added your *nat section after the start of the *filters section and you should move it to before the line *filter

@octrar
Copy link

octrar commented Feb 17, 2019

Its still working on my slow machine, thanks bro :)

@b23prodtm
Copy link

b23prodtm commented May 14, 2019

How to make iP v6 addresses allow
-A ufw-before-forward -i eth0 -o virbr0 -d 2001:db8:1::0/64 -j ACCEPT
I ve got mask error with thi above rule

@drewwells
Copy link

You should get this document updated. https://help.ubuntu.com/community/Router#Enable_IP_forwarding_and_Masquerading
While the proposed solution does indeed work, they don't provide sufficient instructions for enabling the custom nat.sh script on boot. ufw solution may also survive time better than this script will.

@halixness
Copy link

How to make iP v6 addresses allow
-A ufw-before-forward -i eth0 -o virbr0 -d 2001:db8.:1::0/64 -j ACCEPT
I ve got mask error with thi above rule

Still having issues. No errors while enabling ufw, but still my VM (connected via natting) can't get an ip address from the main host.
Disabling ufw makes everything work....

@eapereira
Copy link

Why not to make ufw do that on command line? Like:
ufw forward 25 to 10025

@pierre-auguste
Copy link

Hello,
I did not understood that a "COMMIT" must be added at the end of each sections. (I thought only one at the end the file was enough but that's wrong)
So you have to copy all the *nat rules with the "COMMIT" and paste it just before the *filters rules. And that's it !

@waznico
Copy link

waznico commented Jan 15, 2020

The chain POSTROUTING doesn't appear in my iptables --list
My before.rules looks like

#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
#   ufw-before-input
#   ufw-before-output
#   ufw-before-forward
#

# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]

# Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -s 10.66.66.0/24 -o ens0 -j MASQUERADE

# don't delete the 'COMMIT' line or these nat table rules won't
# be processed
COMMIT

# Don't delete these required lines, otherwise there will be errors
*filter

[...(Lot's of default config)...]


# allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above
# is uncommented)
-A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT

# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT

Does someone has an idea?

Edit: My fault. It was correctly configured but my interface wasn't correct. It's also necessary to use the following command:
iptables -t nat -L -v

@digitalsigi
Copy link

Thank you so much, you made my day.
After searching trying for a couple of days I came across this post.
Works like a charm.

@soletan
Copy link

soletan commented Dec 23, 2020

FWIW there are some additional information included with man ufw-framework covering IP masquerading and port redirections. In the latter case it states to have the patch in file /etc/ufw/before.rules regarding *nat table as well as adding route for allowing that NAT traffic.

@bodz1lla
Copy link

Quick and fast ufw manual, many thanks!

@radshop
Copy link

radshop commented May 2, 2021

Dude! There's never been a man so happy to get a Hello World. I've been trying to solve this with ufw allow route rules, but this is the ticket.

@SomwareHR
Copy link

Thank you! This save me quite a time :D
Just to add one tipical line from UFW log:

MMM DD HH:MM:SS $HOSTNAME kernel: [ $timestamp] [UFW BLOCK] IN=ethWAN OUT= MAC=01:02:03:04:05:06:07:08:09:01:02:03:04:05 SRC=$LANclient DST=$somethingsomething LEN=71 TOS=0x00 PREC=0x00 TTL=128 ID=40423 DF PROTO=TCP SPT=54306 DPT=3128 WINDOW=1021 RES=

BTW, ICMP was working fine during this blockage.

@Sturmkater
Copy link

Sturmkater commented Jul 18, 2021

Hi guys, somehow when I ping it says it's not reachable. What I try to accomplish: traffic coming in from ppp0 on UDP port 53 should be sent over ens3 to ip 192.168.1.2

are my settings correct for that?

# NAT table rules
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Port Forwardings
-A PREROUTING -i ppp0 -p udp --dport 53 -j DNAT --to-destination 192.168.1.2

# Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -s 192.168.1.2 -o ens3 -j MASQUERADE

# don't delete the 'COMMIT' line or these nat table rules won't
# be processed
COMMIT

@duffyduck00
Copy link

duffyduck00 commented Dec 3, 2021

almost everything is working fine - i am using a vpn connection .. i just changed the line
-A POSTROUTING -s 192.168.137.0/24 -o eth0 -j MASQUERADE to -A POSTROUTING -s 192.168.137.0/24 -o tun0 -j MASQUERADE
so if the vpn connection is lost, no traffic will reach internet ... thats how i would like it.

the only thing what is not working till now, is dns through 192.168.137.1 (which is the ip address to the local network). i have to enter dns address 1.1.1.1 at all my clients - but i want to use dns address 192.168.137.1 at all my clients.
i tried portforwarding for port 53

-A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to-destination 192.168.137.1

... but it doesnt work.

any ideas how to make this work ?

@duffyduck00
Copy link

duffyduck00 commented Jan 24, 2022

everything is workine fine now ... after i installed dhcp server on my router pc

@h6w
Copy link

h6w commented Jan 25, 2022

Instead of forwarding ports in before.rules, UFW now supports forwarding itself.

e.g. the command above

-A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to-destination 192.168.137.1

can instead be done along with other ufw commands on the command line

ufw route add in on eth0 to 192.168.137.1 port 53 proto udp

Or even, add an application file in /etc/ufw/applications.d/dns which contains:

[DNS]
title=DNS Server
description=Standard DNS Server
ports=53/udp

and then go:

ufw route add in on eth0 to 192.168.137.1 app DNS

The real advantage to this is that ufw status will show you (almost) everything that's going on, and not hide things away in before.rules!

Status: active

To                         Action      From
--                         ------      ----
192.168.137.1             ALLOW FWD   DNS on eth0

@nettoinfo
Copy link

nettoinfo commented Nov 11, 2022

Portuguese:
Pessoal, muito bom esse tutorial, parabéns!
Eu quero redirecionar a porta 443 para 8443, porque o Tomcat não trabalha com portas menores que 1024....
No FirewallD seria assim: /sbin/iptables -A PREROUTING -t nat -i ens160 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8443
No UFW, como eu faria isso?

English (I'm sorry! - Thank you, Google Translator)
Guys, this tutorial is very good, congratulations!
I want to redirect port 443 to 8443, because Tomcat doesn't work with ports smaller than 1024....
In FirewallD it would look like this: /sbin/iptables -A PREROUTING -t nat -i ens160 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8443
No UFW, how would I do that?

-------------------------------------------------- How resolve
Edit /etc/ufw/before.rules and add this:

*nat
:PREROUTING ACCEPT [0:0]
-A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
-A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
COMMIT

@aceqbaceq
Copy link

hello, thanks for the vauable info.
however i want to underline that if you enable NAT as desribed above you get a problem. when you restart uwf via

systemctl restart ufw

or

ufw reload

you notice that your iptables nat rules start to clone like that

iptables-save

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [66:3560]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
**-A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE**
COMMIT

ufw reload

iptables-save

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [66:3560]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
**-A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE
-A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE**

COMMIT

etc.

i have found the reason of such behavior = https://bugs.launchpad.net/ufw/+bug/364558
so i ve taken the solution

# cat /etc/default/ufw | grep MANAG
MANAGE_BUILTINS=yes

Hope it helps !

@yoyosbg
Copy link

yoyosbg commented Apr 13, 2023

Not straight forward at all!
I expect use simple "ufw deny 3306" for NAT, after some configuration.

@ktechmidas
Copy link

@yoyosbg some ancient code of mine still works I think :)

https://github.com/Monotoko/iptables-nat-helper

@yoyosbg
Copy link

yoyosbg commented May 5, 2023

@yoyosbg some ancient code of mine still works I think :)

https://github.com/Monotoko/iptables-nat-helper

thanks

@friki67
Copy link

friki67 commented May 22, 2023

Hello! I'm trying to set up a VPN gateway (using LXD containers). I'm using ufw for killswitch service. Almost all is working except for port forwarding.


             ┌─────────────────────────┐                  ┌──────────────────────────┐
             │   SECOND CONTAINER      │                  │   OVPN CLIENT CONTAINER  │
             │                         │                  │                          │                ┌─────────────┐
             │     192.168.1.3         │       LAN        │       192.168.1.2        │    VPN TUNNEL  │             │
             │  gw:192.168.1.2     eth0├──────────────────┤eth0                 tun0 ├────────────────┤  VPN NODE   │
             │                         │                  │                          │                │             │
             │ HTTP test server in     │                  │                          │                └──┬──────────┘
             │        8107 port        │                  │                          │                   │
             └─────────────────────────┘                  └──────────────────────────┘                   │
                                                                                                      xxxxxxxxxxxx
                                                                                                   xxxx          xxx
                                                                                                xxx                x
                                                                                                 xx    INTERNET    x
                                                                                                   xxx           xxx
                                                                                                     xxxx    xxxx
                                                                                                        xxxxx

In my VPN gateway I have:

ufw rules

192.168.1.0/24                ALLOW       Anywhere

192.168.1.0/24                ALLOW OUT   Anywhere
Anywhere                      ALLOW OUT   Anywhere on tun0
<myvpnremoteip> 1194/tcp      ALLOW OUT   Anywhere #vpn remote address

before.rules extract:

*nat
:POSTROUTING ACCEPT [0:0]
:PREROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -p tcp --dport 8701 -j  DNAT --to-destination 192.168.1.3
-A POSTROUTING -s 192.168.1.0/24 -o tun0 -j MASQUERADE
COMMIT

I can access http://192.168.1.3:8701 directly, but I cannot access http://192.168.1.2:8107

So, what am I doing wrong?

@meirg
Copy link

meirg commented Oct 19, 2023

@bluebaroncanada

Is there a way to do this without changing the default policy?

Yes, this is certainly preferable. You can add this at the end of the filter rules in /etc/ufw/before.rules (before the COMMIT)
-A ufw-before-forward -i eth0 -p tcp --dport 22 -j ACCEPT

@phlplowe9
Copy link

Nice simple guide but I spent days struggling to make it work.

The problem is ufw will append all of the rules to the iptables chains every time ufw is reloaded or started/stopped. So you end up with lots of copies of the same thing. Or in my case lots of permutations of slightly different things to test, none of which were applying since they were further down.

you should have a -F before the first -A to flush all of the old rules out first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment