Posted on Leave a comment

How to use Fedora Server to create a router / gateway

Building a router (or gateway) using Fedora Server is an interesting project for users wanting to learn more about Linux system administration and networking. In this article, learn how to configure a Fedora Server minimal install to act as an internet router / gateway.

This guide is based on Fedora 28 and assumes you have already installed Fedora Server (minimal install). Additionally, you require a suitable network card / modem for the incoming internet connection. In this example, the  DrayTek VigorNIC 132 NIC was used to create the router.

Why build your own router

There are many benefits for building your own router over buying a standalone box (or using the one supplied by your internet provider):

  • Easily update and run latest software versions
  • May be less prone to be part of larger hacking campaign as its not a common consumer device
  • Run your own VMs or containers on same host/router
  • Build OpenShift on top of router (future story in this series)
  • Include your own VPN, Tor, or other tunnel paths along with correct routing

The downside is related to time and knowledge.

  • You have to manage your own security
  • You need to have the knowledge to troubleshoot if an issue happens or find it through the web (no support calls)
  • Costs more in most cases than hardware provided by an internet provider

Basic network topology

The diagram below describes the basic topology used in this setup. The machine running Fedora Server has a PCI Express modem for VDSL. Alternatively, if you use a Raspberry Pi with external modem the configuration is mostly similar.


Initial Setup

First of all, install the packages needed to make the router. Bash auto-complete is included to make things easier when later configuring. Additionally, install packages to allow you to host your own VMs on the same router/hosts via KVM-QEMU.

dnf install -y bash-completion NetworkManager-ppp qemu-kvm qemu-img virt-manager libvirt libvirt-python libvirt-client virt-install virt-viewer 

Next, use nmcli to set the MTU on the WAN(PPPoE) interfaces to align with DSL/ATM MTU and create pppoe interface. This link has a great explanation on how this works. The username and password will be provided by your internet provider.

nmcli connection add type pppoe ifname enp2s0 username password XXXXXX 802-3-ethernet.mtu 1452

Now, set up the firewall with the default zone as external and remove incoming SSH access.

firewall-cmd --set-default-zone=external firewall-cmd --permanent --zone=external --remove-service=ssh

Add LAN interface(br0) along with preferred LAN IP address and then add your physical LAN interface to the bridge.

nmcli connection add ifname br0 type bridge con-name br0 bridge.stp no ipv4.addresses ipv4.method manual nmcli connection add type bridge-slave ifname enp1s0 master br0

Remember to use a subnet that does not overlap with your works VPN subnet. For example my work provides a subnet when I VPN into the office so I need to avoid using this in my home network. If you overlap addressing then the route provided by your VPN will likely have lower priority and you will not route through the VPN tunnel.

Now create a file called bridge.xml, containing a bridge definition that virsh will consume to create a bridge in QEMU.

cat > bridge.xml <<EOF <network>     <name>host-bridge</name>     <forward mode="bridge"/>     <bridge name="br0"/> </network> EOF

Start and enable your libvirt-guests service so you can add the bridge in your virtual environment for the VMs to use.

systemctl start libvirt-guests.service systemctl enable libvirt-guests.service 

Add your “host-bridge” to QEMU via virsh command and the XML file you created earlier.

virsh net-define bridge.xml

virsh net-start host-bridge virsh net-autostart host-bridge

Add br0 to internal zone and allow DNS and DHCP as we will be setting up our own services on this router.

firewall-cmd --permanent --zone=internal --add-interface=br0 firewall-cmd --permanent --zone=internal --add-service=dhcp firewall-cmd --permanent --zone=internal --add-service=dns

Since many DHCP clients including Windows and Linux don’t take into account the MTU attribute in DHCP, we will need to allow TCP based protocols to set MSS based on PMTU size.

firewall-cmd --permanent --direct --add-passthrough ipv4 -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Now we reload the firewall to take permanent changes into account.

nmcli connection reload

Install and Configure DHCP

DHCP configuration depends on your home network setup. Use your own desired domain name and and the subnet was defined during the creation of br0. Be sure to note the MAC address in the config file below can either be capture from the command below once you have DHCP services up and running or you can pull it off the label externally on the device you want to set to static addressing.

cat /var/lib/dhcpd/dhcpd.leases
dnf -y install dhcp vi /etc/dhcp/dhcpd.conf 
option domain-name ""; option domain-name-servers; default-lease-time 600; max-lease-time 7200; authoritative; subnet netmask { range dynamic-bootp; option broadcast-address; option routers; option interface-mtu 1452; } host ubifi { option host-name ""; hardware ethernet f0:9f:c2:1f:c1:12; fixed-address; }

Now enable and start your DHCP server

systemctl start dhcpd systemctl enable dhcpd

DNS Install and Configure

Next, install bind and and bind-utils for tools like nslookup and dig.

dnf -y install bind bind-utils

Configure your bind server with listening address (LAN interface in this case) and the forward/reverse zones.

$ vi /etc/named.conf
options { listen-on port 53 {; }; listen-on-v6 port 53 { none; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; secroots-file "/var/named/data/named.secroots"; recursing-file "/var/named/data/named.recursing"; allow-query {; }; recursion yes; forwarders {;; }; dnssec-enable yes; dnssec-validation yes; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/"; session-keyfile "/run/named/session.key"; include "/etc/crypto-policies/back-ends/bind.config"; }; controls { }; logging { channel default_debug { file "data/"; severity dynamic; }; }; view "internal" { match-clients { localhost;; }; zone "" IN { type master; file ""; allow-update { none; }; }; zone "" IN { type master; file "0.0.10.db"; allow-update { none; }; }; };

Here is a zone file for example and make sure to update the serial number after each edit of the bind service will assume no changes took place.

$ vi /var/named/
$TTL 86400 @ IN SOA ( 2018040801 ;Serial 3600 ;Refresh 1800 ;Retry 604800 ;Expire 86400 ;Minimum TTL ) IN NS IN A gw IN A ubifi IN A

Here is a reverse zone file for example and make sure to update the serial number after each edit of the bind service will assume no changes took place.

$ vi /var/named/0.0.10.db
$TTL 86400 @ IN SOA ( 2018040801 ;Serial 3600 ;Refresh 1800 ;Retry 604800 ;Expire 86400 ;Minimum TTL ) IN NS IN PTR IN A 1 IN PTR 2 IN PTR

Now enable and start your DNS server

systemctl start named systemctl enable named

Secure SSH

Last simple step is to make SSH service listen only on your LAN segment. Run this command to see whats listening at this moment. Remember we did not allow SSH on the external firewall zone but this step is still best practice in my opinion.

ss -lnp4

Now edit the SSH service to only listen on your LAN segment.

vi /etc/ssh/sshd_config
AddressFamily inet ListenAddress

Restart your SSH service for changes to take effect.

systemctl restart sshd.service

Optional WiFi Configuration

In this optional section we have the configuration for Wireless AP and 4G WAN. I used Ubiquiti wireless in my setup as I needed multi AP and seamless handover. For WiFi you probably want WPA2 pre-shared key, RSN security protocol, and CCMP group as shown below. We also set the AP to run as 5GHz band via “ a”.

dnf install NetworkManager-wifi nmcli connection add type wifi ifname wlp6s0 con-name ap0 autoconnect yes ssid HOMENET 802-11-wireless.mode ap a 802-11-wireless-security.proto rsn 802-11-wireless-security.pairwise ccmp ccmp 802-11-wireless-security.psk xxxxxxxxx 802-11-wireless-security.key-mgmt wpa-psk ipv4.method shared

Optional  4G Configuration

Now install wwan support and if you have a WWAN USB modem like me that needs to be switched to modem mode vs. storage.

dnf install NetworkManager-wwan ModemManager
Enable and start the ModemManager
systemctl start ModemManager  systemctl enable ModemManager
Plug your device in and make sure ModemManager and NetworkManager both see the wwan device.
mmcli -M nmcli dev
If you don’t see your device I recommend you go to this link and open a bug report.

Now configure your 3GPP WAN connection and reload to make sure everything auto-starts.

nmcli connection add type gsm con-name Telekom gsm.apn ifname ttyUSB0 

Since we have the default zone for our firewall set to external, this wwan interface will be put into the correct zone.–>

Thank you

Thanks and please leave a comment below if you have any ideas, edits or questions.