To increase flash lifetime and avoid problems with unexpected power cuts, I run all of my embedded Linux systems from a readonly root filesystem. I find this to be easier than setting up an overlayfs.
This page lists all useful or necessary tweaks I know about. I intend to update it every now and then.
/etc/fstab needs to specify that
/ be mounted readonly.
/var/log must always be writable in my case, so they each get a
tmpfs. Depending on your distribution, this might already be the case --
otherwise, you'll probably need something along the following lines.
PARTUUID=12345678-02 / ext4 defaults,noatime,ro 0 1 tmpfs /tmp tmpfs auto,noatime 0 0 tmpfs /var/log tmpfs auto,noatime,mode=0755 0 0
Note that tmpfs uses half the available memory as size by default.
PrivateTmp=yes do not work on a readonly filesystem.
This affects services such as systemd-timesyncd and can be remedied by running
systemctl edit systemd-timesyncd and pasting the following lines.
[Service] PrivateDevices=no PrivateTmp=no
You may also need to create tmpfs mountpoints for state files, e.g. for systemd-timesyncd:
tmpfs /var/lib/systemd/timesync tmpfs auto,noatime,size=5m,mode=0755,uid=100,gid=103 0 0
Replace 103/100 with UID/GID of your
logrotate keeps state in
/var/lib/logrotate and may not work if it can't
tmpfs /var/lib/logrotate tmpfs auto,noatime,size=1m,mode=0755 0 0
mpd won't start if
/var/log/mpd doesn't exist, so it must be created after
mounting the tmpfs on
/var/log. It may also be necessary to create
/etc/tmpfiles.d/munin-node.conf with the following
d /var/log/mpd 0755 mpd audio - - d /run/mpd 0755 mpd audio - -
Recent mpd versions also appear to write to
tmpfs /var/lib/mpd tmpfs auto,noatime,size=10m,mode=0755,uid=112,gid=29 0 0
Replace 112/29 with the UID of
mpd and the GID of
munin-node keeps plugin state in
/var/lib/munin-node/plugin-state. If you're lazy,
you can symlink that to
/tmp, but a tmpfs is a better solution.
tmpfs /var/lib/munin-node/plugin-state tmpfs auto,noatime,mode=0755 0 0
Also, munin-node will fail if
/var/log/munin-node doesn't exist, so it must
be created after mounting the tmpfs on
d /var/log/munin 0755 munin adm - -
ntpd stores state in
/var/lib/ntp, so it should be a tmpfs.
tmpfs /var/lib/ntp tmpfs auto,noatime,size=1m,mode=0755,uid=106,gid=111 0 0
Replace 106/111 with UID/GID of your
Note that this does not apply if you use ntpdate instead of ntp.
pulseaudio has runtime state in
contains a symlink to a cookie in
/tmp that is updated occasionally).
The latter can be remedied by setting
XDG_CONFIG_HOME for all pulseaudio
processes, though I prefer using tmpfs for both.
tmpfs /var/lib/pulse tmpfs auto,noatime,size=1m,uid=110,gid=114,mode=0700 0 0 tmpfs /home/spotifyd/.config/pulse tmpfs auto,noatime,size=1m,uid=1001,gid=1001,mode=0700 0 0
Replace 110/114 with UID/GID of your
pulse user and
1001 with UID/GID of
each user using pulseaudio.
Some of my readonly systems have a tmpfs on
/var/spool/rsyslog, though I'm
not sure how important that is. Anyways, the following
/etc/fstab line may
tmpfs /var/spool/rsyslog tmpfs auto,noatime,mode=0755 0 0
sudo stores the timestamp of the last successful authentication in
/var/lib/sudo, which should be writable.
tmpfs /var/lib/sudo tmpfs auto,noatime,size=1m,mode=0700 0 0