Read-Only Root Filesystem on Pi Zero with Overlay FS for Reliability

The most common way a deployed Raspberry Pi dies is not a hardware fault but a corrupted microSD card. Pull the power while Linux is writing, and a file or the whole filesystem can be damaged. Constant small writes from logs also wear out the flash cells over months. For a Pi Zero hidden inside a kiosk, a vehicle, a solar logger or a product prototype that people simply unplug, this is a real problem.

The solution is to stop writing to the card. In this tutorial you will first reduce writes with a RAM-based /var/log and volatile journal, then enable the full overlay filesystem built into raspi-config, which makes the root filesystem read-only and stores every change in RAM. You will also learn the workflow for updating a protected device and where to keep data that must survive a reboot.

How the Overlay Filesystem Works

OverlayFS is a Linux kernel feature that merges two directories into one view. The lower layer is the real root partition on the SD card, mounted read-only. The upper layer is a tmpfs in RAM. When a program reads a file, it sees the SD card version unless the file has been changed. When a program writes, the change goes to the RAM layer. Programs do not know the difference; they see a normal writable system.

At reboot the RAM layer vanishes, so the system always starts from the exact state stored on the card. Even if power is cut a thousand times, nothing on the SD card is being written, so nothing can be corrupted.

ApproachProtects against corruptionChanges survive rebootEffort
Normal read-write systemNoYesNone
Logs in RAM only (tmpfs, volatile journal)Partly, fewer writesYes, except logsLow
Overlay filesystem on rootYes, root never writtenNoLow, with raspi-config
Overlay plus read-only boot partitionYes, both partitions protectedNoLow, with raspi-config

Step 1: Reduce Writes Without Going Read-Only

If you still need to change files occasionally, simply moving logs into RAM removes most background writes. Logs are then lost at reboot, which is usually acceptable for a field device.

Keep /var/log and the systemd journal in RAM
# Mount /var/log as a 32 MB RAM disk at boot
echo 'tmpfs /var/log tmpfs defaults,noatime,nosuid,nodev,mode=0755,size=32m 0 0' | sudo tee -a /etc/fstab

# Make journald keep logs only in memory
sudo mkdir -p /etc/systemd/journald.conf.d
printf '[Journal]\nStorage=volatile\nRuntimeMaxUse=16M\n' | sudo tee /etc/systemd/journald.conf.d/volatile.conf

# Disable swap, which writes to the SD card under memory pressure
sudo systemctl disable --now dphys-swapfile 2>/dev/null || true

sudo reboot

# After reboot, confirm
findmnt /var/log
journalctl --header | grep -i 'file path'

Swap deserves a mention. Raspberry Pi OS has traditionally used a swap file managed by dphys-swapfile; newer releases may manage swap differently. Whatever the mechanism, swapping to the SD card means heavy writes, so check with swapon --show and disable it on a device where reliability matters.

Step 2: Enable the Overlay Filesystem

Finish installing and configuring everything first: packages, your Python program, its systemd service, Wi-Fi networks. Then enable the overlay. Interactively, run sudo raspi-config and choose Performance Options, then Overlay File System, answer Yes to enable the overlay and Yes to make the boot partition read-only. The same can be scripted:

Enable, check and disable the overlay from the command line
# Enable the overlay on root and make /boot/firmware read-only
sudo raspi-config nonint enable_overlayfs
sudo raspi-config nonint enable_bootro
sudo reboot

# After reboot: root should be an overlay, boot should be 'ro'
findmnt /
findmnt /boot/firmware

# Quick test: create a file, reboot, and it is gone
touch ~/test-file && ls ~/test-file

# To make permanent changes, turn protection off first
sudo raspi-config nonint disable_overlayfs
sudo raspi-config nonint disable_bootro
sudo reboot

On Bookworm, raspi-config installs and configures the overlayroot package to do this, adding an option to the kernel command line and rebuilding the initramfs. That is why enabling or disabling it always needs a reboot, and why the first enable can take a minute on a Zero.

Updating a Protected Device

  1. Disable the overlay and boot protection, then reboot.
  2. Make the changes: sudo apt update && sudo apt full-upgrade, edit configuration, copy new code.
  3. Test that the device works normally.
  4. Enable the overlay and boot protection again, then reboot and confirm with findmnt /.

Where to Keep Data That Must Survive

A sensor logger still needs to keep its readings. Good options are:

  • Send it away: publish readings over MQTT or HTTP as they are taken, so nothing needs to be stored locally.
  • A USB flash drive: mount it read-write on the OTG port with an adapter. If it is corrupted, the system still boots and the drive can be replaced.
  • A separate data partition: create a third partition on the SD card when preparing the card on a Linux machine, and mount it read-write with the noatime option. Write in occasional batches and call fsync after each batch.
  • Batch then write: keep readings in RAM and write them to persistent storage once an hour, reducing both wear and the window for corruption.

Troubleshooting

  • My changes keep disappearing: that is the overlay working. Disable it before making permanent changes.
  • System becomes slow, then programs crash after days of running: the RAM layer is full. Check with df -h / and find what is writing with sudo du -xh /media/root-rw 2>/dev/null | sort -h | tail or by reviewing your program's file output.
  • Cannot edit config.txt: the boot partition is read-only. Disable boot protection first.
  • Time is wrong after each reboot: the Zero has no real-time clock. It syncs time over the network, so devices without network access need an RTC module.

Summary

Moving logs into RAM reduces SD card wear, and the overlay filesystem from raspi-config removes the corruption risk completely by never writing to the root partition. Configure everything first, enable the overlay and read-only boot, keep persistent data on a separate partition, a USB drive or a remote server, and disable protection only while you update. This turns a Pi Zero into an appliance that can be unplugged at any time.