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 controllerg_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