If you want to run OpenWrt on a Raspberry Pi, the definitive choice is the Raspberry Pi 4 Model B (2GB RAM). It provides native Gigabit Ethernet, hardware NAT offloading support, and stable thermals without requiring an active cooling fan at routing loads. While the Pi 5 is faster, its PCIe architecture requires a specialized HAT for secondary network interfaces, and the Pi Zero 2 W lacks the physical throughput for modern broadband. This guide walks through the exact hardware build, interface mapping, a native GPIO watchdog script, and the specific error strings you will hit when configuring a Pi-based router.
The Hardware Decision Tree: Which Pi to Pick
Choosing the right board prevents bottlenecks. Here is the decision matrix for routing workloads, terminating in our default pick.
| Board Variant | NAT Throughput | Thermals (Routing Load) | Native Ports | Verdict |
|---|---|---|---|---|
| Pi Zero 2 W | ~150 Mbps (USB2 bottleneck) | Passive OK | 0x GbE, 1x USB2 | Reject: Too slow for WAN. |
| Pi 3 Model B+ | ~300 Mbps (USB2 shared bus) | Throttles without fan | 1x GbE (USB2 bus), 1x USB2 | Reject: Shared bus limits speed. |
| Pi 4 Model B (2GB) | ~940 Mbps (Native GbE) | Passive OK (with case) | 1x Native GbE, 2x USB3 | DEFAULT PICK |
| Pi 5 (4GB) | ~1.5 Gbps (requires HAT) | Requires Active Cooling | 1x Native GbE, 2x USB3 | Overkill unless using PCIe HAT. |
Parts List & Interface/Pin Mapping
A Pi only has one physical Ethernet port. To build a standard router (one WAN, one LAN), you must add a secondary interface. Do not buy cheap USB2 adapters; they will cap your WAN at 300 Mbps. You need a USB3 Gigabit adapter with a chipset that has native OpenWrt kernel module support.
Exact Bill of Materials
- Compute: Raspberry Pi 4 Model B (2GB RAM)
- Enclosure: Flirc Raspberry Pi 4 Passive Aluminum Case (acts as a giant heatsink)
- Storage: SanDisk Extreme 32GB microSD (A2 rating for better random I/O)
- WAN Adapter: USB3 to Gigabit Ethernet Adapter (Must use Realtek RTL8156 chipset, e.g., UGREEN or Cable Matters RTL8156 models)
- Power: Official Raspberry Pi 27W USB-C Power Supply
Interface & GPIO Mapping Table
Unlike Arduino projects where you map logic pins, in an OpenWrt Pi build, you map physical interfaces and sysfs GPIO pins to logical network zones.
| Physical Hardware | OpenWrt Logical Interface | Firewall Zone | Notes |
|---|---|---|---|
| Pi 4 Native Ethernet (RJ45) | eth0 (br-lan) | LAN | Connects to your internal switch/APs. |
| USB3 RTL8156 Adapter | eth1 (wan) | WAN | Connects to ISP modem. Requires kmod-usb-net-rtl8156. |
| GPIO 21 (Pin 40) to GND | Physical Reset Button | N/A | Used by our watchdog script for factory reset. |
Flashing and First Boot Configuration
OpenWrt provides two image types for the Pi: squashfs and ext4. You must use the ext4-factory image. The squashfs image relies on a specific partition layout that the Pi's Broadcom bootloader often struggles with when expanding the filesystem on larger SD cards.
- Download the Image: Go to the OpenWrt Table of Hardware and download the latest stable
ext4-factory.img.gzfor the BCM2711 (Pi 4). - Flash the SD Card: Use BalenaEtcher or Raspberry Pi Imager. Do not use the Imager's 'OS customization' settings; let OpenWrt handle the network config.
- First Boot: Insert the SD card, connect the native Ethernet to your PC, and power on. The Pi will boot and assign itself
192.168.1.1. - Install USB WAN Drivers: SSH into the Pi (
ssh root@192.168.1.1) and install the driver for the RTL8156 adapter before configuring the network.opkg update opkg install kmod-usb-net-rtl8156 reboot
- Configure Interfaces: In LuCI (the web UI), go to Network > Interfaces. Edit the
WANinterface, set Protocol to 'DHCP client', and assign it to the neweth1interface. Ensure the WAN interface is assigned to thewanfirewall zone with Masquerading enabled.
GPIO Watchdog & Reset Script
Headless routers need a physical way to trigger a factory reset if you lock yourself out of LuCI. The following Bash script uses the native Linux sysfs GPIO interface. It targets the Pi 4B / Pi 400 (BCM2711 chip). It monitors GPIO 21 (Physical Pin 40). When pulled to ground via a momentary pushbutton for 3 seconds, it triggers an OpenWrt factory reset.
Save this as /usr/bin/gpio-reset.sh and make it executable (chmod +x), then add it to /etc/rc.local to run on boot.
#!/bin/bash
# Target: Raspberry Pi 4B / 400 (BCM2711)
# Pin: GPIO 21 (Physical Pin 40)
GPIO_PIN=21
GPIO_PATH="/sys/class/gpio/gpio${GPIO_PIN}"
HOLD_TIME=3 # Seconds to hold for reset
# Error handling: Clean up if GPIO is already exported from a crashed previous run
if [ -d "$GPIO_PATH" ]; then
echo "$GPIO_PIN" > /sys/class/gpio/unexport
sleep 1
fi
# Export the pin and configure
echo "$GPIO_PIN" > /sys/class/gpio/export
if [ $? -ne 0 ]; then
logger -t gpio-reset "Failed to export GPIO $GPIO_PIN. Exiting."
exit 1
fi
echo "in" > "$GPIO_PATH/direction"
echo "1" > "$GPIO_PATH/active_low" # Button pulls to GND, so active_low makes 1 = pressed
logger -t gpio-reset "Monitoring GPIO $GPIO_PIN for factory reset..."
# Polling loop with debounce
while true; do
VALUE=$(cat "$GPIO_PATH/value")
if [ "$VALUE" -eq 1 ]; then
START_TIME=$(date +%s)
# Check if button is held
while [ "$VALUE" -eq 1 ]; do
sleep 1
CURRENT_TIME=$(date +%s)
ELAPSED=$((CURRENT_TIME - START_TIME))
if [ "$ELAPSED" -ge "$HOLD_TIME" ]; then
logger -t gpio-reset "Button held for ${HOLD_TIME}s. Triggering firstboot!"
/sbin/firstboot -y
/sbin/reboot
exit 0
fi
VALUE=$(cat "$GPIO_PATH/value")
done
fi
sleep 0.5 # Polling interval
doneDebugging: Exact Error Strings & Ranked Causes
When building a Pi router, you will inevitably hit network state errors. Here are the exact strings logged in logread and how to fix them.
Error 1: br-lan: received packet on eth0 with own address as source address
What it means: The kernel is seeing its own MAC address coming back into the LAN bridge. This usually indicates a physical loop or a MAC cloning conflict.
- Most Likely Cause: You plugged the WAN cable and LAN cable into the same unmanaged switch, creating a physical bridge loop.
- Second Cause: Your ISP modem is locked to the MAC address of your old router, and you attempted to clone the MAC in OpenWrt, but the clone applied to the wrong interface (e.g., applied to br-lan instead of eth1).
- Fix: Verify physical cabling. If MAC cloning is required, go to Network > Interfaces > WAN > Advanced Settings, and enter the MAC address in the 'Override MAC address' field. Reboot the cable modem afterward.
Error 2: netifd: Interface 'wan' has link connectivity loss
What it means: The WAN interface dropped the physical link or failed to get a DHCP lease.
- Most Likely Cause: The USB Ethernet adapter went to sleep or crashed due to USB autosuspend. The RTL8156 chipset is notorious for this on Linux if not configured correctly.
- Second Cause: The ISP requires a specific MTU or VLAN tag (common with fiber ONTs) which is not set on the WAN interface.
- Fix: Disable USB autosuspend. Add
usbcore.autosuspend=-1to your/boot/cmdline.txtfile. If on fiber, check if your ISP requires VLAN ID 201 or similar, and configure a VLAN interface over eth1 in LuCI.
The First Three Things to Check When WAN Fails
If you have no internet on the LAN side, run this mental checklist before wiping the SD card:
- Check Firewall Zones: Go to Network > Firewall. Ensure the
waninterface is assigned to thewanzone, and thatMasquerading(NAT) andMSS clampingare checked. If Masquerading is off, your LAN traffic reaches the ISP but gets dropped because it uses private IP space. - Check Physical Interface Assignment: Go to Network > Interfaces > WAN > Physical Settings. Ensure it is strictly bound to
eth1(the USB adapter). If it is bridged witheth0, you have just merged your LAN and WAN into a single broadcast domain. - Check DNS Forwarding: SSH in and run
ping 8.8.8.8. If that works, butping google.comfails, your issue is DNS. Go to Network > DHCP and DNS, and ensure 'Allow dynamic DNS updates' is checked, or manually set upstream DNS servers to 1.1.1.1.
Extending or Simplifying the Build
Not every deployment requires a dual-interface NAT router. Depending on your network topology, you should adapt the build.
How to Simplify: The 'Dumb AP' or VLAN-on-a-Stick
If you already have a primary router (like a UniFi Dream Machine) and just want the Pi to run AdGuard Home or act as a wireless controller, do not use the USB WAN adapter. Simplify the build by deleting the WAN interface in LuCI entirely. Change the LAN interface IP to match your main router's subnet, point its gateway to your main router, and disable the Pi's DHCP server. This turns the Pi into a transparent bridge, eliminating double-NAT headaches and reducing CPU load to near zero.
How to Extend: Dual-WAN Failover (mwan3)
If you are deploying this in a remote cabin with unreliable internet, you can extend the build to support dual-WAN. Purchase a second USB3 Ethernet adapter (or use a 4G LTE USB modem). Install the multi-WAN package:
opkg install luci-app-mwan3
Configure wan1 (RTL8156 Ethernet) and wan2 (LTE Modem) in LuCI. The mwan3 package will monitor interface health via ping checks and automatically route traffic through the LTE modem if the primary Ethernet link drops. Ensure you set the metric of the primary WAN lower (e.g., 10) than the backup WAN (e.g., 20) so traffic prefers the cheaper/faster link.
For a dedicated, always-on routing appliance, the Raspberry Pi 4B (2GB) running OpenWrt with an RTL8156 USB WAN adapter remains the most cost-effective, thermally stable, and thoroughly documented build available. Stick to the ext4 filesystem, bind your firewall zones strictly, and disable USB autosuspend to ensure months of uninterrupted uptime.






