This guide will cover how to set up a standard Ubuntu pc as a drop in replacement for a normal consumer router, but far more powerful and with considerably more functionality. It will also touch on some QOS filtering to help improve latency and network speed. If you get into any difficulties, rescue and recovery commands that can help are listed at the end. Also listed are instructions on how to completely revert all changes made in this tutorial.
I'm writing this howto because I wanted to set my Ubuntu server up as a router, and due to the lack of other up-to-date and easy to follow howtos on the subject I had to figure it all out myself. I wanted to document what I'd learned so I could save other people a whole lot of time and effort.
I'm assuming that if you are reading this you do have a basic working knowledge of what an internet gateway/router actually DOES, what NAT is and the basics of ip networking. If not, I suggest you read and digest the following links, then come back :
You will need a terminal up on the machine you are setting this up on. I do not recommend doing this over ssh unless you also have physical access to the pc, it is far too easy to get a firewall rule wrong and lock yourself out of the system.
Basic setup (the bare minimum required to get a functioning and secure NAT router)
Ok, to do this you need a spare pc with Ubuntu on it and two network cards. It doesn't need very impressive specs at all. I run my gateway on a P3 600mhz with 512mb of ram but I think you could easily do it on anything better than a 200mhz P2 and 128mb of ram. Any edition of Ubuntu will work, desktop or server edition. The only real difference is that server edition has no gui. This isn't a problem, we will only be using the command line anyway.
This guide uses webmin as a web interface to configure the necessary iptables rules and servers. I like using webmin instead of scripts because webmin is nicer to look at and easier to comprehend than a script with the same functionality, which results in less confusion, less bugs and a better understanding of what you are actually doing. Open a terminal and run the commands below to install all necessary software:
You can find the latest version of webmin here as a debian package:
sudo aptitude install bind9 dhcp3-server perl libnet-ssleay-perl openssl libauthen-pam-perl libpam-runtime libio-pty-perl libmd5-perl
The latest version at the time of writing this guide is 1.430, to install this version execute the following command:
IMPORTANT NOTE: It is an EXTREMELY bad idea to leave webmin open to the outside world. Only your user password stands between a remote hacker and complete control of your pc. This is very insecure, DO NOT DO IT. If you really need to access webmin remotely, I assume you know what you are doing, and know how to use ssh tunnelling .
cd ~ && wget http://prdownloads.sourceforge.net/webadmin/webmin_1.430_all.deb && sudo dpkg -i webmin_1.430_all.deb
You can now access webmin from the local pc by going to https://localhost:10000. If you are using firefox you will need to add a security exception. This isn't at all insecure, it is just because you are using a self signed certicate. Once you have logged in you should see a splash screen like this:
SCREENSHOT: Webmin splash screen
All configuration pages are accessed through the main menu on the left.
For security reasons, the first thing you should do after you have logged in with your username and password is to disable all remote access to webmin. Click "Webmin" in the control panel on the left and go to "Webmin Configuration". Now click ip access control. Change the radio button to say "Only allow from listed addresses" and add the value "127.0.0.1" (without inverted commas) to the text box. Click save.
SCREENSHOT: Ip access restriction screen
Webmin is now set up and ready to use!
Configuring the network cards
Seeing as you want to use this computer as a router, you should already have two network cards. You need to find out what their names are and decide which one should be internet facing and which one should be connected to the local network. To find out what network cards you have in your system, run the command:
You might see quite a few interfaces here depending on your system, the only ones you need to worry about are the ethernet interfaces (the ones called something like ethXX). They will usually be labelled eth0 and eth1 but might be any numbers, so I will from now on refer to them as eth_BAD and eth_SAFE. eth_BAD is the internet facing adapter, eth_SAFE is the local network adapter. It is a good idea to write down which one is which because you will be referring to it often.
We will set up routing first using the very powerful and flexible linux firewall, iptables.
It is important to note that if you make a mistake here you could completely disable all networking, which would cut off your access to the internet and also stop you from accessing webmin to fix the problem. If you run into difficulties, there are some commands at the end of this guide which you can use to fix the problem.
Ok, now we need to enable packet forwarding, otherwise NAT will not work. You can do this by editing the following file:
Hit ctrl+w to search, type net.ipv4.ip_forward then press enter. Make sure the line says net.ipv4.ip_forward = 1 and is uncommented. It should now look like this:
sudo cp /etc/sysctl.conf /etc/sysctl.conf.bak && sudo nano /etc/sysctl.conf
Press ctrl+o to save and ctrl+x to exit. Now reboot to turn on packet forwarding.
# Uncomment the next line to enable packet forwarding for IPv4
At this stage, your new server/gateway should be getting it's internet access through eth_BAD. If your internet doesn't work through eth_BAD, go make it work, then come back again when you have .
Now go back to the webmin page and click "Networking" then "Network Configuration" on the left. Go to "Network Interfaces". We now need to set a static ip address for our local network on eth_SAFE.
I will use 192.168.0.0/24 for the purposes of this guide. This is the standard ip range to use for local home networks. Go to the "Interfaces Activated at Boot Time" tab and click eth_SAFE to configure it if it is there already. If it isn't there already (it probably isn't) then click "Add a new interface". Enter the following details:
"Name" - Enter the device name, probably eth0, eth1 or similar.
"IP Address" - Make sure the "Static" radio button is checked, and enter 192.168.0.1 into the text box.
"Netmask" - Should be 255.255.255.0
"Broadcast" - 192.168.0.255
"Activate at boot?" - Set to yes
SCREENSHOT: Configuring eth_SAFE
Then click "Create". Check the radio button next to the new interface you created and click "Apply" to activate those settings. Great! The two network interfaces are now totally configured.
Setting up the local network
Giving eth_SAFE a static ip address is only part of what we need to do to set up a local network on that socket. We also need to provide a caching DNS server and a DHCP server to tell clients necessary information about the local network and how to resolve domain names.
We will set up DHCP first. Go to the "Servers" tab on the left in webmin, and click "DHCP Server". In the subnets section at the top, click "Add a new subnet". Enter details as follows:
"Subnet description" - A name for your subnet, I used "Local network on eth_SAFE"
"Network address" - 192.168.0.0
"Netmask" - 255.255.255.0
"Address ranges" - this can be anything you like, 192.168.0.100 - 192.168.200 should cover it.
SCREENSHOT: Configuring DHCP subnet
Leave all the other options alone and click "Create". Now a new icon should have appeared called 192.168.0.0. Click this icon, you will be returned to a screen similar to the one you just left except it has some new buttons at the bottom. Click the one that says "Edit Client Options".
"Subnet mask" - 255.255.255.0
"Default routers" - 192.168.0.1
"Broadcast address" - 192.168.0.255
"DNS servers" - 192.168.0.1
SCREENSHOT: Configuring DHCP client options
Click "Save" and then "Save" again. One last thing to do on this page - scroll down and click "Edit Network Interface". Select eth_SAFE from the list and click "Save".
SCREENSHOT: Configuring DHCP interfaces
The DHCP server is now set up. Click the "Start Server" button at the bottom of the page, the server should start with no errors. If it gives errors, you've done something wrong .
Ok, all done! On to...
Configuring the DNS server
The DNS server works out of the box, it doesn't actually NEED any additional configuration.
Configuring the firewall (or "Why I stopped worrying and learned to love IPtables")
Setting up ip masquerading (routing)
Now we get to the "fun" part where we dive into iptables. From now on you can completely screw up your networking if you aren't careful, so make sure you know how to recover if it all goes horrible wrong.
On the left hand side, click "Linux Firewall". Check the radio button for "Do network address translation" and select eth_BAD as the interface to do it on. Check the box "Enable firewall at boot time" and click "Setup Firewall". Click "Apply Configuration".
SCREENSHOT: Setting up the firewall
Setting up the firewall
At this point your server is configured as a working router/dns/dhcp server. It should work ok in this setup for everything you need it to do but it isn't properly secured. We need to define some rules that say who can make connections to our pc. We don't want just anybody from the big bad internet tapping into our home file shares for example. We do this by using iptables filtering.
The linux firewall works with three IP tables: MANGLE, PREROUTING and FILTER. The actual firewalling bit is done with FILTER, so in the "Linux Firewall" section of webmin, change the IPtable drop down box to the "Packet Filtering (filter)" IPtable.
SCREENSHOT: IPtables FILTER table
There are three "chains" listed here. Each chain defines what to do with a packet depending on where it is going. The three chains here are INPUT, FORWARD and OUTPUT. For each chain you can add rules that tell the firewall what to do for packets that meet certain defined criteria. You will probably want to blacklist all INPUT and FORWARD packets by default, then enable the ones you need. Change the default action on both INPUT and FORWARD to "Drop".
To add a rule, just click the "Add Rule" button and fill in the packet criteria and action to take as necessary.
Here is the bare minimum of rules that you NEED for your network to function properly:
Accept if protocol is ICMP (note: This allows your server to respond to pings. It isn't strictly necessary, but it doesn't really pose a security risk and makes network troubleshooting a LOT easier. If you're extremely paranoid, feel free not to bother with this option)
Accept if input interface is lo
Accept if input interface is eth_SAFE
Accept if input interface is eth_BAD and state of connection is ESTABLISHED,RELATED
Accept if input interface is eth_SAFE and output interface is eth_BAD
Accept if input interface is eth_BAD and output interface is eth_SAFE and state of connection is ESTABLISHED,RELATED
The above rules implement a very simple firewall that allows absolutely nothing in from the outside world unless it is part of an established connection. It also assumes the internal network is completely trusted and allows unfettered access to the server and outside world from the internal network. This is the default setting for pretty much every NAT device ever.
At this point you are effectively finished. You can just leave your server as a simple router with no other rules at the point. It is very secure and will work fine for most purposes. If, however, you want to run publicly accessible server, QOS filtering or if the internal network isn't completely trustworthy, you need to add some extra rules. Read on...
For reference, my INPUT and FORWARD tables look like this. I have added extra rules to mine to allow some servers to be accessable to the outside world:
SCREENSHOT: My INPUT rules
SCREENSHOT: My OUTPUT rules
Beyond the basics (more advanced tasks)
More fun with IPtables
If you are actually going to start using IPtables properly, you need to understand what it is, how it works and in what order the tables are applied. I suggest you read the wikipedia article and reference the diagram below to help give you a better understanding of the linux network stack:
It is important to note at this point that IPtables will apply your rules to each and every packet in order from top to bottom. Each rule is compared to your packet. As soon as an ACCEPT or DROP rule is found that matches your packet type, this action will be taken. If a packet gets to the end of a rule list without matching anything, the default action is taken. Here are two example scenarios:
ACCEPT if input interface is eth1
DROP if port is 22
Any incoming packets on eth1 will be allowed through, EVEN IF the port is 22.
DROP if port is 22
ACCEPT if input interface is eth1
Now incoming packets will be allowed on eth1 except if the port is 22.
Servers running on the router itself
If you want to run a server on your router (eg web server or ssh server) you need to open these ports to the outside world. This is easy to do by adding a rule to the INPUT filter explicitly allowing the incoming connection. Simply click "Add Rule" and accept packets with the packet type and destination port that are required by the server. Eg an ssh server might run on port 22 and accepts TCP packets so the rule would look like:
Accept if protocol is TCP and destination port is 22.
Giving a pc/server present in the lan a static ip address
This is necessary if you want to run a server on a pc inside the lan and need a port forwarded, for example a web server or bittorrent client.
This is quite a bit more complicated than for services running on the router itself, but still not too much of a challenge. First you have to set up the pc in the lan that runs the server (referred to from here on as the "host") with a static ip address. Because the ip addresses are allocated with DHCP, a host might be given a different ip address each time it connects to the network. You can easily give it a static ip address by telling the DHCP server to give it the same ip address each time.
Go into webmin and click the "Servers" section and select the DHCP server. In the hosts section click "Add a new host". Fill the details as shown:
"Host description" - Whatever you want, this is just to help you remember which host it is
"Host name" - Set this to the hostname of the host. This can be found by executing hostname on the host pc.
"Hardware Address" - This is the mac address of the host. This can be found be executing ifconfig on the host machine and looking at the mac address of the appropriate network card.
"Fixed IP address" - This is the ip address you want to give the host. This ip address should be in your local lan and should not be included in the group of ip addresses you already told the dhcp server to hand out dynamically. If you have been following this guide, it should be 192.168.0.X where X is a number from 2 to 99 inclusive.
"Host assigned to" - You can set this option to a subnet in order to use ip addresses within the dhcp dynamic allocation pool.
SCREENSHOT: DHCP static ip configuration
When you are finished, you can click "Save". To apply the settings, you need to delete the current DHCP lease by clicking the "List Active Leases" button at the bottom and clicking the current lease for the particular host. Then go back to the main dhcp server screen again and click "Start Server" to apply all settings. Next time the host reconnects to the network it will receive the new static ip address.
Now the host in the lan has the same ip address all the time, the router can send packets to that same ip address each time and it will reach the right host.
This part can be a bit of a pain because you actually have to do TWO things. Firstly you have to set a rule in PREROUTING to tell IPtables where to route the incoming packets, but you also need to explicitly allow these packets in FORWARD otherwise they will be blocked by the filter. This is perfectly logical but sometimes can cause major headaches if you forget to set one or the other.
In webmin, click "Networking" and then "Linux Firewall". Change the IP table in the drop down box to "Network address translation (nat)". In the PREROUTING chain at the top, click add rule. Fill in the details as listed below:
"Action to take" - Check the "Destination nat" radio button
"IPs and ports for DNAT" - Put the lan ip of the host and the port you want clients to connect to from the outside here
"Network protocol" - You have to specify udp or tcp (if you actually have need to use some other protocol this guide can't help very much )
"Destination TCP or UDP port" - The port that the server is actually listening on on the host (note: this doesn't HAVE to be the same as the port external clients connect to)
SCREENSHOT: Example: Port 2222 from outside forwaded to port 22 inside lan
Then click "Save". Now change the IP table in the drop down box to "Packet filtering (filter)". In the FORWARD chain, add a rule like this:
"Action to take" - Accept
"Network protocol" - set this to tcp or udp depending on what kind of service you are running. Some services (eg most bit torrent clients) need both tcp AND udp forwarded. In this case you may need to define two separate rules, one for tcp and one for udp.
"Destination TCP or UDP port" - set this to the incoming port used by the client when connecting from outside the lan.
SCREENSHOT: Example: Port 2222 forwarding explicitly allowed
Now you can just hit "Apply configuration" and you're done! That was easy wasn't it?
What to do if it all goes pear shaped
If you do manage to lock yourself out of webmin, don't panic. Running the following command will flush all iptables rules, which should give you webmin access back again so you can fix the problem:
Warning: The above command will totally disable the firewall - your router and possibly the lan behind it will be wide open to the whole internet.
To totally revert all changes made in this tutorial, run this command:
After a reboot, everything should be totally back to normal again.
sudo aptitude purge webmin bind9 dhcp3-server && sudo cp /etc/sysctl.conf.bak /etc/sysctl.conf
QOS with wondershaper
Setting up a static external ip/dns settings