The Raspberry Pi 3 Model B+ makes a highly capable, low-power travel router or IoT NAT gateway, routing traffic between its 10/100 Ethernet port (WAN) and its 802.11n Wi-Fi radio (LAN). However, you will hit a hard ceiling of roughly 40 Mbps real-world Wi-Fi throughput due to the 2.4GHz 802.11n radio limits and the shared internal USB 2.0 bus. If you need gigabit routing, you are using the wrong board. But for isolating IoT devices, running a travel hotspot, or managing a captive portal, the Pi 3B+ is a bench staple.

This guide targets the Raspberry Pi 3 Model B+ running Raspberry Pi OS Bookworm (64-bit Lite). Bookworm introduced a massive shift by replacing dhcpcd with NetworkManager. If you follow older tutorials, your configuration will fail silently. We will bypass this using a robust, error-handled bash script.

Hardware Spec Sheet & Port Mapping

Difficulty Rating: Intermediate
Estimated Time: 45 minutes
Target Board: Raspberry Pi 3 Model B+ (1GB RAM, BCM2837B0)

Required Parts List

  • Board: Raspberry Pi 3 Model B+ (The 3B+ has improved thermal management and a slightly better Wi-Fi/Ethernet PHY than the base 3B).
  • Storage: 32GB Samsung EVO Plus MicroSD (U3 rated for sustained logging I/O).
  • Power: CanaKit 5V 2.5A Micro USB Power Supply (Do not use standard phone chargers; voltage drop under Wi-Fi TX load causes brownouts).
  • Networking: Cat6 Ethernet patch cable for WAN uplink.

Interface & Bus Mapping Table

Understanding the internal bus topology is critical. The Pi 3B+ routes both the Ethernet MAC and the Wi-Fi chip through the same USB 2.0 internal bus, which caps at 480 Mbps theoretical (roughly 300 Mbps real-world). This is why we assign Ethernet to WAN and Wi-Fi to LAN.

Logical Interface Physical Hardware Internal Bus Max Real-World Throughput Role in Build
eth0 LAN7515 Ethernet PHY USB 2.0 ~94 Mbps WAN (Uplink)
wlan0 Cypress CYW43455 (802.11n) SDIO / USB 2.0 ~40 Mbps LAN (Access Point)
lo Loopback Kernel N/A Localhost

Step-by-Step NAT Configuration (Bookworm Compatible)

In Raspberry Pi OS Bookworm, NetworkManager aggressively claims control of wlan0. If hostapd tries to grab the interface while NetworkManager is holding it, the access point will fail to start. We must explicitly tell NetworkManager to ignore the Wi-Fi interface.

  1. Update the system: Run sudo apt update && sudo apt upgrade -y to ensure all firmware and kernel modules are current.
  2. Install dependencies: Run sudo apt install hostapd dnsmasq iptables -y.
  3. Unblock the Wi-Fi radio: Run sudo rfkill unblock wlan to ensure the radio isn't soft-blocked by the kernel.
  4. Disable NetworkManager for Wi-Fi: We will handle this in the setup script by adding an unmanaged device rule to NetworkManager.
  5. Enable IP Forwarding: The kernel must be told to route packets between interfaces. This is handled via sysctl.

The Automated Setup Script

Below is the complete, compilable bash script to configure the NAT gateway. It includes strict error handling (set -euo pipefail), interface validation, and writes the necessary configuration files for hostapd, dnsmasq, and iptables.

Save this as setup_router.sh, make it executable with chmod +x setup_router.sh, and run it via sudo ./setup_router.sh.

#!/bin/bash
set -euo pipefail

# --- Configuration Variables ---
WAN_IF='eth0'
LAN_IF='wlan0'
SSID='FluxNet_Pi3'
WPA_PASSPHRASE='SuperSecret123!'
CHANNEL='6'
SUBNET='192.168.50.0/24'
ROUTER_IP='192.168.50.1'

# --- Pre-flight Checks ---
if [ "$(id -u)" -ne 0 ]; then
  echo 'ERROR: This script must be run as root (use sudo).' >&2
  exit 1
fi

if ! ip link show "$LAN_IF" &> /dev/null; then
  echo "ERROR: Interface $LAN_IF not found. Check your Wi-Fi hardware." >&2
  exit 1
fi

if ! ip link show "$WAN_IF" &> /dev/null; then
  echo "ERROR: Interface $WAN_IF not found. Check your Ethernet cable." >&2
  exit 1
fi

echo 'Stopping services for safe reconfiguration...'
systemctl stop hostapd dnsmasq NetworkManager 2>/dev/null || true

# --- NetworkManager Exclusion ---
echo 'Configuring NetworkManager to ignore wlan0...'
cat < /etc/NetworkManager/conf.d/unmanaged.conf
[keyfile]
unmanaged-devices=interface-name:$LAN_IF
EOF

# --- Hostapd Configuration ---
echo 'Writing hostapd.conf...'
cat < /etc/hostapd/hostapd.conf
interface=$LAN_IF
driver=nl80211
ssid=$SSID
hw_mode=g
channel=$CHANNEL
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=$WPA_PASSPHRASE
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
country_code=US
ieee80211n=1
EOF

# --- Dnsmasq Configuration ---
echo 'Writing dnsmasq.conf...'
cat < /etc/dnsmasq.conf
interface=$LAN_IF
dhcp-range=192.168.50.10,192.168.50.100,255.255.255.0,24h
dhcp-option=3,$ROUTER_IP
dhcp-option=6,$ROUTER_IP
listen-address=127.0.0.1,$ROUTER_IP
bind-interfaces
EOF

# --- Static IP for LAN Interface ---
echo 'Assigning static IP to $LAN_IF...'
ip addr flush dev "$LAN_IF"
ip addr add $ROUTER_IP/24 dev "$LAN_IF"
ip link set "$LAN_IF" up

# --- Kernel IP Forwarding ---
echo 'Enabling kernel IP forwarding...'
sysctl -w net.ipv4.ip_forward=1
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99_pi_router.conf

# --- IPTABLES NAT Rules ---
echo 'Flushing and applying iptables NAT rules...'
iptables -t nat -F
iptables -F
iptables -t nat -A POSTROUTING -o "$WAN_IF" -j MASQUERADE
iptables -A FORWARD -i "$WAN_IF" -o "$LAN_IF" -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i "$LAN_IF" -o "$WAN_IF" -j ACCEPT

# Save iptables rules (requires iptables-persistent)
apt-get install -y iptables-persistent > /dev/null 2>&1 || true
netfilter-persistent save > /dev/null 2>&1 || true

# --- Start Services ---
echo 'Starting services...'
systemctl restart NetworkManager
sleep 2
systemctl enable hostapd dnsmasq
systemctl start hostapd dnsmasq

echo 'SUCCESS: Raspberry Pi 3 Router is online. Connect to SSID: $SSID'

Debugging: "nl80211: Could not configure driver mode"

If you attempt to start hostapd manually and receive the exact error string nl80211: Could not configure driver mode, the access point will fail to broadcast. This is the most common failure mode on Pi 3 and Pi 4 boards running modern kernels.

The First Three Things to Check

  1. NetworkManager Interference: Run nmcli device status. If wlan0 shows as 'connected' or 'disconnected' (managed), NetworkManager is holding the lock. You must add the unmanaged-devices rule shown in the script above and restart NetworkManager.
  2. Missing Country Code: The Cypress Wi-Fi chip refuses to enter AP mode if the regulatory domain is unset. Ensure country_code=US (or your local ISO code) is explicitly defined in /etc/hostapd/hostapd.conf.
  3. RFKill Soft Block: Run rfkill list. If 'Soft blocked' says 'yes' for Wireless LAN, run sudo rfkill unblock wlan.

Ranked Causes for Persistent Failures

  • Cause 1 (80%): NetworkManager or wpa_supplicant is actively polling the interface. Fix: sudo systemctl stop wpa_supplicant and mask it via systemctl mask wpa_supplicant.
  • Cause 2 (15%): Channel congestion or DFS restrictions. The Pi 3 does not support 5GHz DFS channels properly in AP mode. Fix: Force channel=1, 6, or 11 in hostapd.conf.
  • Cause 3 (5%): Power supply brownout. Under heavy Wi-Fi TX load, the voltage drops below 4.63V, triggering a kernel-level USB/SDIO bus reset. Fix: Check for the lightning bolt icon on the display or use a multimeter to verify 5.1V at the GPIO header pins (Pin 2 and Pin 6).

Extending and Simplifying the Build

Depending on your end goal, you may want to pivot from this manual Debian-based setup to a more specialized firmware, or add network-level filtering.

How to Simplify: Flash OpenWrt

If you just want a standard router UI and don't care about using the Pi for other Python/C++ projects, abandon Raspberry Pi OS entirely. Download the OpenWrt image for the Raspberry Pi 3. OpenWrt handles the NAT, firewall, and LuCI web interface out of the box, treating the Pi exactly like a commercial off-the-shelf router. This eliminates the need to maintain bash scripts and systemd services.

How to Extend: Add Pi-hole DNS Sinkhole

To turn this router into an ad-blocking gateway, install Pi-hole. Because our script already configures dnsmasq for DHCP, you will need to disable the DHCP server inside the Pi-hole web admin panel and let our existing dnsmasq instance handle IP assignments, or allow Pi-hole to take over DHCP entirely. Point the upstream DNS in Pi-hole to a secure resolver like Quad9 (9.9.9.9) to keep your IoT traffic clean.

Frequently Asked Questions

Can a Raspberry Pi 3 router handle gigabit fiber internet speeds?

No. The Raspberry Pi 3 Model B+ features a 10/100 Ethernet controller, not Gigabit Ethernet. Even if your fiber ONT outputs 1000 Mbps, the Pi's physical Ethernet port will hard-cap your WAN connection at roughly 94 Mbps. Furthermore, the internal USB 2.0 bus bottleneck means simultaneous heavy uploads and downloads will degrade performance. For gigabit routing, you must upgrade to a Raspberry Pi 4 or Pi 5, or use a dedicated x86 mini-PC with native Intel NICs.

How do I add a captive portal to my Raspberry Pi 3 router?

To add a captive portal (the splash page that requires a click or password before granting internet access), you need to intercept HTTP/HTTPS traffic on port 80 and 443 and redirect it to a local web server. The easiest way to implement this on a Pi 3 is by installing Nodogsplash or OpenNDS. OpenNDS integrates directly with your existing iptables rules and provides a lightweight C-based daemon that manages client authentication tokens without requiring a heavy database backend.

Is it safe to leave a Raspberry Pi 3 router running 24/7?

Yes, provided you manage thermals and storage wear. The BCM2837B0 chip on the 3B+ will throttle at 85°C. If the Pi is in an enclosed acrylic case acting as a router, it will likely idle around 55°C but spike under heavy NAT translation loads. Apply a 14x14x4mm copper heatsink to the SoC and ensure the case has passive ventilation. To prevent MicroSD card corruption from constant DHCP lease logging, mount /var/log and /tmp as tmpfs (RAM disks) in your /etc/fstab file.