Debian Wireless Router Tutorial

Contributed by Andrew D. Hwang


This tutorial explains how to configure a simple, debian-based IPv4 router and firewall, providing

  • one or more wired connections to a home local access network (LAN),
  • an encrypted, password-protected wireless access point (WAP), and
  • a wired connection to an ISP that transparently routes from the LAN and WAP to the internet while shielding the internal networks.

These instructions are written for people with no prior experience with single-board computers (SBC), and are tailored for a PCEngines APU 2E4 from TekLager with debian 12.4 (bookworm) or later pre-installed. The information below may be useful more generally for setting up a secure, text-configured, easily-maintained home or office router that will last through debian's next few major releases. Particularly, we'll avoid software that is nearing end of life or otherwise deprecated.

This tutorial does assume familiarity with the command line, debian filesystem organization, user and file permissions, and IPv4 networking. Reference information on these topics, and on most system-level aspects of debian, may be found in the Debian Administrator's Handbook (currently written for debian 11).

In the spirit of starting from a fresh install, we'll use preferred software and practices for bookworm, including systemctl to enable, start, and stop services; ifupdown to manage network interfaces; and apt to manage packages. For file editing, nano is small but intuitive.

Cautions and Disclaimers

TekLager will install debian on request. To emphasize, the configuration is entirely by editing configuration files and managing services with a command prompt. For router management remotely through a web-based graphical interface, you probably want OpenWRT instead of debian.

At this writing (early 2024), web searches related to "debian wireless router configuration" return a patchwork of documentation and advice often based on older software and practices. This write-up is an attempt to provide current guidance for a minimal, contemporary installation.

The usual caveats hold: Although the author (Andrew D. Hwang) has made a good faith effort to provide accurate, safe information, this document may not work for you, or may contain errors. Information is provided as-is, without any warranty, including the implied warranty of merchantability or fitness for a particular purpose.

Capsule Summary

Here are the four packages we'll install, and their purposes:

  • Kea: dynamic host configuration protocol (DHCP) server for the LAN interfaces.
  • hostapd, wpasupplicant, and wireless-tools: wireless configuration, authentication, and management.

Kea, the new DHCP server created by the Internet Systems Consortium (ISC), replaces isc-dhcp-server, whose End of Life (EOL) was announced by the ISC in late 2022.

We'll use isc-dhcp-client, which is pre-installed with bookworm, to configure the WAN interface. (This is the only deprecated package used in this tutorial: According to the ISC and recent debian documentation, isc-dhcp-client is EOL. Unlike with Kea, ISC does not list a replacement DHCP client. The previous debian link mentions the busybox utility udhcpc as compatible with ifupdown.)

We'll use nftables for routing, network address translation (NAT, also known as IP masquerading), and firewalling. nftables is not a package needing installation or a service needing management, but part of the kernel requiring one-time configuration.

The legacy software iptables is mentioned in this tutorial precisely once. Ahem.

We'll edit the following five configuration files:

  • /etc/network/interfaces: parameters to bring up network interfaces.
  • /etc/dhcp/dhclient.conf: configure networking (WAN) over our ISP.
  • /etc/kea/kea-dhcp4.conf: auto-assign static and dynamic IP addresses on internal networks (LAN).
  • /etc/nftables.conf: configure routing, NAT, and firewalling.
  • /etc/hostapd/hostapd.conf: parameters for the wireless access point (WAP).

For further reading, please consult the official Kea documentation, the nftables wiki and quick-start guide, the hostapd wiki, and the Gentoo wiki page for hostapd.

Optionally, we'll modify /etc/resolv.conf to specify nameservers if we don't like our ISP's defaults.

Getting Started

A few decisions need to be considered before we start configuring:

  • How will the router be administered: remotely by ssh from the LAN, or locally through the serial port?
  • Who will administer: the root user directly, or an ordinary user who uses su or sudo to get root?
  • What is the structure of the network we're building? What are the names of the network, the router, and other machines on the LAN?

Initial configuration must be done through the serial port. This tutorial assumes the router will be administered over the LAN by ssh, and the default non-root user debian will use su to get root. If you decide differently, modify the instructions accordingly.

Machines have hostnames. In debian, edit /etc/hostname as root to set the hostname at the next boot.

For convenience and personality in this tutorial, we'll call the router Portal. There must be another machine on the LAN by which we access Portal. We'll call this computer Hal because "Hal" is easy to type, not as a wry homage to the murderous computer HAL9000 who declined to open the pod bay doors in Stanley Kubrick's 2001: A Space Odyssey.

For definiteness, we'll assume the wired LAN is called This name is not routable from the internet, and should not be a real domain. With these names (you should supply your own), the network will look like this:

                         []     +-- (configured, not used)
                         []     |
Internet --- Modem --+ Portal --+-- (
                         []     |
			 []     +-- (unnamed wireless network)
We'll assume Hal, short for, has static IP address


The plus signs mark the conceptual locations of Portal's network ports. From the internal networks, Portal is, and this address is the gateway.

Connecting to Portal

When "Portal" is connected to a power supply it boots automatically in about 40 seconds. (The scare quotes are a reminder that Portal doesn't know its name yet. From now on we'll ignore this.) Once Portal is booted, a shell prompt can be reached by serial cable from Hal.

Hal does not need to run debian, or any GNU/Linux distribution, it just needs a keyboard, monitor, USB port, and the terminal emulator program putty. All our typing will be done in putty on Hal's keyboard; the files created, modified, and saved will be on Portal.

If necessary, install putty on Hal and (for later use) generate an ssh key pair with no password.

Connect a serial cable to the retro-looking 9-pin connector on Portal, and plug the USB end into Hal. On Hal, start putty with root privileges. Select "serial connection", using a connection speed of 115200 and the USB tty device. (On the author's "Hal" this is /dev/ttyUSB0.) Pressing return should give a prompt on Portal. Enter the default account name and password (debian). In the putty window you should now be logged onto Portal.

First we'll set up secure, password-free login on Portal by creating a new file .ssh/known_hosts (note the initial dot!) in debian's home directory.

    debian@Portal:~$ mkdir .ssh
    debian@Portal:~$ nano .ssh/known_hosts
Paste Hal's public ssh key into known_hosts, save, and exit. Once the network is configured, this key will allow secure login and file transfer from Hal to the debian account on Portal without a password.


Speaking of passwords, change debian's password on Portal:

    debian@Portal:~$ passwd
and follow the prompts to enter a new password.


The rest of the tutorial is performed as root. Exercise the usual care in typing: File-manipulating commands do not run interactively as root, and have power to Damage the System. Type

    debian@Portal:~$ su
and enter the default root password. The prompt changes as a visual reminder of being root.


We need to change root's password:

    root@Portal:/home/debian# passwd
and again follow the prompts. Although Portal does not allow root to log in remotely with a password, changing default passwords is basic security.


All changes to be made are in the system configuration directory /etc. We'll move there for convenience, and set the hostname as warm-up:

    root@Portal:/home/debian# cd /etc
    root@Portal:/etc# nano hostname
Edit in your router's new name, save, and exit. This name will take effect at the next boot.


By default, the system binaries directory /sbin is not in debian's or root's PATH environment variable. Although many commands below are in /sbin, typing their full path as root can serve beneficially as an inducement to slow down and double-check before hitting return.

This step optionally reboots Portal to set the new hostname; feel free to skip to the next section. Otherwise, type

    root@Portal:/etc# /sbin/reboot
and wait for Portal to boot up on its own. Boot messages will be printed in the putty console. Error messages similar to
[    9.412581] ath10k_pci 0000:01:00.0: firmware: failed to load ath10k/pre-cal-pci-0000:01:00.<wbr></wbr>0.bin (-2)
are harmless and may be safely ignored. Once you get a prompt, log in as debian (with debian's new password), su to get root (with root's new password), and
    root@Portal:/home/debian# cd /etc


Configuring the WAN

Because Portal runs bookworm (or later), its network interface names follow the modern Linux convention: a two-letter prefix (en for ethernet, wl for wireless), the PCI bus (p1, p2, …), and the slot number (s0, s1). The APU 2E4 board has three Intel I210 ethernet ports. Starting at the serial port and moving rightward, the kernel names these enp2s0 (the WAN), enp3s0, and enp4s0. There is also a Qualcomm Atheros QCA 986x/988x wireless interface, which the kernel names wlp1s0.

Interface Configuration

Parameters for starting and stopping network interfaces are supplied in the file /etc/network/interfaces. The manual page (man interfaces) describes the structure and workings of this file.

We'll make a back-up copy of the default configuration in case we need to restore a known working state, then open the file in a text editor:

    root@Portal:/etc# cp -p network/interfaces network/interfaces.orig
    root@Portal:/etc# nano network/interfaces
Paste in the contents below, with the appropriate local addresses and network name:
# /etc/network/interfaces

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The WAN interface
allow-hotplug enp2s0
iface enp2s0 inet dhcp
iface enp2s0 inet6 auto

# primary LAN
auto enp3s0
iface enp3s0 inet static

# secondary LAN
auto enp4s0
iface enp4s0 inet static

# wireless
auto wlp1s0
allow-hotplug wlp1s0
iface wlp1s0 inet static
    hostapd /etc/hostapd/hostapd.conf
Save the file and exit the editor.


To get Portal talking to the internet we'll use DHCP to ask our ISP for a routable address. As above, make a back-up of the client configuration file, and open the file in a text editor for perusal:

    root@Portal:/etc# cp -p dhcp/dhclient.conf dhcp/dhclient.conf.orig
    root@Portal:/etc# nano dhcp/dhclient.conf
The default configuration may be fine. If so, exit without making changes.


Alternatively, you might want to comment out the requests for domain-name, domain-name-servers, domain-search, and host-name in order to use manually-chosen name servers. Put a # at the start of a line to comment out that line. Add newlines as needed to keep or omit individual parameters. (Comments in this file may not start in the middle of a line.) Save any changes to /etc/dhcp/dhclient.conf and exit the editor.

If you're not using your ISP's nameservers, put your preferred search domain (the LAN) and nameservers manually into the file /etc/resolv.conf. For example:

# /etc/resolv.conf
# Quad9 nameservers rather than google's


We're ready to start the connection to our ISP. Connect an ethernet cable to your modem and Portal's leftmost port enp2s0, closest to the serial cable.

The command ifup (interface up) followed by the name of a network interface starts that interface. Do

    root@Portal:/etc# /sbin/ifup enp2s0
After a few seconds there should be a response from your ISP leasing a routable IP address. (If not, see below.)


Once Portal can talk to the internet, be sure the system software is current:

    root@Portal:/etc# apt update
If there are updates, apply them:
    root@Portal:/etc# apt upgrade
Running this pair of commands regularly (perhaps weekly) should largely represent the long-term maintenance of Portal once everything is configured.


Start-up Errors

If there is an error message that the interface enp2s0 is already configured, first stop the interface, then start it again to test the new configuration:

    root@Portal:/etc# /sbin/ifdown enp2s0
    root@Portal:/etc# /sbin/ifup enp2s0


Otherwise, when a network interface does not start there are typically error messages that may be informative, or at least provide terms for web searching. The self-documented utility ip (which replaces ifconfig, route, and many other network diagnostics) can be used to list information about network interfaces. For example,

    root@Portal:/etc# ip a
lists the current status of all network interfaces. Detailed network diagnostics and debugging are beyond the scope of this tutorial.


Configuring the LAN

As outlined earlier and specified in /etc/network/interfaces, we're setting up three ipv4 subnets in the address space:

  • The primary wired LAN on enp3s0 assigned to and named
  • The secondary wired LAN on enp4s0 assigned to (This is likely optional, but it's easy to do and worthwhile if there's any chance of wanting a second wired network months or years from now.)
  • The wireless LAN on wlp1s0 (note carefully: double-u ell pee one ess zero) assigned to

Desktop machines and printers will be named,, and so forth.

Counting rightward from the router's serial connector, connect the second ethernet port (next to the WAN cable) to your ethernet hub. Start the interface:

    root@Portal:/etc# /sbin/ifup enp3s0
If there are no errors you should be able to ping (Portal) from machines connected to your hub.


The second ethernet interface (enp4s0) may be started manually at this time or not, as you prefer. (It will be started at each reboot. To prevent this, comment out its stanza in /etc/network/interfaces.)

Dynamic Address Service

Next we'll set up the DHCP server Kea to listen on our three subnets for client requests from our LAN. The package isc-dhcp-server is designated EOL by the ISC, so we'll remove it, then install Kea:

    root@Portal:/etc# apt purge isc-dhcp-server
    root@Portal:/etc# apt install kea
Kea is configured by files in /etc/kea. The syntax is JSON (Javascript object notation) rather than ini (*nix initialization). Particularly, double slashes denote comments. The extensive comments in the original files are useful, and mostly removed below for brevity. Section numbers refer to the Kea documentation.


For our ipv4 network, save a backup copy of /etc/kea/kea-dhcp4.conf, then edit in the contents below. Although lengthy, the configuration code below is divided into bite-sized stanzas by indentation and curly braces. Stanzas worthy of careful inspection are marked ATTN, and as noted require modification. You will need to modify:

  • The IP addresses of your real nameservers if you aren't using your ISP's defaults.
  • The name of your local network if you're using one.
  • The static IP address of any local machine, as desired; in the sample configuration, Hal is assigned the static address
  • The hardware (or MAC, for media access control) address of any local machine with a static IP address; an "advanced network settings" window on that machine should supply the ethernet MAC address, or on debian you can find the MAC address of each interface in the output of ip a.


// /etc/kea/kea-dhcp4.conf
"Dhcp4": {
    "interfaces-config": {
        // See section 8.2.4 for more details.
        // ATTN: Tutorial-specific
       "interfaces": [ "enp3s0", "enp4s0", "wlp1s0" ]

    // Kea supports control channel. For details, see Sections 8.8, 16 and 15.
    "control-socket": {
        "socket-type": "unix",
        "socket-name": "/run/kea/kea4-ctrl-socket"

    "lease-database": {
        "type": "memfile",
        "lfc-interval": 3600

    "expired-leases-processing": {
        "reclaim-timer-wait-time": 10,
        "flush-reclaimed-timer-wait-<wbr></wbr>time": 25,
        "hold-reclaimed-time": 3600,
        "max-reclaim-leases": 100,
        "max-reclaim-time": 250,
        "unwarned-reclaim-cycles": 5

    "renew-timer": 900,
    "rebind-timer": 1800,
    "valid-lifetime": 3600,

    // ATTN: Change nameservers and network name as needed
    "option-data": [
            "name": "domain-name-servers",
            "data": ","

            "name": "domain-name",
            "data": ""

            "name": "domain-search",
            "data": ""

            // Tutorial-specific, but do not change
            "name": "routers",
            "data": ""

    // Simple IPv4 subnet declaration.
    // This is a list [ ] of structures { }.
    // ATTN: Tutorial specific, but do not change unless noted
    "subnet4": [
	// first wired subnet, on enp3s0
	    "id": 1,
            "subnet": "",
            // ATTN: Reserving - for static addresses
            "pools": [ { "pool": " -" } ],
	    "comment": "enp3s0",

            // subnet-specific options
            "reservations": [
                    // ATTN: Change settings as needed
                    "hw-address": "00:11:22:33:44:5f",
                    "ip-address": "",
                    "hostname": "Hal"
            // ATTN: add comma-separated JSON objects for other hosts as needed
	// end of first wired subnet

        // ATTN: Nothing below here needs to be modified, but parts are commented
	// second wired subnet, on enp4s0
	    "id": 2,
            "subnet": "",
            // ATTN: enp4s0 gets; rest of subnet is dynamically assigned
            "pools": [ { "pool": " -" } ],
	    "comment": "enp4s0",

            "option-data": [
                    "name": "routers",
                    "data": ""
	// end of second wired subnet

	// wireless subnet, on wlp1s0
	    "id": 3,
            "subnet": "",
            // ATTN: wlp1s0 gets; rest of subnet is dynamically assigned
            "pools": [ { "pool": " -" } ],
	    "comment": "wlp1s0",

            "option-data": [
                    "name": "routers",
                    "data": ""
	 // end of wireless subnet
    // end of "subnet4"

    // Default code from the original file
    "loggers": [
        "name": "kea-dhcp4",
        "output_options": [
                "output": "syslog:dhcp",
                "pattern": "%-5p %m\n",
                "maxsize": 1048576,
                "maxver": 8

        "severity": "INFO",
        "debuglevel": 0
Note: The entire file is contained in curly braces. Do not omit or remove these. The two unindented braces at the end are not a typo.


Save the configuration file and exit the editor. Now start the Kea server:

    root@Portal:/etc# systemctl start kea
If there are no errors, kea is listening for and serving DHCP client requests on,, and


If there are errors with the configuration, syntax slips are a possibility. Guided by Kea's error messages, search for and fix mismatched brackets and braces, stray commas, etc.

We can now test our DHCP server. Machines newly-connected to the ethernet hub should get IP addresses after a few seconds, either static addresses if specified in the configuration above, or dynamic. (Machines on the LAN with existing dynamic addresses will keep them until their old dhcp lease expires, often in less than an hour, almost certainly in less than one day.)

Routing Configuration

The Linux kernel manages routing. We do not need to install server software or enable any services, but do need to ensure the appropriate kernel parameters are set at boot time. First do

    root@Portal:/etc# cat /proc/sys/net/ipv4/ip_forward
If the value is 1, Portal's kernel is configured for NAT. If the value is 0, do
    root@Portal:/etc# echo 1 > /proc/sys/net/ipv4/ip_forward
to set the flag, and uncomment the appropriate line in /etc/sysctl.conf so this flag is set at boot.


We'll use nftables to manage traffic on the LAN, and to/from the internet. Save a backup copy of the configuration file /etc/nftables.conf, then paste in:

# /etc/nftables.conf
flush ruleset

# external wired
define EXT = enp2s0

# local wired
define ETH1 = enp3s0
define ETH2 = enp4s0

# internal wireless
define WLS = wlp1s0

table ip global {
  chain input {
    type filter hook input priority 0; policy drop;

    # established/related connections
    ct state established,related accept

    ct state invalid drop

    #allow loopback, LAN
    iifname { lo, $ETH1, $ETH2, $WLS } accept

    # explicitly drop unestablish/unrelated external packets
    iifname $EXT drop

    # else dropped by policy

  chain forward {
    type filter hook forward priority 0; policy drop;

    # established/related connections
    ct state established,related accept
    ct state invalid drop

    # accept LAN
    iifname { $ETH1, $ETH2, $WLS } accept
    # others dropped by policy

  chain postrouting {
    type nat hook postrouting priority 100; policy accept;

    # masquerade private IP addresses
    ip saddr meta oifname $EXT counter masquerade
    ip saddr meta oifname $EXT counter masquerade
    ip saddr meta oifname $EXT counter masquerade
Save the file and exit the editor. This configuration will be applied automatically at each boot, but it must be manually loaded now:
    root@Portal:/etc# /sbin/nft -f /etc/nftables.conf
If there are no errors, the wired subnet should be able to connect to the internet. (If enp4s0 is started manually, should also be connected.) We can test by pinging, or browsing the web from Hal.


Configuring the Wireless Interface

The wireless interface needs two additional packages to set parameters. We'll use hostapd (host access point daemon) to configure and manage the interface and wpasupplicant to assist with authenticating clients. Although not strictly necessary, wireless-tools contains useful utilities for debugging and optimizing a wireless network (not covered in this tutorial). These are found in /sbin and have names starting with iw. Issue the first command, and optionally the second:

    root@Portal:/etc# apt install hostapd wpasupplicant
    root@Portal:/etc# apt install wireless-tools
Save a backup copy of /etc/hostapd/hostapd.conf. Let's assume our wireless access point (WAP) is to be called Charon, with the case-sensitive password AETHERDOOR. Our configuration file, with the appropriate two-letter country code, might look like this:
# /etc/hostapd/hostapd.conf


Save the configuration file and exit the editor. Start the hostapd and wpa_supplicant (note the underscore) services:
    root@Portal:/etc# systemctl start hostapd
    root@Portal:/etc# systemctl start wpa_supplicant
Finally, start the wireless interface:
    root@Portal:/etc# /sbin/ifup wlp1s0
If there are no errors, the router will have a wireless access point named Charon with password AETHERDOOR. Connected devices should be able to see the internet.


Miscellaneous Notes

Wireless hardware requires proprietary firmware. If you installed bookworm yourself, be sure to add the non-free-firmware repository to /etc/apt/sources.list. This repository is new with bookworm. TekLager's debian install includes the latest Atheros firmware and links to the non-free repository.

The kernel wiki and Gentoo wiki links for hostapd may be consulted for information on the meanings of the configuration parameters above. The values shown are appropriate for networks consisting only of recent hardware and software, and should auto-negotiate acceptable network throughput, but are not necessarily optimized for speed.

Unlike the previously-edited configuration files, which are safe to leave world-readable, hostapd.conf contains the plaintext password of the wireless network. If there are users who have non-root shell access on Portal but are not allowed to use the wireless network, do

    root@Portal:/etc# chmod 600 hostapd/hostapd.conf
to make the file readable only by root.


A wireless passphrase may be hashed into a 64-byte string by running

    root@Portal:/etc# wpa_passphrase wlp1s0
and following the prompt. The resulting value is, according to some sources, an acceptable value for wpa_passphrase, and avoids putting the plain text password in the configuration file. This did not work for the author, however.


Final Steps

Now that wired and wireless networking are configured and operational, we want to ensure the necessary services start automatically at boot:

    root@Portal:/etc# systemctl enable kea hostapd wpa_supplicant
This creates service-starting symlinks in /etc/systemd/system. The systemctl man page and Debian Administrator's Handbook contain more details.


A serial cable attaching Hal to Portal is probably inconvenient. You can administer Portal by ssh from the LAN. Assuming your public key generated on Hal is in the file .ssh/known_hosts on Portal in debian's home directory, the command

    me@HAL:~$ ssh debian@
will get you a shell prompt on Portal. From here, do su to become root and run administrator commands. You may want to add a stanza to .ssh/config on Hal to simplify logging in. The lines below let you type ssh Pt on Hal to get to Portal over your network:
host Pt
        ForwardX11                      no
        User                            debian


If everything is working, there is one last test while we still have a serial connection: Reboot Portal and verify that all services start correctly. Issue

    root@Portal:/etc# /sbin/reboot
and wait for the router to boot up all the way with no manual intervention.


If the network is fully functioning after rebooting, it is safe to disconnect the serial cable (which will kill putty) and mount the router in its permanent location. Congratulations, and happy networking!

Further Possibilities

There are additional tweaks you may want to take on Portal, or topics you may want to investigate.

The user name debian is easily guessable by users of your network. If this is a concern, create (adduser) a new user with su or sudo privileges (install sudo on Portal accordingly), verify that the new user can get root, copy Hal's ssh key to the new account for easy login, and remove (deluser) the debian account.

The file /etc/crontab can be used to stop and start the wireless network at specified times, for example, so as not to leave the network open at night.

This tutorial does not cover setting up and using a virtual private network (VPN).

A few lines in /etc/nftables.conf will allow you to do things like:

  • Run a publically-visible server on your network and have Portal forward connections to the appropriate machine.
  • Block certain services or sites from all or selected machines in your network.

The possibilities are too numerous to discuss here. The Debian Administrator's Handbook (network infrastructure and network services) and nftables wiki (matching and acting on packets) are good starting points.

Caution: If Portal accepts incoming ssh connections, take care that it forwards them to an internal machine. Otherwise, Portal itself is accessible by ssh from the internet, i.e., can be administered remotely by anyone who has (or can guess) an account name and password.

It may be prudent to test your outward-facing configuration by scanning your public IP address to check for open ports. If you are not running any public facing servers, your router should be invisible to the internet.