The Verdict: Which Hardware Combo Wins for a Pi Router?

Turning a Raspberry Pi into a dedicated router for network segmentation, IoT VLANs, or a Pi-hole gateway is one of the most practical embedded networking projects you can build. But the bottleneck is always I/O. The Pi’s internal bus architecture dictates your maximum throughput, and picking the wrong Network Interface Card (NIC) combination will cap your gigabit connection at 300 Mbps.

Below is the decision matrix for routing hardware. We evaluate the three most common dual-NIC configurations available in 2026.

Configuration Max Real-World NAT Throughput CPU Overhead at 1Gbps Verdict
Pi 4 (4GB) + USB 3.0 Gigabit NIC ~650 Mbps High (Bottlenecked by USB 3.0 controller sharing PCIe x1) Budget pick, but struggles with heavy concurrent connections.
Pi 5 (4GB) + PCIe M.2 Dual NIC HAT ~940 Mbps Low (Direct PCIe Gen 2 lane) Best performance, but requires kernel driver compilation for most M.2 NICs.
Pi 5 (4GB) + USB 3.0 Gigabit NIC (AX88179) ~880 Mbps Medium (Pi 5 PCIe bus handles USB 3.0 much better than Pi 4) DEFAULT PICK: Plug-and-play kernel support, no driver compilation, excellent throughput.
The Concrete Pick: Buy the Raspberry Pi 5 (4GB) and pair it with the Cable Matters USB 3.0 to Gigabit Ethernet Adapter (Model 200201). It uses the ASIX AX88179 chipset, which has native, in-tree kernel support in Raspberry Pi OS. You will not need to mess with dkms or compile out-of-tree drivers.

Parts List & Interface Mapping

Here is the exact bill of materials (BOM) and the logical interface mapping for this build. Total cost is roughly $110.

Component Exact Model / Variant Approx. Cost Role / Interface Mapping
Compute Board Raspberry Pi 5 (4GB RAM) $60 Runs Raspberry Pi OS (Bookworm/64-bit)
USB NIC Cable Matters 200201 (AX88179) $18 LAN (Downlink): Maps to enx[MAC]
Power Supply Official Pi 27W USB-C PD PSU $12 Prevents brownouts under USB NIC load
Thermal Mgmt Official Pi 5 Active Cooler $5 Mandatory; NAT routing pushes CPU to 65°C+
Cabling 2x CAT6 UTP Patch Cables $8 WAN (eth0) and LAN (enx)

Interface Mapping Table

Unlike GPIO pins, network interfaces are mapped logically. The built-in Ethernet is hardwired to eth0. The USB NIC will enumerate as enx followed by its MAC address (e.g., enx00e04c680a1b). We will use predictable naming in our configuration.

  • Physical Port 1 (Built-in RJ45): eth0WAN (Connects to ISP Modem / Upstream Router)
  • Physical Port 2 (USB 3.0 NIC): enx*LAN (Connects to local switch, Wi-Fi AP, or direct to PC)

Step-by-Step: Flashing, Wiring, and Configuring the Gateway

Raspberry Pi OS (Bookworm) defaults to NetworkManager, which is great for desktops but terrible for static routing and NAT gateways. We will disable it and use systemd-networkd, which is significantly more robust for headless router duties.

  1. Flash the OS: Use Raspberry Pi Imager to flash Raspberry Pi OS Lite (64-bit, Bookworm) to a high-endurance microSD card or an NVMe drive via M.2 HAT. Enable SSH and set your username/password in the advanced settings.
  2. Boot and Update: Boot the Pi, SSH in, and run sudo apt update && sudo apt upgrade -y. Reboot.
  3. Disable NetworkManager: Run sudo systemctl disable NetworkManager and sudo systemctl stop NetworkManager.
  4. Enable systemd-networkd: Run sudo systemctl enable systemd-networkd and sudo systemctl enable systemd-resolved.
  5. Wire the Interfaces: Plug your upstream internet connection into the built-in eth0 port. Plug your local switch or AP into the USB 3.0 enx port.

The NAT & Routing Script (nftables + systemd-networkd)

Below is the complete, copy-pasteable Bash script to configure your WAN DHCP client, LAN static IP/DHCP server, IP forwarding, and nftables NAT masquerade. This targets the Raspberry Pi 5 (4GB) running Bookworm.

Safety & Network Warning: Running this script will reconfigure your network stack. If you are SSH'd in via Wi-Fi or the interface you are modifying, you will drop your connection. Connect a monitor/keyboard or ensure you are plugged into the correct port before executing.
#!/bin/bash
# pi-router-setup.sh
# Target: Raspberry Pi OS Bookworm (64-bit) on Pi 5
# Configures systemd-networkd and nftables for NAT routing.

set -euo pipefail
trap 'echo "[ERROR] Script failed at line $LINENO. Check interface names with ip a." >&2; exit 1' ERR

# 1. Define Interfaces
WAN_IF="eth0"
# Find the USB NIC dynamically by looking for the 'enx' prefix
LAN_IF=$(ip -o link show | awk -F': ' '{print $2}' | grep '^enx' | head -n 1)

if [ -z "$LAN_IF" ]; then
    echo "[FATAL] Could not find USB NIC (enx*). Is it plugged into a blue USB 3.0 port?"
    exit 1
fi

echo "Detected WAN: $WAN_IF | LAN: $LAN_IF"

# 2. Configure WAN (DHCP Client)
cat < /dev/null
[Match]
Name=$WAN_IF

[Network]
DHCP=ipv4

[DHCPv4]
UseMTU=true
RouteMetric=10
EOF

# 3. Configure LAN (Static IP + DHCP Server)
cat < /dev/null
[Match]
Name=$LAN_IF

[Network]
Address=192.168.50.1/24
DHCPServer=yes
IPForward=ipv4

[DHCPServer]
PoolOffset=10
PoolSize=200
EmitDNS=yes
DNS=192.168.50.1
EOF

# 4. Enable IP Forwarding in sysctl
cat < /dev/null
net.ipv4.ip_forward=1
net.ipv4.conf.all.rp_filter=2
net.ipv4.conf.$WAN_IF.rp_filter=2
EOF
sudo sysctl --system

# 5. Configure nftables for NAT Masquerade
cat < /dev/null
#!/usr/sbin/nft -f
flush ruleset

table inet nat {
    chain postrouting {
        type nat hook postrouting priority 100; policy accept;
        oifname "$WAN_IF" masquerade
    }
}

table inet filter {
    chain forward {
        type filter hook forward priority 0; policy accept;
        iifname "$LAN_IF" oifname "$WAN_IF" accept
        iifname "$WAN_IF" oifname "$LAN_IF" ct state established,related accept
    }
}
EOF

# 6. Restart Services
sudo systemctl restart systemd-networkd
sudo systemctl enable nftables
sudo systemctl restart nftables

echo "[SUCCESS] Router configuration applied. Rebooting in 5 seconds..."
sleep 5
sudo reboot

Debugging: When the Router Drops or Fails to Boot

Network configuration on embedded Linux is unforgiving. If your LAN clients can't reach the internet, or the Pi fails to route, follow this decision path.

The First Three Things to Check

  1. Verify Interface State: Run ip a. Ensure eth0 has a public/upstream IP and enx... has 192.168.50.1. If the USB NIC is missing, it's a power or driver issue.
  2. Verify IP Forwarding: Run cat /proc/sys/net/ipv4/ip_forward. It must output 1. If it outputs 0, your sysctl config failed to apply.
  3. Verify NAT Rules: Run sudo nft list ruleset. You must see the masquerade directive under the postrouting chain. If the table is empty, nftables.service failed to load.

Ranked Causes for Common Error Strings

Exact Error String Ranked Causes (Most to Least Likely) Fix
nftables.service: Main process exited, code=exited, status=1/FAILURE 1. Syntax error in /etc/nftables.conf.
2. Interface name mismatch (e.g., script hardcoded eth1 instead of enx...).
Run sudo nft -c -f /etc/nftables.conf to dry-run and validate syntax. Check ip a for exact names.
RTNETLINK answers: File exists 1. systemd-networkd is fighting with a leftover dhcpcd or NetworkManager instance trying to assign a default route. Run sudo apt purge dhcpcd5 and ensure NetworkManager is fully masked/disabled.
USB disconnect, device number X (in dmesg) 1. USB NIC drawing too much peak current during TX bursts.
2. Using a USB 2.0 port or an unpowered hub.
Move the NIC to the blue USB 3.0 port closest to the power connector. Ensure you are using the official 27W PD power supply.

Extending the Build: VLANs, Pi-hole, and WireGuard

Once your baseline NAT gateway is stable, you can extend the functionality without rebuilding the OS.

  • To Simplify (Bridge Mode): If you don't need NAT and just want the Pi to act as a transparent bridge (e.g., for inline IDS like Suricata), delete the nftables NAT rules and configure a [Network] Bridge=br0 in systemd-networkd linking both interfaces.
  • To Extend (Pi-hole DNS): Install Pi-hole via the official curl script. During setup, when asked which interface to listen on, select enx... (your LAN interface). Pi-hole will automatically bind to 192.168.50.1 and serve DNS to your DHCP clients.
  • To Extend (WireGuard VPN): Install WireGuard (sudo apt install wireguard). Generate your keys, and add PostUp = nft add rule inet nat postrouting oifname %i masquerade to your wg0.conf to allow remote clients to route through your Pi's WAN connection.

For deeper reading on modern Linux firewall syntax, refer to the official Netfilter nftables NAT wiki. For Pi-specific bus limitations and power requirements, always consult the Raspberry Pi 5 Hardware Documentation.