Part of the Raspberry Pi Reliability series.
The first issue you’re likely to hit with a long-running Pi, particularly with a Raspberry Pi Zero, is the Pi dropping off your WiFi network for no apparent reason after days or just hours of operation.
The information in this post is, to the best of my knowledge, current as of November 2023. It should work on Raspberry Pi OS versions bullseye and bookworm, at least, but I make no promises.
Fortunately, this is one of the easiest problems to watch for. Tell your favorite monitoring software — I use Uptime Kuma at home — to ping the Pi on a regular basis and alert you if it stops responding for more than a couple minutes.
The Pi will need to have a static IP, DHCP reservation, or a consistent name (maybe a
.local name, via mDNS) to use for monitoring.
I’ll briefly note a few possible causes:
- The Pi’s WiFi chip has a “low power” mode, but anecdotally it (or its firmware) handles this more poorly
- “Advanced” WiFi features on your WiFi router may be messing with the Pi’s WiFI connection
- In a WiFi network with multiple access points, the Pi might be switching between them often for some reason
- The Pi may not have a good WiFi signal, or some environmental factors are affecting its connection
- idk, there’s so much that can go wrong with a WiFi connection, I’m not listing it all here
These fixes are not without risk, and you should only use any given intervention if you understand it and what it will do. (See my Pi Reliability post on risk vs. benefits.)
This feels like a hack, but based on hours of reading online discussions, most people seem to settle on a script that periodically checks whether the WiFi connection is good, and restarts the WiFi interface or the whole Pi if it’s not.
I’ve written what I think is the best possible version of this hack: my
wifi-check.sh script starts by disabling the WiFi chip’s low power mode, then checks to see if that worked, and escalates from there to more extreme measures.
You can grab the latest version of the script from my dotfiles repository. Place it at
/usr/local/bin/wifi-check.sh, or wherever you prefer.
When scheduling it to run, it’s important to use
flock to ensure there’s only ever a single copy of the script running. I schedule it by placing the following content at
* * * * * root flock -x -n -E 0 /tmp/wifi-check.lock env PING_TARGET=192.168.1.1 WLAN_IF=wlan0 /usr/local/bin/wifi-check.sh
Note that if this script reboots the machine while you're performing maintenance or upgrades, your Pi could be left in a broken state. Disable this cron job before doing any risky maintenance.
To reduce the risk of this intervention, I also disable automatic updates; see this post on disabling/removing unneeded software.
The Raspberry Pi’s little-known watchdog feature can monitor a network interface and reboot the Pi if … something bad happens? I haven’t been able to figure out exactly what about the interface it watches for, but I’m enabling this feature on my Pi Zeros, figuring it can’t hurt.
After setting up the watchdog — for which I’ll refer you to my Pi Reliability post on hardware/firmware issues — you can tell it to watch your WiFi interface by adding the following line to
interface = wlan0
The watchdog also has a “ping mode,” but I think my
wifi-check script is a much more graceful and customizable way to handle ping failures. See
watchdog.conf(5) for more.
Anecdotally, I think disabling the client steering feature on my Eero home network helped my Pi Zeros stay online more consistently. I don’t have enough data to say this definitively, though.
Disabling other “advanced” WiFi features, especially those that try to encourage clients to switch WiFi bands or access points, may help too.
This is unlikely to do anything unless you’re hitting some unusual bug, but it’s worth noting that IPv6 has, in the past, led to all sorts of strange behaviors in different networking contexts. (Disabling IPv6 on a device that lives on your home WiFi network is also unlikely to break anything.)
You can try disabling IPv6 by writing this to the file
/etc/sysctl.d/90-disable-ipv6.conf, then rebooting:
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1