Make your Raspberry Pi file system read-only (Raspbian Buster)
Raspberry Pi(e)s are often used for kiosk applications where their sole purpose is to serve preloaded HTML5 content from an SD card to its attached HDMI screen. This is a very common setup but at some point you will encounter weird issues resulting from SD card corruption.
This guide was originally created for Raspbian Stretch and has been updated for Raspbian Buster. You can still find the guide for Raspbian Stretch here.
In our case usually after around 6 months we would encounter random crashes and find log messages like this:
end_request: I/O error, dev mmcblk0, sector 148225
mmcblk0: error -110 transfering data, sector 148226, nr 254, response 0x900, card status 0xb00
What is going on here?!
A quick Google search later we knew that these were the typical signs of the SD card going bad. These cards are just not designed for 24/7 operation and will start to accumulate bad sectors after some time.
Also kiosk applications are often not properly shut down but instead simply unplugged. Repeating this increases the risk of file system corruption.
Luckily on Raspbian Buster you can force your file system into “read-only mode”. While in read-only mode the system cannot write any data to your SD card thus significantly prolonging the lifespan of your card.
To achieve this, we need to take the following steps:
- Configure the operating system to write all temporary files to the “tmpfs” file system which resides in memory.
- Configure additional services to also use the tempfs file system.
- Redirect all system log files to memory.
- Add some optional scripts to toggle read-only mode on / off
Let’s get started
Important: You absolutely should create a backup image of your SD card before following this tutorial. I have used this method successfully on countless Pi(e)s, still you use this at your own risk. Don’t blame me if anything goes wrong 😉
Preparations
Log in to your Raspberry via SSH. I recommend you first update your Pi one more time to get all the latest software packages:
$ sudo apt-get update && apt-get upgrade
Do a little housekeeping and remove the following packages. If these were not installed in the first place then just skip this step:
$ sudo apt-get remove --purge triggerhappy logrotate dphys-swapfile
Clean up your packages:
$ sudo apt-get autoremove --purge
Disable swap and filesystem check and set it to read-only
Edit the file /boot/cmdline.txt
and add the following three words at the end of the line:
fastboot noswap ro
This line should now look similar to this:
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait fastboot noswap ro
Replace your log manager
We want to avoid writing any system log files to the SD Card. Therefore we will remove the standard syslog output of log files to /var/log
and instead replace it with the busybox in-memory logger:
$ sudo apt-get install busybox-syslogd
$ sudo apt-get remove --purge rsyslog
Hint: From now on use sudo logread
to check your system logs.
Make the file-systems read-only and add the temporary storage
Update the file /etc/fstab
and add the ,ro
flag to all block devices. The updated file should look like this:
proc /proc proc defaults 0 0
PARTUUID=fb0d460e-01 /boot vfat defaults,ro 0 2
PARTUUID=fb0d460e-02 / ext4 defaults,noatime,ro 0 1
Also add the entries for the temporary file system at the end of the file:
tmpfs /tmp tmpfs nosuid,nodev 0 0
tmpfs /var/log tmpfs nosuid,nodev 0 0
tmpfs /var/tmp tmpfs nosuid,nodev 0 0
Move some system files to temp filesystem
Note: This part is different from previous Raspbian versions (Stretch etc.). On Raspbian Buster do NOT move the
/var/lock
and/var/run
directories as they are already symlinked totmpfs
directories. You can read more about these changes in the Debian Buster tmpfs documentation.
$ sudo rm -rf /var/lib/dhcp /var/lib/dhcpcd5 /var/spool /etc/resolv.conf
$ sudo ln -s /tmp /var/lib/dhcp
$ sudo ln -s /tmp /var/lib/dhcpcd5
$ sudo ln -s /tmp /var/spool
$ sudo touch /tmp/dhcpcd.resolv.conf
$ sudo ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf
Update the systemd random seed
Link the random-seed file to the tmpfs
location:
$ sudo rm /var/lib/systemd/random-seed
$ sudo ln -s /tmp/random-seed /var/lib/systemd/random-seed
Edit the service configuration file /lib/systemd/system/systemd-random-seed.service
to have the file created on boot. Add the line ExecStartPre=/bin/echo "" >/tmp/random-seed
under the [Service]
section.
The modified [Service]
section should look like this:
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/bin/echo "" >/tmp/random-seed
ExecStart=/lib/systemd/systemd-random-seed load
ExecStop=/lib/systemd/systemd-random-seed save
TimeoutSec=30s
At this point after rebooting you should have a working Raspberry Pi in read-only mode 👋 👋 👋. Cheers to that🍺!
Optional: Adding some useful commands to switch between RO and RW modes
This step is optional but makes switching between read-only and read-write mode much more convenient in case you need to update or debug your system.
Here we create two shell commands ro
(read-only) and rw
(read-write) which can be used at any time to switch between the modes. In addition it will add an indicator to your command prompt to show the current mode.
Edit the file /etc/bash.bashrc
and add the following lines at the end:
set_bash_prompt() { fs_mode=$(mount | sed -n -e "s/^\/dev\/.* on \/ .*(\(r[w|o]\).*/\1/p") PS1='\[\033[01;32m\]\u@\h${fs_mode:+($fs_mode)}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
}alias ro='sudo mount -o remount,ro / ; sudo mount -o remount,ro /boot'alias rw='sudo mount -o remount,rw / ; sudo mount -o remount,rw /boot'PROMPT_COMMAND=set_bash_prompt
Finally ensure the file system goes back to read-only once you log out. Edit (or create) the file /etc/bash.bash_logout
and add the following lines at the end:
mount -o remount,ro /
mount -o remount,ro /boot
You’re done! Now just reboot the system:
$ sudo reboot
❤️ Thank you very much for reading! I️f you have any comments or suggestions, please start a conversation in the comments. ❤️