NAT 2/3 – Build a linux router with iptables

In this article we'll see how to set up a linux router. This type of router can be used either at home or in data center when you are doing virtualization (for example, on a proxmox directly to give internet access to VMs when you have only one WAN IP)

All examples will use debian 8 (pre-release 3.16.0-4-amd64) and iptables 1.4.21. It is therefore possible that some things will vary over time.


A debian 8 server (physical or virtual with 2 network interfaces)

Network configuration used for this article:

Ip wan:
Local Network
wan interface: eth0
lan interface: eth1

What does it take to make a good router?

– Set up network interfaces
– Set up a DNS cache server (optional)
– Set up a DHCP server (optional)
– Natter the connection (creating a script – starting with the network)
– Activate router mode on kernel
– Open a port (optional)


Set up network interfaces

In our example, we will use an internet connection with fixed ip.
To start, open the file /etc/network/interfaces with your favorite editor (vim, nano, …)

WAN #Interface
auto eth0 #Démarre the network interface at the start
iface eth0 inet static #Configuration interface in fixed ip mode
        address #Adresse ip of the router
        netmask #masque of subnet 
        gateway #Paserelle
        dns-nameservers #serveur dns

#Interface lan
car eth1
iface eth1 inet static

By default, only eth0 is declared and configured in "dhcp" mode. It is therefore necessary to replace existing lines with them.
Eth0 being my ip wan, this configuration comes directly from my F.A.I. , in your case, you have to adapt it to it directly.
Finally, we must not forget to restart the network service to apply it.

systemctl restart networking

Normally, if all goes well, you must have internet access from the router. You can test this via a ping for example.

In addition, you can also test that the other interface works well by setting up your computer in the same network with for example the next configuration.
Address: Router: Dns:
You should be able to pingate, but it is not possible to go out on the internet at the moment.


Set up a DNS cache server

The dns cache server allows you to cache on DNS resolutions. This avoids contacting your F.A.I. every time you visit a domain name. In our example, we will use bind9.

To install it use the following command.

apt-get install bind9

Now that bind is installed, you'll need to set up 2 things for it to act like a DNS cache server.

To start, open the configuration file /etc/bind/named.conf.options

1 – Added servers dns on which bind will transfer its queries (those of your F.A.I. / for example).

To do this, uncheck the "forwarders" lines and add your ip's as in the example below.


NB: This configuration should be inside the options tag. (This is the case with the commented example in the file)

2 – Allow customers (computers from the local network) to communicate with the DNS.

Note: It is important not to allow everyone because your server could be used to carry out certain attacks.

Outside of the options tag. we will create an "ACL" representing the machines authorized to use the DNS relay.

acl "localnetwork";;

Once this is done, we will allow this "acl" to use our server. Place this configuration in the options tag this time.

allow-query - localnetwork;

Once completed, your configuration file should look like this:

acl "localnetwork";;

        directory "/var/cache/bind";

        If there is a firewall between you and nameservers you want
        to talk to, you may need to fix the firewall to allow multiple
        ports to talk.  See

        If your ISP provided one or more IP addresses for stable
        nameservers, you probably want to use them as forwarders.
        Uncomment the following block, and insert the addresses replacing
        the all-0's placeholder.


        allow-query - localnetwork;
        If BIND logs error messages about the root key being expired,
        You will need to update your keys.  See
        dnssec-validation auto;

        auth-nxdomain no;    Conform to RFC1035
        listen-on-v6 - any;

You can now restart bind

systemctl restart bind9

Tip: you can check that bind9 works well via the following command:

systemctl status bind9


Setting up a DHCP server

In this example, we will use "isc-dhcp-server" (there are other servers such as dnsmasq)

apt-get install isc-dhcp-server

To begin with, we'll create an empty configuration file rather than using the original.

cd /etc/dhcp 
mv dhcpd.conf dhcpd.conf.original
touch dhcpd.conf

Finally, the freshly created dhcpd.conf file is edited to add the following configuration:

domain-name-servers; #Configuration of the DNS server is your debian router's LAN ip.
subnet netmask - #Configuration of the local network. in our case
  default-lease-time 86400; #Temps second after which the dhcp server lets go of the ip if it is no longer present on the network
  range; #Range address that the dhcp can allocate to the customer (included in
  routers option;#Adresse ip of the router. Same as the dns server in our case.

Note that it is possible to use the DHCP to attach ips to customers. This is very convenient when your machine travels in multiple networks.

To do this, add to the rest of your setup

host pc-portable - #Nom of the host
  hardware ethernet aa:bb:cc:dd:ee:ff; #Mac address of the host
  fixed-address; #Ip (included in your network) that you want to give to your ip.

Nb: you can give fixed ips outside the "range" option but this must be included in the sub-network. (in our case

Finally, you have to say which interfaces our DHCP server will listen to. To do this edit the file /etc/default/isc-dhcp-server

Spot the INTERFACES line" and add your LAN network interface. Which gives this:


Finally, more than just restarting your dhcp service via

systemctl restart isc-dhcp-server

To test your DHCP server, connect a computer to the eth1 interface in automatic mode and you should get an ip address automatically. (That's the goal :))

Natter the connection

To do the mattage via iptables, we will create a bash script that will start at the start of the WAN interface (eth0). There is also the iptables-save package on debian that allows you to save automatically. Personally, I will use a homemade script because it is clearer and above all easy to comment on.

Below, the script used. In my example, it will be saved in /root/


WANIF eth0

firewall_start() - #Exécuter at the start
        #Ces rules apply to incoming packages

        #Tout what comes out can go back again 
        $IPT -A INPUT -i $WANIF -m state --state ESTABLISHED,RELATED -j ACCEPT 
		#On opens port 22 from the WAN on our rokiller to allow its remote management. 
		#Cette step is not mandatory and depends on your configuration
        $IPT -A INPUT -i $WANIF -p tcp --dport 22 -j ACCEPT 
		#On allows PING on the WAN interface (optional)
        $IPT -A INPUT -i $WANIF -p icmp -j ACCEPT
		#On lets everything that goes into the lan interface to allow our users to use DHCP and DNS
        $IPT -A INPUT -i $LANIF -j ACCEPT
		#Tout what does not MATCH with the previous rules - ON throws!
        $IPT -P INPUT DROP

		NAT' 'NAT'
        #Ces rules rewrite NAT addresses
		#Tout what has finished crossing the router (postrouting) and coming out by the WAN will be NATté

        #Ces rules apply to packages crossing the router
		#Tout what comes from the WAN and comes out through the LAN and which corresponds to a response is allowed to pass.
        $IPT -A FORWARD -i $WANIF -m state --state ESTABLISHED,RELATED -j ACCEPT
		#Tout what starts from the LAN is to allow it to cross the router.
		#Tout what does not MATCH with the previous rules - ON throws!



firewall_stop() - #exécuté during the stop
		#Clear different tables and reset the configuration.
        $IPT -F
        $IPT -t nat -F

firewall_restart() - #exécuté at the restart
        sleep 2

box $1 in 'start')
echo "use: -bash 'start'stop-restart'

Don't forget to give the running rights to your script.

chmod ugox/root/

Finally, we will launch this one at the same time as our network interface. For this, have returned to /etc/network/interfaces and add the following lines below the WAN interface (eth0)

        post-up /root/ start
        pre-down /root/ stop

In the end, your file should look like this:

This file describes the network interfaces available on your system
and how to activate them. For more information, see interfaces(5).

The loopback network interface
auto lo
iface lo inet loopback

The primary network interface
car eth0
iface eth0 inet static
        post-up /root/ start
        pre-down /root/ stop

car eth1
iface eth1 inet static


Turn on router mode on the kernel

To activate the router mode permanently, simply edit the file /etc/sysctl.conf

Then, comment on the next line


At this point, the configuration will be applied automatically to re-start. However, the configuration is not active at the moment.
You can activate this directly with the next command or by restarting your debian machine.

 echo "1" /proc/sys/net/ipv4/ip_forward
 /root/ start

Note: at this point, you should be able to surf the net through your new router!

Open a port

To open a port, we'll need to add a new NAT rule to our file /root/

These rules are to be added as a result of our NAT section in the file

        port #Routage 3389
        #On allows packages to cross to our local pc only for service.
        #Cette rule is actually a RULE of FORWARD but I put it right next to that of NAT to facilitate understanding.
        $IPT -A FORWARD -i $WANIF -p tcp --dport 3389 -d -j ACCEPT 

        #Tout who enters the WAN (input therefore) and enters the TCP:3389 will be redirected to 
        $IPT -A PREROUTING -t nat -j DNAT -i $WANIF -p tcp --dport 3389 --to-destination 

Nb: the service is only accessible from the outside (This rule does not manage the loopback nat that will be the subject of another article)

Here, you now have a functional router under debian!

The NAT 1/3 – Theory

The Internet isn't working! What for? (diagnose configuration)


If you want to restart your iptable script after change, you can use the following command

/root/ restart



Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.