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.

topology

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 00xxx5511yyy0001@t-online.de 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 10.0.0.1/24 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 10.32.0.0/16 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 "lajoie.org"; 
option domain-name-servers 10.0.0.1;
default-lease-time 600; 
max-lease-time 7200; 
authoritative; 
subnet 10.0.0.0 netmask 255.255.255.0 { 
  range dynamic-bootp 10.0.0.100 10.0.0.254; 
  option broadcast-address 10.0.0.255; 
  option routers 10.0.0.1; option interface-mtu 1452; 
}
host ubifi { 
  option host-name "ubifi.lajoie.org"; 
  hardware ethernet f0:9f:c2:1f:c1:12; 
  fixed-address 10.0.0.2; 
}

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 { 10.0.0.1; };
  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 { 10.0.0.0/24; }; 
  recursion yes; 
  forwarders {8.8.8.8; 8.8.4.4; }; 
  dnssec-enable yes; 
  dnssec-validation yes; 
  managed-keys-directory "/var/named/dynamic"; 
  pid-file "/run/named/named.pid"; 
  session-keyfile "/run/named/session.key"; 
  include "/etc/crypto-policies/back-ends/bind.config"; 
}; 
controls { }; 
logging { 
  channel default_debug { 
    file "data/named.run"; 
    severity dynamic; 
  };
}; 
view "internal" { 
  match-clients { localhost; 10.0.0.0/24; }; 
  zone "lajoie.org" IN { 
    type master; 
    file "lajoie.org.db"; 
    allow-update { none; };
  }; 
  zone "0.0.10.in-addr.arpa" 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/lajoie.org.db
$TTL 86400 
@ IN SOA gw.lajoie.org. root.lajoie.org. ( 
  2018040801 ;Serial  
  3600 ;Refresh 
  1800 ;Retry 
  604800 ;Expire 
  86400 ;Minimum TTL ) 
IN NS gw.lajoie.org. 
IN A 10.0.0.1 
gw IN A 10.0.0.1
ubifi IN A 10.0.0.2

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     gw.lajoie.org. root.lajoie.org. ( 
  2018040801 ;Serial 
  3600 ;Refresh 
  1800 ;Retry 
  604800 ;Expire 
  86400 ;Minimum TTL ) 
IN         NS      gw.lajoie.org. 
IN         PTR     lajoie.org. 
IN         A       255.255.255.0 
1   IN     PTR     gw.lajoie.org. 
2   IN     PTR     ubifi.lajoie.org.

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 10.0.0.1

Restart your SSH service for changes to take effect.

systemctl restart sshd.service

Thank you

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

Fedora Project community

39 Comments

  1. Alex

    I think you need a newline between “AddressFamily inet” and “ListenAddress 10.0.0.1” for the /etc/ssh/sshd_config file.

    It might also we worth including MRTG / nethogs.

    Since I doubt this would work with UPNP (would it?) perhaps mention the limitations / problems that might affect common home systems like game consoles or p2p systems like bit-torrent which might rely on it.

    Otherwise, pretty solid article 🙂

    • Hi Alex,

      Multicast is working between br0 and the Ubiquiti wireless since the APs and user subnet are all on the same L2 domain.

      I can confirm the UPnP for my HP printer is working via both LAN and WLAN links.

      Eric

  2. Zaptac

    In order for the server to work as a router, you also have to turn on forwarding (net.ipv4.ip_forward=1 / net.ipv6.conf.default.forwarding=1)

    And, why virtual machines on a router?

    • When I enabled an interface via firewalld in external zone to masquerade, the net.ipv4.ip_forward sysctl variable was set automatically.

      • Zaptac

        Thanks, I did not know that. But makes sense.

        However, I still do not understand why KVM is running on the router? At least for openstack I would personally take a dedicated host. Attack vector and so on…

        • Hi Zaptac,

          The external interface has all ports closed off so lets hope firewalld can hold its own. The KVM part is for a few things including, UbiFi controller, OpenShift, and for a local sandbox to try out new tricks learned from https://www.offensive-security.com.

          I’d like to get to a point were I can also have IdM, and some other management nodes running to prepare for RHCA Cloud and Datacenter certifications.

          Eric

  3. Zach

    I’m curious ass to why you use BIND instead of DNSMasq or Unbound instead?

    • I used seperate BIND and DHCP services over DNSmasq as I hit one limitation with DNSmasq when trying to deploy virtualized OpenShift on KVM in the router. I needed to use wild card record pointing to multiple A records which is not supported yet in the DNSmasq I was using. Seems you can have one wild card record but it can only point to one A records.

      Thanks for the tip on Unbound, I’ve added it to my weekend bucket list.

  4. Osqui

    Maybe with dnsmasq instead of ISC’s dhcp/dns servers it’s easier. Thanks a lot, anyway!

  5. Germano

    For server usage I prefer to use systemd-networkd, is much easier to use than NetworkManager

    • I would have agreed with you until I tried to open my first bugzill afor an issue and had the fix delivered within a couple hours. The NetworkManager folks are doing a great job on improving features an stability.

  6. GW

    I believe you have a cut and paste error in the dhcpd.conf file, domain-name-servers line. I believe that is option not ption

    dnf -y install dhcp
    vi /etc/dhcp/dhcpd.conf

    option domain-name “lajoie.org”;
    ption domain-name-servers 10.0.0.1;
    default-lease-time 600;

    Regards.

  7. For an ISP that uses DHCP to assign IP addresses to customers you will want to allow DHCP on the external zone:

    firewall-cmd –permanent –zone=external –add-service=dhcpv6-client

    firewall-cmd –reload

    I am already using a Raspberry Pi with CentOS 7 as my LAN gateway router here at home for a couple years now. I have a cable modem in bridged mode, which forwards all traffic to my Raspberry Pi. The Pi strictly acts as a router. So the portion covering ADSL is not necessary.

    I also want to add that it is overkill to use ISC DHCP and BIND for such a set up. DNSMasq works just fine for DHCP and DNS, even with DNS SEC enabled. The idea of using qemu-kvm to run the services is great if you have a full computer as your router. On a Raspberry Pi it is not feasible to do so and most people will want a device that consumes low amounts of power for a home router.

    • Hi Brenton,

      These firewall rules are not needed in PPPoE case.

      In this case its a little different. We have PPPoE on our WAN link which is doing IPv4 and IPv6 LL address assignment via PPP IPCP and IP6CP respectively. Once we have LL address on the interface then the RA (SLAAC) address comes into the picture via source specifi multicast.

      Agree about QEMU on ARM or Power9 for that matter. I expect we will see QEMU show up in the ARMN/Power9 platforms once they have their own UEFI which we can boot from.

      Cheers,
      Eric

  8. How well does the DrayTech card’s Stateful Firewall work under Linux? Do you need to load any binary blobs or work with DKMS for kernel modules? Looking at the documentation from on the site looks like you can interact with a web interface.

    Nice work and very cool approach, might even share the PCI card with the Virtual Machine (PCI Host device)?

    • Hi Kevin,

      The card has a full modem OS running on it and provides in ethernet interface inside fedora to run your PPPOE against.

      I used its web GUI to turn it into a L2 bridge plus turned off all local L2 services in the model like TR-069. You also use the GUI to load the correct xDSL firmware based on who your carrier is.

      I can make a post on how to setup the modem if needed and you can grab the GUI manual here: https://www.draytek.com/en/download/firmware/vigornic-132-series/

  9. dramon

    Nice article!
    I would like to know what “PCI Express modem for VDSL” was used exactly?

    Thanks.

  10. João Rodrigues

    Remember, the keywords here are “If you want to learn about Linux system administration and networking”.

    If you want a router because you don’t trust your ISP to spy on your home network or because you want/need features that your ISP’s router doesn’t have or for whatever other reason, use a firewall/router distro, like ipfire or opnsense.
    It’s easier to setup and more secure.

    • Hi João,

      Agree if time is of the essence and the user does not have the background of desire to learn.

      Can you elaborate more and provide an example of how its more secure to use a firewall/router distro over fedora?

      My own experience with IPFire and OPNsense/pfSense is that both have rock solid BSD networking stack. Things get a little rough when you try and get new driver support, run on non-x86 HW, or look at new things like DPDK, SR-IOV, or containers.

      This is a good place to shared experience and knowledge so anyone please feel free to add your thoughts.

      I’d also highlight the developer community size and their upstream commits when comparing platforms.

      Thanks,
      Eric

      • I cannot speak for enterprise environments but I can speak about what I do to manage my home infrastructure. I have tried many different OS’s on single board computers to run my gateway router, managed switch, file server, and git server. I am a freelance software developer. Specifically on my router I use CentOS 7 on a Raspberry Pi 3 B+ because it has a longer release cycle. It hosts dnsmasq, hostapd, and arpwatch with postfix for email notifications.

        I’ve tried Raspbian, Fedora, Slackware, Arch, and FreeBSD. Router distros can be misconfigured just as easily as a full Linux/BSD distro. Router distros are also more difficult to customize. A regular distro has a larger range of software packages available, larger user base, and more developers. This boils down to better support and an easier time finding help. You will not need a router distro to accomplish what want if you know what you are doing.

  11. Postroutine

    Thanks for your fantastic article. I had never consider including the modem as part in my RAS (run under Fedora Server).

    I got a couple of questions:
    – NetworkManager can control a Fiber connection?
    – Is NetworkManager fully manageable by Ansible?

  12. Ajay

    How do you handle IPv6 DHCP-PD? I am not able to find any pointers to do pppoe over ipv4 and DHCPv6 PD

    • Hi Ajay,

      I’ve asked one of the fedora developers this same question as my carrier supports prefix delegation and I’d like to do the same. I’ll reply here once we have a working setup as they informed me a few weeks back that “ipv6.method shared” mode supported this.

      Stay tuned…

      Eric

      • dag

        Hi Eric, were you able to find any info on the DHCPv6-PD? I’d rather not use wide-dhcpv6(fairly old) or dibbler(no systemd unit files).

        Thanks again for writing this article.

  13. Johanh

    I’ve got cable (Docsis) 100/20 and also have a IPV6 tunnel. I’ve been thinking on this, because all my desktops are running Fedora. But I’ve ended up with an Ubiquiti Erlite-3 as router. Soon getting fiber and native IPV6. An option is a small 2HE rack mounted chassis with a micro- or mini-ATX mainboard when the Erlite-3 gets old.

  14. Karl

    Hi Eric,

    thanks for the great article.
    I have a very similar setup. ( Telekom VDSL, VigorNIC 132)
    But I do not get an IPv6 address when I use the network manager.
    If I use pppoe-setup, I can add add “+ipv6” to “/etc/ppp/options” to get an IPv6 address on ppp0 interface, but this does not work if I setup the DSL-Connection via NetworkManager.

    Do you know how to setup IPv6?

    Thanks

    • vi /etc/sysctl.conf
      net.ipv6.conf.ppp0.accept_ra=2

      nmcli the pppoe interface down then back up and you should see IPv6 address.

  15. Eri

    Is only one network card needed, or does the machine need to be multi-homed (multiple physical Ethernet interfaces)?

    Thanks,
    Erik

    • Johanh

      With a VLAN capable switch, one physical ethernet port is fine. But if you can’t use VLANs, you need at least two physical interfaces.

      • Adding to Eri, you typically have one port connected to the DSL modem with a dedicated cable and then a second interface for the other network/s.

        If you have a switch which supports VLAN tagging or transparently supports 802.1q then you could do a “router on a stick” solution.

        Just be aware most modems expect native or untagged traffic for PPPoE in for your LAN you would need to update MTU to take into account the new 802.1q header.

  16. ganner rhysode

    This is a great tutorial ! thank you for this

  17. dag

    Updating this with IPv6 guidance would be a nice touch, as well as either a separate guide or divisions into subsections on how to do this for Cable/Fiber(no PPP).

    A followup about QoS would be neat, a stock Fedora router is extremely susceptible to bufferbloat https://www.bufferbloat.net/projects/

    The “cake”(https://www.bufferbloat.net/projects/codel/wiki/CakeTechnical/) queueing discipline has recently been accepted upstream into net-next which greatly assists with these issues so hopefully we’ll see this hit stable before too long.

  18. It’s really important to be concerned with your router. SO many bad things can happen if we are not aware. Thanks for this great post, Now I will use useful security criteria to be secure.

  19. Mike C.

    This is a great topic and should incorporate WireGuard at some point.

Comments are Closed

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat. Fedora Magazine aspires to publish all content under a Creative Commons license but may not be able to do so in all cases. You are responsible for ensuring that you have the necessary permission to reuse any work on this site. The Fedora logo is a trademark of Red Hat, Inc. Terms and Conditions