Running a Raspberry Pi with a read-only root filesystem
dzombak.com
dzombak.com
Both SquashFS and EROFS are filesystem specifically designed for this kind of embedded, read-only use case. The former is optimized for high data density and compression, and already well established. The later is comparatively new and optimized for high read speed.[3] SquashFS as a rootfs can already be found in many embedded applications using flash storage and is typically also combined with tmpfs and persistent storage mount points or overlay mounts.
For both those filesystems, one would build a rootfs image offline. In the Debian ecosystem, there already exists a tool that can bootstrap a Debian image into SquashFS[4].
[1] https://en.wikipedia.org/wiki/SquashFS
[2] https://en.wikipedia.org/wiki/EROFS
[3] https://www.sigma-star.at/blog/2022/07/squashfs-erofs/
[4] https://manpages.debian.org/testing/mmdebstrap/mmdebstrap.1....
I also have a pi running pikvm. You change the filesystem by doing:
# rw <-- makes filesystem read/write
# (change config, or commands making filesystem changes)
# ro <-- back to read-onlyI can't vouch for every single distribution out there, but I've done this successfully on Debian at least.
- Use a power supply that can deliver enough current
- Use good USB cables that can actually carry said current (a lot of people miss this one)
- Do not use cheap SD cards
- Oversize your card so that the card can properly perform wear-levelling.
I have a pair of Raspberry Pi's (2's and/or 3's IIRC) running constantly since 2015. They're running an ancient version of Redsleeve (and are on my list to rebuild but never mind that). DNS, DHCP, and a few other services run on them. They've also survived multiple abrupt powerfail events.
They log to the SD card, and yet I've never had a problem. I personally believe that the fact that I'm using oversized cards with gigabytes of free space is the key. Well, perhaps that and the fact that my personal home directory is on NFS.
Or maybe I'm just lucky? Who knows...
For my own deployments, I ended up doing read only boot from SD card, making use of a ram disk for temporary files, and hosting the actual os on a USB stick, which was much better shielded from power issues. Worked great, never had issues, but the setup was pretty non standard.
The main idea, though, was to set up the os so that the boot folder was on the SD card, with root mounted from the usb drive, and /tmp on a ramfs. Iirc, I would install normally on the SD card, and then copy data to the usb stick and edit the boot files to point where they needed to. And finally, set the SD card to read only mode once everything was settled.
I think there's better options for all of this on more recent pi's, though. I think you can just boot directly from USB now, for example, instead of relying on the SD card.
Got a USB cable tester and found both had cables with 1+ Ohms resistance, which would cause drop to less than 4V under load!
Swapped both cables to some good ones and never had an issue since.
I always use A1 or ideally A2 rated cards from reputable brands bought from reputable stores. Not sure if they help with longevity but the additional IOPS are very noticeable.
The Pis are energy efficient and worth running apps where catastrophic data loss aren't a concern. I use my Pi 1 with DietPi to run AdGuard and my Pi 4 for simple web apps, like dashboards.
But the world has moved forward and there are options like the ODroid that are almost as cheap and energy efficient, without the relying on an SD card. I run my Home Assistant off my ODroid with nvme. They are all backed up to a couple different places, but my failure expectations are completely different. I fully expect my Pis to just have completely ruined cards one day, whereas I am more worried about a bad update to my Home Assistant server.
for stuff that has to be more reliable, I use openwrt (pi + ntp + usb gps + rtc => a standalone ntp server)
Or maybe I'm just lucky also.
Yes, but then the budget then quickly rises to a point where a compact desktop such as a used Intel NUC is cheaper, on top of being far more powerful.
So you reduce the chance of SD failure but introduce a risk of network failure. Of course, network failure doesn't have to be fatal but you won't have any logs to know what happened.
In my experience the chance of one of my Pi's not being able to access the network for one reason or another is much larger than a failed SD card, so I keep my logs on the card.
I think this is half of the problem: SDHC does not require wear-leveling at all, I am unsure of SDXC. But regardless, the wear-levelling algorithm the SD card firmware does is completely invisible, from some vendors it might do a decent job, from some it might be a no-op, we have no way to tell.
The only way to know you're getting wear-levelling is to do it at an OS level, e.g. UBIFS stacked on MTD emulation - but there's a bunch of assumptions there which make it unsuitable for SD cards.
It's just a few lines of code in initramfs!
--- a/usr/share/initramfs-tools/scripts/local 2021-11-05 12:50:23.541088057 +0100
+++ b/usr/share/initramfs-tools/scripts/local 2021-11-05 13:02:14.483203576 +0100
@@ -180,9 +180,20 @@
# Mount root
# shellcheck disable=SC2086
- if ! mount ${roflag} ${FSTYPE:+-t "${FSTYPE}"} ${ROOTFLAGS} "${ROOT}" "${rootmnt?}"; then
- panic "Failed to mount ${ROOT} as root file system."
- fi
+ #if ! mount ${roflag} ${FSTYPE:+-t "${FSTYPE}"} ${ROOTFLAGS} "${ROOT}" "${rootmnt?}"; then
+ # panic "Failed to mount ${ROOT} as root file system."
+ #fi
+
+ mkdir --parents /tmp/diskroot
+ mount -t ${FSTYPE} ${roflag} ${ROOTFLAGS} ${ROOT} /tmp/diskroot
+
+ mount -t tmpfs -o size=6G none ${rootmnt?}
+ chmod 755 ${rootmnt}
+
+ cp --force --archive --verbose /tmp/diskroot/* ${rootmnt}
+
+ umount /tmp/diskroot
+ rm -r --force /tmp/diskroot
}
local_mount_fs()
and `update-initramfs -u`.Or if you set rootfstype=ramfs, then you can take up to all of physical RAM, but ramfs isn't swappable.
Initramfs (and tmpfs) are swappable right? As you say, ramfs is the one that isn't swappable. So if your initramfs is "to big" can't it just be swapped out?
It makes sense if you replace "initramfs" with "initrd":
> One pitfall of this is that the decompressed contents of your ~initramfs~ _initrd_ must fit within half of your physical RAM since Linux decompresses it into a tmpfs. > Or if you set rootfstype=ramfs, then you can take up to all of physical RAM
Use an USB Flash drive mounted as a R/W filesystem for logs, etc. fsck can usually recover those f/s when crashed. The root f/s remains intact.
However, where-ever systemd is the init one can do it via adding to the kernel command line
systemd.volatile=overlay
"If this setting is set to "overlay" the root file system is set up as "overlayfs" mount combining the read-only root directory with a writable "tmpfs", so that no
modifications are made to disk, but the file system may be modified nonetheless with all changes being lost at reboot."See man 7 kernel-command-line for the other volatile mode options.
I could do so much more with this resource, but I'm honestly quite happy with it as it is.
I had a Pi3b run ADS-B (generally RTL-SDR) for many years. Dang though, all with (seemingly) random SD storage failures. Article details seems like it can help.
There are more options now though. Aarch64 ones that use eMMC.
I replaced the Pi3b with a Pine64 Rock64 running FreeBSD 14 booting from eMMC. Simple and just works with all RTL-SDR needs covered.
It's great to have options, both hw and os.
I use the overlayfs provided by raspi-config.
(The same way undoes read-only mode, but two reboots will be required instead of one.)
I can't find an authoritative source, but some quick Googling brings up websites like Reddit and Stackexchange saying that SD cards have ~100,000 lifetime write cycles. I feel like it would be hard to exhaust that.
Is this a real problem people experience?
That’s what setting a read-only root file system prevents in a roundabout way, so people have started to misidentify it as the solution.
It's not the flash endurance you hit typically, but bugs in the card firmware that cause the FTL to completely lose it's mind. Yes, even with supposedly quality brands.
About the only way I found to deal with the problem is to use "industrial" SD cards that are a little slower and pretty expensive, but the firmware takes less liberties in the name of specious benchmarks.
I'm using it on 10 year old Pi's with USB RS485 dongles to get Ethernet access to solar equipment.
Having a kick ass fs at your back is great. Go for it!
One of my persistently greatest annoyances about running stuff on pis has been that journald is so monolithic. There's no per-app controls. I'd love to log most system functions persistently with decent sized history (since they are very low volume), but have the main app or another app do something else. Struggling to find them ATM, but there are a number of issues opened around this way back, and all closed, saying to run multiple systemd-journal instances then configure apps to direct traffic to each, but that sure sucks to setup & configure, & is something I'd hope journald would help me with out of the box.
I've since then switched to using only Toshibha memory cards in RPi & haven't had any failures.
Unfortunately, some software is database-oriented and likes to write to disk for every tiny thing, so the approach doesn't work with stuff like Home Assistant unless you carefully configure logging.
The basic simple stuff doesn't really cause any user-level noticable changes:
https://github.com/EternityForest/KaithemAutomation/blob/mas...
After that, I disable and mask apt-daily (The Debian auto updater), and purge dphys-swapfile.
My full set of assorted tweaks can be found here, some might not be relevant for you:
https://github.com/EternityForest/KaithemAutomation/blob/mas...
Next, I often run Chromium as a kiosk, and Chromium likes to hammer the SD card, so I set the XDG folder environment variables to make it put it's stuff in RAM. My embedded chrome stuff can be found here:
https://github.com/EternityForest/KaithemAutomation/blob/mas...
With all these tweaks, a Pi will have excellent reliability without losing the benefits of a writable FS. If you need true industrial grade perfect reliability, you probably need an industrial card and maybe true a read-only system.
https://github.com/hcfman/sbts-aru
It will shrink your partitions, add new ones and install one of these and set up a sub micro second system clock and an audio recorder suitable for sound localization with a single install command. Works on all versions of Pi in both raspbian and bookworm.
If you don’t need the recorder just turn it off but you have a rootfs, a swap fs, a config fs and a disk fs.
I would argue that /var is kinda explicitly for writing stuff to, so I would mount a tmpfs overlay on top of it as a more durable solution than mounting tmpfs on explicit directories inside it.
In fact, I am interested in how the procedure in this article compares to just slapping a tmpfs overlay on top of the whole system? Could be interesting to compare.
Just putting it here in case anyone have similar blogs/articles I can read about that goes through the same journey.