Using a Raspberry Pi Zero 2 W as a USB Ethernet Gadget Router on Raspberry Pi OS Bookworm (2025)

The Raspberry Pi Zero 2 W can act as a USB Ethernet device when connected to a host computer. This makes it possible to create a fully isolated, point‑to‑point network link over USB — ideal for headless access, provisioning, or embedded deployments.

Raspberry Pi OS Bookworm introduced changes to the boot partition layout and USB subsystem, so older tutorials no longer work. This guide shows the correct, modern procedure for Bookworm (2023+), including how to:

  • Enable USB gadget mode
  • Expose a USB Ethernet interface to the host
  • Assign the Pi a static IP
  • Run a DHCP server
  • Provide routing, NAT, and DNS to the host
  • Use a clean CGNAT /30 network for isolation

The result is a Pi Zero 2 W that behaves like a small router over USB — similar to Android USB tethering — but with deterministic addressing and no external dependencies.

1. Hardware Setup

The Pi Zero 2 W has two micro‑USB ports:

  • USB (inner port): data + OTG
  • PWR IN (outer port): power only

For gadget mode, always connect the host to the USB port.

A data‑capable micro‑USB cable is required. Many cables are charge‑only and will not work.

2. Enable USB Gadget Mode (Bookworm Paths)

Bookworm stores boot configuration files under:

Code

/boot/firmware/

Edit /boot/firmware/config.txt

Add inside the [all] section:

Code

dtoverlay=dwc2,dr_mode=peripheral

The dr_mode=peripheral parameter is mandatory on Bookworm for the Pi Zero family.

Edit /boot/firmware/cmdline.txt

This file must remain a single line.

Insert after rootwait:

Code

modules-load=dwc2,g_ether

Example:

Code

console=serial0,115200 console=tty1 root=PARTUUID=XXXX rootfstype=ext4 fsck.repair=yes rootwait modules-load=dwc2,g_ether quiet splash

This loads:

  • dwc2 — USB OTG controller
  • g_ether — USB Ethernet gadget

3. Configure the USB Network Interface on the Pi

Bookworm defaults to NetworkManager, but systemd‑networkd is the cleanest way to manage gadget interfaces.

Enable systemd‑networkd

Code

sudo systemctl enable systemd-networkd
sudo systemctl start systemd-networkd

Tell NetworkManager to ignore usb0

Create:

Code

/etc/NetworkManager/conf.d/10-ignore-usb0.conf

Contents:

Code

[keyfile]
unmanaged-devices=interface-name:usb0

Restart:

Code

sudo systemctl restart NetworkManager

4. Assign a Static IP and Enable DHCP Server

Use a small CGNAT /30 block for a clean point‑to‑point link. Example network: 100.64.64.64/30

  • Pi: 100.64.64.65
  • Host: 100.64.64.66

Create /etc/systemd/network/usb0.network

Code

[Match]
Name=usb0

[Network]
Address=100.64.64.65/30
DHCPServer=yes

Create /etc/systemd/network/usb0.dhcpserver

Code

[DHCPServer]
PoolOffset=1
PoolSize=1
EmitDNS=yes
DNS=8.8.8.8
EmitRouter=yes

Restart:

Code

sudo systemctl restart systemd-networkd

After reconnecting USB, the host will receive:

  • IP: 100.64.64.66
  • Router: 100.64.64.65
  • DNS: 8.8.8.8

5. Enable Routing and NAT on the Pi

To let the host reach the internet through the Pi’s Wi‑Fi, enable IPv4 forwarding and NAT.

Enable IPv4 forwarding

Edit:

Code

sudo nano /etc/sysctl.conf

Add or uncomment:

Code

net.ipv4.ip_forward=1

Apply:

Code

sudo sysctl -p

Configure NAT using nftables

Bookworm uses nftables by default.

Edit:

Code

sudo nano /etc/nftables.conf

Add a NAT table:

Code

table ip nat {
    chain prerouting {
        type nat hook prerouting priority -100;
    }

    chain postrouting {
        type nat hook postrouting priority 100;
        oifname "wlan0" ip saddr 100.64.64.64/30 masquerade
    }
}

Enable:

Code

sudo systemctl enable nftables
sudo systemctl restart nftables

This rewrites packets from the host so they appear to come from the Pi’s Wi‑Fi IP.

6. Connect the Pi to the Host

Plug the Pi’s USB port into the host using a data‑capable cable.

The host will detect a new USB Ethernet interface:

  • Linux: enx…
  • macOS: enX
  • Windows: “RNDIS/Ethernet Gadget”

The host receives:

Code

100.64.64.66

The Pi remains reachable at:

Code

100.64.64.65

Test connectivity from the host:

Code

ping 100.64.64.65
ping 8.8.8.8
ping google.com

All should succeed.

7. Routing Behavior on the Host

The Pi’s DHCP server assigns a high metric to the USB default route (e.g., 20100). This ensures the host prefers its normal network (Wi‑Fi/Ethernet) and only uses the Pi as a fallback.

Example routing table:

Code

default via 172.19.19.1 dev wlp3s0 metric 600
default via 100.64.64.65 dev enx... metric 20100
100.64.64.64/30 dev enx... scope link

This is expected and correct.

8. Result

You now have a fully functional USB‑Ethernet router built into a Raspberry Pi Zero 2 W:

  • Pi boots from the USB data port
  • Pi exposes a USB Ethernet interface
  • Pi assigns the host an IP via DHCP
  • Pi advertises itself as the default route
  • Pi provides DNS
  • Pi NATs traffic from usb0 → wlan0
  • Host can reach the internet through the Pi
  • The USB link remains isolated and deterministic