Linux as a router with iptables, bind9, and dhcpd

There are some benefits to using a Linux box as a router. You get full access to the power of iptables, can host stuff directly on the box itself rather than having forwarding ports to other machines on your network, can torrent with way more peers as the box will support more connections than a usual home router, use the router itself as a fileserver/seedbox, etc.

The network setup this entails is as follows: [Modem] – [Linux box/router] – [switch] – [other machines on your network]

For the box itself you will need two network interfaces, one for your modem and one for your switch. Throughout this tutorial, we will be referring to the one connected to your modem as eth0 and the one connected to your switch as eth1.

Additionally, the network range I will be using for your local network will be

This tutorial is intended for Debian/Ubuntu but porting it to CentOS is trivial.

Step 0 – Configure network interfaces

Debian uses /etc/network/interfaces for assigning IP addresses and so on to its network interfaces. You can use the following and tweak it to your needs.

# Loopback interface. Omitting this will cause weird problems
auto lo
iface lo inet loopback

# The interface connected to the modem. This implies you do not
# have a static IP address from your ISP. If you do, you can
# use the same notation eth1 uses below, with the addition of a 
# gateway clause
auto eth0
iface eth0 inet dhcp

# Interface bound to local network. 
auto eth1
iface eth1 inet static

Step 1 – Install packages

We will need dhcpd to provide DHCP to our local network and bind9 to provide DNS lookups

apt-get install isc-dhcp-server bind9

Step 2 – Configure dhcpd

As mentioned earlier, we’ll be using as our IP range. Additionally, we’ll use for the IP of our router on the local network.

The configuration file for dhcpd is /etc/dhcp/dhcpd.conf. You can configure it as follows for our purposes:

default-lease-time 600;
max-lease-time 7200;

subnet netmask {
        option domain-name-servers;
        option routers;


This will hand out IP addresses between and for your local network. When/if they run out, old addresses will be reused.

Step 3 – Configure bind9 to provide DNS for your network

Debian uses /etc/bind for its bind9 named configuration files. The one we care about in this case is /etc/bind/named.conf.options

At some point the file will contain the directive allow-recursion, inside the options block. The act of allowing a DNS server to provide DNS for domains other than ones it hosts is referred to as recursion, as it is recursively contacting other DNS servers to carry out the client’s request. Allow recursion for your local network as follows:

allow-recursion {; };

Step 4 – Allow packet forwarding in the kernel

Make sure the following two lines are either present or not commented in /etc/sysctl.conf


Then reload sysctl:

# sysctl -p

Step 5 – iptables packet fowarding/masquerading

We need to have iptables route packets from eth0 to eth1. For this we will use an init script. Create this file: /etc/init.d/iptables


# Provides: iptablesrules
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description:
# Description:

iptables -F
iptables -t nat -F

iptables -P INPUT ACCEPT

iptables -A FORWARD -i eth1 -s -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

The most important lines are the last two. The first is accepting all packets that forward from eth1 (the local network) and the second masquerades them out eth0 (the internet).

That big comment at the top is to avoid warnings from Debian’s new dependency boot system.

Now enable the script:

# update-rc.d iptables enable

Step 6 – Restart services (or reboot)

/etc/init.d/bind9 restart
/etc/init.d/isc-dhcp-server restart


At this point, you’re essentially done. Restart the services and your machines on your local network will start receiving IP addresses and be able to connect to the internet, faster than if you were using a normal consumer-grade router.

Read on if you’d like more functionality.

Appendix 0 – Port forwarding

As tempting as hosting all the services you want on your router may be, you will invariably want to forward ports to machines behind your router.  Simply add this line to the iptables init script we made:

iptables -t nat -I PREROUTING -p tcp --dport 2080 -i eth0 -j DNAT --to

This will forward all requests coming from eth0 (the internet) on port TCP 2080 to port 80 on machine If you need to use UDP rather than TCP, replace tcp with udp in that command.

Appendix 1 – Static IP’s on the local network

Having all of the computers on your network get a random dhcp address can be inconvenient if you want to export NFS shares to a single machine, among other reasons. DHCP can assign IP addresses based on MAC addresses. You can add lines such as the following to the dhcpd.conf file we referred to earlier:

host adore {
 hardware ethernet f4:6d:04:44:11:fc;

What you provide for the hostname can be anything you feel like making up, really. Make sure that the IP you give it does not overlap the range you are having dhcpd provide.

Appendix 2 – Well, what if I want WiFi?

A nice use for your old Linksis wifi router would be to use it as a hotspot. Simply log in to its admin interface, disable its built-in DHCP server, configure its WiFi settings as you’d prefer, and plug one of its switch ports into your switch which is connected to your Linux router. Leave the Linksys’ WAN port unplugged.

At this point it will essentially serve as a wireless “switch” of sorts. So you’ll have all the benefits of using a computer running Linux as a router, and still have WiFi for your place using the old Linksys as a hotspot.

Another way of providing WiFi connectivity is adding a wireless card to your Linux router. Unfortunately, that isn’t something I’ve felt like dealing with yet, so I’m not going to write an article on it.

One thought on “Linux as a router with iptables, bind9, and dhcpd

Leave a Reply

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

× six = twenty four