I work in a public library as a system administrator. Recently my task was to put public computers behind a separate router in order to control internet access. As I have plenty of computer parts lying around I decided to build a router with some older computer with a Linux operating system. In my case Ubuntu Server 18.04.1 LTS (Bionic Beaver).
I wrote this guide to help others with a similar task.
Prerequisites
- A computer running Ubuntu Server 18.04.1 LTS. I’m not going into the details on how to install Ubuntu operating system. It is pretty straightforward. If you need help for the basic installation you can use this guide on HowtoForge.
- At least two network interfaces. One is for the WAN and the other for LAN part of a router. You would also want to use some switch in a case you are going to connect multiple devices in the local network. But this is pretty much everything you need for a working router.
If you are not that much into building a machine from your old computer parts, there are plenty of small form network appliances on the Amazon. They are like small fanless solid state computers with two or more network interfaces. I recommend this one:
Last update on 2023-09-29.
Note that this one is a BAREBONE without RAM and SSD mSata. You need to buy them separately and put in by yourself. Like:
RAM:
Last update on 2023-09-29.
…and mSATA SSD drive:
Last update on 2023-09-29.
Note: As we are going to be messing up with the firewall, I would not recommend you to configure it via SSH. You may lock yourself out during the process.
1. Network Interfaces configuration
First, we need to configure the network interfaces we will be using. In my case, eth0 will be the WAN and eth1 LAN.
WAN (eth0) – this interface will get an IP from the ISP, so we leave it using DHCP.
LAN (eth1) – we configure the interface with a static IP within the subnet we are going to use for local area network
Just a little note, Ubuntu 18.04 does not use the traditional network configuration file /etc/network/interfaces. It uses NETPLAN. In my case, there is a config file, called 50-cloud-init.yaml inside the /etc/netplan/ folder. In your case, the file may have a different name, just look for the file with .yaml extension inside netplan folder.
Let’s open it with nano:
sudo nano /etc/netplan/50-cloud-init.yaml
Edit it accordingly to your network needs, in my example I configured like this:
# This file is generated from information provided by # the datasource. Changes to it will not persist across an instance. # To disable cloud-init's network configuration capabilities, write a file # /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following: # network: {config: disabled} network: ethernets: eth0: dhcp4: true eth1: addresses: - 192.168.1.1/24 dhcp4: false nameservers: addresses: - 8.8.8.8 - 8.8.4.4 search: [] version: 2
To sum up: eth0 which is the WAN, gets IP from internet provider’s modem. Eth1 is LAN part of the router. We need it to have a static IP and DNS servers (in my example I used Google’s). Also we didn’t configure any gateway on eth1.
Save the configuration with following commands:
sudo netplan generate sudo netplan apply
2. SETTING UP A DHCP SERVER
Next, we want to set up a DHCP server. We really don’t want to configure each client with static IP within the LAN network. For this task, we need to install the following package.
sudo apt-get install isc-dhcp-server
Next we need to edit /etc/default/isc-dhcp-server file. This tells the DHCP server which network interface it should be listening to. In my case it of course eth1, the LAN interface.
We enter the command:
sudo nano /etc/default/isc-dhcp-server
And under “INTERFACESv4” insert your LAN network interface. In my case it’s eth1:
INTERFACESv4="eth1"
Next step would be configuring the DHCP server. This is done by editing the file /etc/dhcp/dhcpd.conf
sudo nano /etc/dhcp/dhcpd.conf
Here is a bunch of different parameters, most of them are commented with # before every line. To keep it shorter, I will write it down only the parameters I used and/or edit them accordingly my needs. If you want, you can delete all the content of this file and just copy/paste the code below. Of course, you change the IPs, GATEWAYS, etc.. according to your own network configuration.
option domain-name "whatever.you.want"; option domain-name-servers 8.8.8.8, 8.8.4.4; default-lease-time 600; max-lease-time 7200; ddns-update-style none; authoritative; log-facility local7; subnet 192.168.1.0 netmask 255.255.255.0 { range 192.168.1.101 192.168.1.200; option subnet-mask 255.255.255.0; option routers 192.168.1.1; option broadcast-address 192.168.1.255; }
Now let’s apply the settings and enable the DHCP server on boot with following commands:
sudo systemctl restart isc-dhcp-server sudo systemctl enable isc-dhcp-server
With the following command, we check the status.
sudo systemctl status isc-dhcp-server
If everything is correctly set up, there must be a line, saying “ACTIVE“. Otherwise, you messed something up within /etc/dhcp/dhcpd.conf file. It may be missing some semicolon or bracket.
3. CONFIGURING FIREWALL
In order to have a functional router, we need to configure the firewall properly. This is done by writing down some iptables rules. In order to preserve the rules if the server is restarted, I created a script to be executed at boot time.
First lets enable UFW with…
sudo ufw enable
Next we need to enable forwarding packages from WAN to LAN. We the following parameter inside /etc/ufw/sysctl.conf file:
We open the file…
sudo nano /etc/ufw/sysctl.conf
…and we just remove the # in front of the following line:
net/ipv4/ip_forward=1
In Ubuntu 18.04 the file /etc/rc.local doesn’t exist anymore. But we can still create it with:
sudo nano /etc/rc.local
Next, copy/paste the following script. There are comments explaining each iptables rule. You can delete them if you wish, but you must NOT delete #!/bin/bash. Also, change eth0 and eth1 if your network interfaces have some different names.
#!/bin/bash # /etc/rc.local # Default policy to drop all incoming packets. iptables -P INPUT DROP iptables -P FORWARD DROP # Accept incoming packets from localhost and the LAN interface. iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -i eth1 -j ACCEPT # Accept incoming packets from the WAN if the router initiated the connection. iptables -A INPUT -i eth0 -m conntrack \ --ctstate ESTABLISHED,RELATED -j ACCEPT # Forward LAN packets to the WAN. iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT # Forward WAN packets to the LAN if the LAN initiated the connection. iptables -A FORWARD -i eth0 -o eth1 -m conntrack \ --ctstate ESTABLISHED,RELATED -j ACCEPT # NAT traffic going out the WAN interface. iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # rc.local needs to exit with 0 exit 0
This script must be executed at boot time, so we need to make the file executable with the following command:
sudo chmod 755 /etc/rc.local
And that’s it. We reboot the router with sudo reboot command and we are good to go. 🙂
Take care. 🙂
Thank you so much for this guide! I am relatively new at linux but know enough to learn quickly. My setup is pretty much as you describe above except that rather than server out IP’s via DHCP my setup will:
1. Accept unfiltered content from my ISP via the modem
2. filer the content running:
– ufw
– fail2ban
– Pi-Hole
3. Send the resulting filtered content to a Google Wi-Fi that will take care of handing out IP addresses
Do you know if this setup is possible?
Definitely possible.
You have two options.
1. Connect WAN side of Google Wi-FI to LAN of the Ubuntu machine. You can assign a static IP or you leave it to DHCP server to assign a WAN IP of Google Wi-Fi router. In this case, you have double NAT, which is just fine in most cases. Just make sure the subnets of Ubuntu LAN (Google WiFi WAN) and Google Wi-Fi LAN are different.
2. You put a Google Wi-Fi to Bridge Mode. This way you leave routing (and of course assigning IPs to Wifi clients) only to Ubuntu router.
Hi! I’ve got Ubuntu Server on VirtualBox, with 2 network: nat, int net.
So my problem is: on the second network internet doesn’t works.
Have you tried to use the 2nd interface as “Bridged” instead of internal?
top effort this worked like a treat……. this setup rules for loads of workarounds. e.g. creating a nice isolate wired LAN you have complete control over. whilst leaving the rubbish BT homehub to deal with all the wifi junk in the house. Got this running on an old lenovo desktop box from the attic, with a used 4 port 1Gb server network card for £10 quid in about 20 mins.
Thank you very much! You saved me! A complete and easy to follow guide.
You rule 😀
You’re welcome. 🙂
Nice tuto Blaz.
It worked like a charm for me. The unique difference is that my provider uses PPPOE and i will have to config the conection.
Many thanks for your time!.
Abraham
Hi!
What (and where) should i change, if my ISP give me static ip (IP, GW, MASK, DNS)?
You need to change the settings under the “eth0” (which is the WAN port of the router). As you can see, now is: “dhcp4: true”
Change it accordingly to the given static IP, GW, MASK and DNS provided by your ISP.
So the segment of eth0 would be something like:
dhcp4: false
addresses:
- xxx.xxx.xxx.xxx/xx
gateway4: xxx.xxx.xxx.xxx
nameservers:
addresses:
- xxx.xxx.xxx.xxx
- xxx.xxx.xxx.xxx
Note that the subnet mask is presented by the prefix /xx after the IP address.
Here’s a cheat sheet: 🙂
Prefix size | Subnet mask
/24 | 255.255.255.0
/25 | 255.255.255.128
/26 | 255.255.255.192
/27 | 255.255.255.224
/28 | 255.255.255.240
/29 | 255.255.255.248
/30 | 255.255.255.252
I hope it helps. Good luck.
Thank you so much! 🙂
No worries. 🙂
How do you route ports for example 80 to a specific IP address in a LAN?
Let’s assume a desired specific address in LAN is 192.168.1.77
In the file /etc/rc.local just before the last line (exit 0) you need to add two rules:
iptables -A PREROUTING -t nat -i eth0 -p tcp –dport 80 -j DNAT –to 192.168.1.77:80
iptables -A FORWARD -p tcp -d 192.168.1.77 –dport 80 -j ACCEPT
Of course, change an IP address to your needs. Also if your WAN interface is not called eth0, change it accordingly. Reboot the router and you are good to go. 🙂
I am getting the fail error of “Not configured to listen on any interfaces!”
My /etc/default/isc-dhcp-server looks like
INTERFACESv4=”enp1s10″
INTERFACESv6=””
What is going wrong?
Actually, with your question, I realized there was a mistake. It is the “isc-dhcp-server” file to edit properly. Thanks, the mistake has been corrected. 🙂
Regarding your error, first, please double check if the LAN interface name (in your case enp1s10) is correct. As it is declared in netplan file (/etc/netplan/50-cloud-init.yaml). Also, maybe you forgot to edit this file and set the static IP for this LAN interface, like in the guide.
Also, be careful that you change the interface names to your needs. Through the whole guide, I used interface names eth0 (for the WAN) and eht1 (for the LAN). You may have different names, change it accordingly…
Thank you very much, you just saved a client around $500USD a month with IBM Cloud by spinnig up an Ubuntu box for $30USD a month
You’re welcome. 🙂
Thanks for the detail tutorial.
I already try to solve this problem with other tutorial for three days.
This really helps me a lot, and save my time. Thanks 🙂
Brilliant post. Thank you so much Blaz.