The Verdict: Decision Tree for Pi 3 Routing
Using a Raspberry Pi 3 as a router is a classic edge-networking project, but it comes with a hard physical limitation: the USB 2.0 bus. The Pi 3 shares its 480 Mbps USB 2.0 bus between the four USB ports and the built-in Ethernet controller. This means your maximum real-world throughput is capped at roughly 300 Mbps, even if you plug in a Gigabit USB adapter. If you are routing a 1 Gbps fiber connection, the Pi 3 will bottleneck your network. If you are routing an IoT VLAN, a Pi-hole network, or a sub-300 Mbps WAN link, it is a highly capable, low-power router.
| Your Requirement | Recommended Hardware |
|---|---|
| WAN speed > 500 Mbps (Gigabit Fiber) | Abandon Pi 3. Buy a Raspberry Pi 5 or a used enterprise mini-PC (e.g., Intel N100). |
| WAN speed < 300 Mbps + need low power | Raspberry Pi 3 Model B+ with an ASIX AX88179 USB adapter. |
| Need built-in dual-band WiFi routing | Abandon Pi 3. The Pi 3 only has 2.4GHz 802.11n. Use a Pi 4 or Pi 5. |
Default Pick for this Guide: We are building a wired edge router using the Raspberry Pi 3 Model B+ (which has better thermal management and a slightly improved Ethernet MAC than the older 3B) paired with an ASIX AX88179 USB-to-Gigabit Ethernet adapter.
Hardware Spec Sheet: Overcoming the USB Bottleneck
The most common reason Pi 3 router builds fail or drop packets is the use of cheap Realtek-based USB Ethernet adapters. The Realtek RTL8153 chipset is notorious for triggering USB UAS (USB Attached SCSI) bugs and dropping interrupts on the Pi 3's DWC2 USB controller under sustained load. You must use an adapter with the ASIX AX88179 chipset, which has native, stable mainline Linux kernel support.
| Component | Exact Variant / Model | Estimated Cost (2026) |
|---|---|---|
| Compute Board | Raspberry Pi 3 Model B+ (1GB RAM) | $35 - $45 (Used/Refurb) |
| WAN/LAN Adapter | UGREEN or Cable Matters USB 3.0 to Gigabit Ethernet (Must specify AX88179 chipset) | $16 - $20 |
| Storage | SanDisk Extreme 32GB A2 microSD (Raspberry Pi OS Lite) | $12 |
| Power Supply | Official Raspberry Pi 5.1V 2.5A Micro-USB Power Supply | $12 |
| Cabling | 2x CAT6 Patch Cables (WAN to Modem, LAN to Switch) | $8 |
Under-voltage detected in dmesg), your USB adapter will randomly disconnect, killing your LAN routing.
Port Mapping and Logical Interface Assignment
Because the Pi 3 only has one physical RJ45 jack, we must map our physical ports to logical interfaces in the OS. Raspberry Pi OS uses predictable network interface names by default, but for a router, it is highly recommended to revert to standard ethX naming via raspi-config to make firewall scripting predictable.
| Physical Port | Logical Interface | Role | IP Assignment |
|---|---|---|---|
| Built-in RJ45 Jack | eth0 | WAN (Uplink to ISP Modem) | DHCP Client (from ISP) |
| USB AX88179 Adapter | eth1 | LAN (Downlink to Switch/PC) | Static: 192.168.50.1/24 |
| Built-in WiFi (Optional) | wlan0 | Disabled or LAN Bridge | N/A (Left unconfigured for stability) |
Step-by-Step Router Configuration (nftables & dnsmasq)
Raspberry Pi OS (Bookworm and later) has deprecated iptables in favor of nftables. While iptables-legacy still works, writing native nftables rules is faster and future-proof. We will use dnsmasq for DHCP and DNS forwarding.
Target Board: Raspberry Pi 3 Model B+ running Raspberry Pi OS Lite (64-bit, Bookworm).
1. Prepare the OS and Interfaces
- Flash Raspberry Pi OS Lite (64-bit) to your microSD card.
- Boot the Pi, connect via SSH, and run
sudo raspi-config. - Navigate to Advanced Options > Network Interface Names and select No (this forces
eth0andeth1instead ofenx...MAC-based names). - Reboot the Pi. Verify interfaces with
ip link show. You should seeeth0andeth1.
2. Install Required Packages
sudo apt update
sudo apt install dnsmasq nftables -y
sudo systemctl enable nftables
sudo systemctl enable dnsmasq
3. Configure the LAN Interface
Edit /etc/dhcpcd.conf (or /etc/NetworkManager/system-connections/ if using NetworkManager, but dhcpcd is standard for Lite headless setups) to assign a static IP to the LAN port:
echo 'interface eth1
static ip_address=192.168.50.1/24' | sudo tee -a /etc/dhcpcd.conf
sudo systemctl restart dhcpcd
4. Configure dnsmasq (DHCP & DNS)
Backup the default config and write a clean router configuration:
sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig
sudo nano /etc/dnsmasq.conf
Paste the following:
interface=eth1
dhcp-range=192.168.50.10,192.168.50.200,255.255.255.0,24h
dhcp-option=option:router,192.168.50.1
dhcp-option=option:dns-server,192.168.50.1
listen-address=::1,127.0.0.1,192.168.50.1
bind-interfaces
5. Enable IP Forwarding and NAT (The Router Script)
Create a script to enable kernel forwarding and load the nftables NAT rules. Save this as /usr/local/bin/setup-router.sh:
#!/bin/bash
# setup-router.sh - Raspberry Pi 3 Router NAT Configuration
# Target: Pi 3 B+ / Raspberry Pi OS Bookworm
set -e
WAN_IF='eth0'
LAN_IF='eth1'
# 1. Enable IPv4 forwarding in the kernel
echo 1 > /proc/sys/net/ipv4/ip_forward
# Make it persistent across reboots
if ! grep -q 'net.ipv4.ip_forward=1' /etc/sysctl.conf; then
echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
fi
# 2. Flush existing nftables and apply NAT rules
nft flush ruleset
nft add table ip nat
nft add chain ip nat prerouting '{ type nat hook prerouting priority -100 ; policy accept ; }'
nft add chain ip nat postrouting '{ type nat hook postrouting priority 100 ; policy accept ; }'
# Masquerade outbound traffic from LAN to WAN
nft add rule ip nat postrouting oifname '$WAN_IF' masquerade
# Allow established/related connections back in
nft add table ip filter
nft add chain ip filter forward '{ type filter hook forward priority 0 ; policy drop ; }'
nft add rule ip filter forward iifname '$LAN_IF' oifname '$WAN_IF' accept
nft add rule ip filter forward iifname '$WAN_IF' oifname '$LAN_IF' ct state established,related accept
echo 'Router NAT and Forwarding rules applied successfully.'
Make it executable and run it:
sudo chmod +x /usr/local/bin/setup-router.sh
sudo /usr/local/bin/setup-router.sh
nftables rules survive a reboot, run sudo nft list ruleset > /etc/nftables.conf after executing the script, and ensure nftables.service is enabled.
Debugging: Exact Errors and the First Three Checks
When a Pi router fails to pass traffic or hand out IPs, it is almost always due to service conflicts or interface naming changes. Here are the exact error strings you will see and how to fix them.
Error 1: dnsmasq: failed to create listening socket for port 53: Address already in use
Ranked Causes:
- systemd-resolved is running: Modern Debian/Ubuntu-based systems use
systemd-resolvedas a local DNS stub listener on port 53. It conflicts withdnsmasq. - Another DNS server is installed: Pi-hole or Unbound is already bound to port 53.
The Fix: Disable the stub listener in systemd-resolved, or stop it entirely if you don't need it on the router itself.
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
sudo systemctl restart dnsmasq
Error 2: nft: Error: Could not process rule: No such file or directory
Ranked Causes:
- Missing Table/Chain: You tried to add a rule to a chain (e.g.,
postrouting) before creating the parent table (e.g.,nat) in thenftsyntax. - Typo in Interface Name: The script references
eth1, but the OS assigned the USB adapterenx00e04c680123because predictable interface names were not disabled inraspi-config.
The Fix: Run ip a. If your USB adapter is named enx..., either rename it via udev rules, disable predictable names in raspi-config, or update the LAN_IF variable in the bash script to match the exact enx string.
Error 3: LAN clients get IP addresses but cannot ping 8.8.8.8
Ranked Causes:
- IP Forwarding is off: The kernel is dropping packets between
eth1andeth0. - WAN interface has no default route:
eth0didn't receive a DHCP lease from your ISP modem.
The Fix: Run cat /proc/sys/net/ipv4/ip_forward. If it returns 0, run echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward. Next, run ip route. If there is no default via... line pointing to eth0, restart dhcpcd on the WAN interface.
Extending or Simplifying the Build
Once your base router is passing traffic, you can tailor the build to your specific network needs.
How to Simplify: Convert to a Transparent Bridge
If you don't need NAT or DHCP and just want the Pi to act as a bridge (e.g., for inline network monitoring or passing a single public IP to a downstream device), strip out dnsmasq and nftables. Instead, use bridge-utils to bond eth0 and eth1 into a single br0 interface. This removes the CPU overhead of NAT, allowing the Pi 3 to pass traffic slightly faster, though still capped by the USB 2.0 bus.
How to Extend: Add Network-Wide Ad Blocking (Pi-hole)
Since dnsmasq is already handling DNS for your LAN, extending the build to block ads is trivial. Instead of installing the full Pi-hole suite (which installs its own dnsmasq and web server), simply append upstream blocklists directly to your existing dnsmasq config. Add conf-file=/etc/dnsmasq.d/blocklist.conf to your main config, download a standard hosts-file blocklist, and format it as address=/doubleclick.net/0.0.0.0. Restart dnsmasq, and your router now natively drops ad domains at the DNS level with zero extra memory overhead.
For deeper documentation on modern Debian networking, refer to the Raspberry Pi OS Configuration Guide and the Netfilter NAT Wiki. For advanced DNS routing options, consult the official dnsmasq manual.






