Make your Raspberry Pi file system read-only (Raspbian Buster)

Andreas Schallwig
Sep 24 · 4 min read

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:

  1. Configure the operating system to write all temporary files to the “tmpfs” file system which resides in memory.
  2. Configure additional services to also use the tempfs file system.
  3. Redirect all system log files to memory.
  4. 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 to tmpfs 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. ❤️

The Startup

Medium's largest active publication, followed by +537K people. Follow to join our community.

Andreas Schallwig

Written by

Co-founder of multiple IT start-ups, passionate about blinking stuff, computers and cooking. Currently working as Technical Director at mediaman in Shanghai.

The Startup

Medium's largest active publication, followed by +537K people. Follow to join our community.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade