Ok, so I want to make a router using Ubuntu Server 18.04 ( already have the hardware and it all works, I have IPfire currently on it). I’ve looked at all the router distros and they seem rather limited in scope.


The article: https://arstechnica.com/gadgets/2016/04/the-ars-guide-to-building-a-linux-router-from-scratch/

The firewall guide: https://help.ubuntu.com/lts/serverguide/firewall.html

Ubuntu Server now uses netplan. I've looked at the documentation and it’s fairly clear I am not exactly skilled at this usage of the OS. I was hoping maybe someone could help me “translate” the way this article does it (the way I am more familiar) into the more modern implementation.

How would I make a netplan version of 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 WAN interface, marked Lan1 on the case
auto p4p1
iface p4p1 inet dhcp

# The LAN interface, marked Lan2 on the case
auto p1p1
iface p1p1 inet static

Also, I would prefer to use UFW over directly using iptables, as most of the rules in UFW are also what most of the article states. One key difference from the article is he has this for the NAT section.

From article


# p4p1 is WAN interface, #p1p1 is LAN interface


From firewall guide

# nat Table rules

# Forward traffic from eth1 through eth0.

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

But, after I figure out those two sections. I should be able to handle the rest. Any help would be great!

  • I solved it. With netplan, there isn't any need to set up the WAN and LAN inputs. This is pretty much taken care of during installation. The firewall rules are pretty much minimal and worked. Aug 20 '18 at 13:39
  • I had some trouble with netplan and bridged interfaces with dnsmasq -dnsmasq wouldn't come up on time. Its a known issue, and not fixed yet. I seem to recall it worked ok with 2 ports only. I'd strongly suggest dumping netplan. I went with firewalld so I'm not much help with your actual question but Nov 18 '18 at 13:47

Full Credit goes to: https://www.ascinc.com/blog/linux/how-to-build-a-simple-router-with-ubuntu-server-18-04-1-lts-bionic-beaver/

I will assume for the following that you just installed Ubuntu 18.04 and have not done anything with it yet.

0. Turn on the firewall in order to make sure the routing rules are actually applied

sudo ufw enable

1. Setup The Network Interfaces

First, we need to configure the network interfaces we will be using. WAN (enp0s7) – this interface will get an IP from the ISP, so we leave it using DHCP.

LAN (enp3s0f0) – 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}
            dhcp4: true
            dhcp4: false
                search: []
    version: 2

To sum up: enp0s7 which is the WAN, gets IP from internet provider’s modem. enp3s0f0 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 enp3s0f0.

Save the configuration with following commands:

sudo netplan generate
sudo netplan apply


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/dhcpd.conf file. This tells the DHCP server which network interface it should be listening to. In my case it of course enp3s0f0, the LAN interface.

We enter the command:

sudo nano /etc/default/isc-dhcp-server

And edit accordingly, in my case it is:


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,;
default-lease-time 600;
max-lease-time 7200;
ddns-update-style none;
log-facility local7;
subnet netmask {
     option subnet-mask;
     option routers;
     option broadcast-address;

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.


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.

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 enp0s7 and enp3s0f0 if your network interfaces have some different names.


# /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 enp3s0f0 -j ACCEPT

# Accept incoming packets from the WAN if the router initiated the
#  connection.
iptables -A INPUT -i enp0s7 -m conntrack \

# Forward LAN packets to the WAN.
iptables -A FORWARD -i enp3s0f0 -o enp0s7 -j ACCEPT

# Forward WAN packets to the LAN if the LAN initiated the connection.
iptables -A FORWARD -i enp0s7 -o enp3s0f0 -m conntrack \

# NAT traffic going out the WAN interface.
iptables -t nat -A POSTROUTING -o enp0s7 -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

The default settings on UFW firewall mess with our configuration, and in order for our router to work properly (to forward packages from WAN to LAN), you need to enable the following parameter inside /etc/ufw/sysctl.conf file. We run the command:

sudo nano /etc/ufw/sysctl.conf

Now we just remove # in front of the following line:


There we go! We have a working router, just do a sudo reboot command to reboot the server.


As per my comments - I wouldn't use netplan here. Its perfectly fine until you try bridging and I couldn't get it to work reliably. IMO its not ready. As of 18.04 switching back to the classic ifup network management is the smart thing to do.

I don't use ufw in my own build but it can't be that hard to translate them (famous last words).

firewalld uses remarkably similar commands for these and they should translate directly to UFW. The commands are literally "classic" firewall commands. They're untested on ufw, and might need some tuning from someone who uses ufw.

I don't really like how the ufw notes gives a range of IPs over an interface (though you might be forced to), but it should translate to something like this. enp1s0 is my 'external' interface, and br0 is basically all my other interfaces bridged together

For reference, my firewalld setup looks like this:

sudo firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -o  enp1s0 -j MASQUERADE
sudo firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i br0 -o  enp1s0 -j ACCEPT
sudo firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i enp1s0 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo firewall-cmd --runtime-to-permanent

The second last command is critical

And that should translate to something like this.

#masquerade traffic coming out from enp1s0 
# Forward and accept any traffic from br0 to enp1s0  
-A FORWARD 0 -i br0 -o  enp1s0 -j ACCEPT
#accept traffic on existing connections
-A FORWARD 0 -i enp1s0 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT

The default netplan configuration, as I recall gives all the outputs automatic IP addresses.

This is going to be a problem eventually when you run a DHCP server. You want a static IP address on that interface.

If you must, a minimal netplan config looks like this - I think it worked before I tried to bridge things.

  • enp1s0 is my external interface
  • enp1s0 is internal.

I'm not entirely sure why enp2s0 has dhcp enabled - you might be able to remove that stanza. Optional is useful since you might not always have something plugged into the port

            addresses: []
            dhcp4: true
            dhcp4: true
            optional: true
    version: 2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.