Filesystem: tmpfs and no swap#

Why#

A microSD card has a limited number of writes before it degrades. System logs, in particular, generate continuous writes. The approach here: move everything volatile (logs, temp directories) into RAM via tmpfs, and accept the trade-off, this data is lost on every reboot. For a time server, that’s a reasonable compromise: what matters is the current state, not the log history.

How#

/etc/fstab#

cp -a /etc/fstab /etc/fstab.bak
tmpfs   /tmp        tmpfs   defaults,noatime,nosuid,size=100m           0 0
tmpfs   /var/tmp    tmpfs   defaults,noatime,nosuid,size=100m           0 0
tmpfs   /var/log    tmpfs   defaults,noatime,nosuid,mode=0755,size=256m 0 0
tmpfs   /var/nts    tmpfs   defaults,noatime,nosuid,mode=0755,size=16m  0 0
tmpfs   /var/time   tmpfs   defaults,noatime,nosuid,mode=0755,size=64m  0 0
  • noatime on the root filesystem: removes the systematic write of read timestamps, a quiet but continuous source of wear.

The sizes (size=) are based on observed usage, not picked at random: 100m for /tmp and /var/tmp comfortably covers the temp files from a package install or a certbot renewal, without ever weighing on the Pi 5’s available RAM (4 or 8 GB) as long as that space isn’t actually used (lazy allocation, see below). 256m for /var/log has to cover nginx logs, auditd’s own internal rotation (capped at 32 MB max, System hardening chapter), and journald all at once, with a comfortable margin. 64m for /var/time (Munin and Public telemetry chapters) is deliberately more modest: this mount point only holds small PNG graphs and a periodically regenerated text stats file, never a history that grows without bound. 16m for /var/nts (NTS keys and cookies, Chrony chapter) is the most modest of all: a tenfold margin over the volume actually observed, on the order of a hundred KiB.

/etc/tmpfiles.d/: rebuilding the tree on every boot#

A tmpfs is empty on every startup. Without explicitly rebuilding the expected directories, several services (auditd, nginx) simply refuse to start.

# nginx - logs on tmpfs /var/log
d /var/log/nginx       0750 -      -      -
f /var/log/nginx/error.log  0664  -      -      -
f /var/log/nginx/access.log 0664  -      -      -

# auditd refuses to start if /var/log/audit/ is missing
d /var/log/audit       0750 root   root   -
systemctl daemon-reload
mount -a
systemd-tmpfiles --create /etc/tmpfiles.d/orlinum.conf

Pitfalls to avoid#

A rule referencing a system user that doesn’t exist yet fails the entire tmpfiles.d application. If a rule references a user created by a package not yet installed (e.g. a system account specific to some daemon), systemd-tmpfiles fails with Failed to resolve user '...'. Fix: install the relevant package first, or re-apply the tmpfiles.d rules afterward.

  • Sizing tmpfs at random. A size that’s too small causes writes to silently fail once the quota is hit (the service keeps running, but the most recent log entries just disappear). Size against an observed need, with a comfortable margin, tmpfs allocation is lazy: RAM is only consumed proportional to actual usage, so a generous max size costs nothing until it’s reached.
  • Forgetting that logs disappear on reboot. This is a deliberate trade-off, not an oversight, but this setup no longer fits as-is once persistent log history is required for compliance/traceability reasons: logs would then need to be streamed continuously to a remote system. rsyslog, the classic and proven tool for this job (forwarding to a log collector, including over an encrypted channel), is a lead to follow; setting it up is out of scope for this guide, and interested readers will find plenty of useful documentation online.

Verify#

findmnt -t tmpfs
# Should list /tmp, /var/tmp, /var/log, /var/nts, /var/time

df -h /var/log /var/nts /var/time
# Confirms actual usage, usually very low under normal conditions (1-3%)

ls -ld /var/log/nginx /var/log/audit
# Directories should exist with correct ownership after a reboot

The most telling test: reboot the server and check that all relevant services start normally, proof that tmpfiles.d reconstruction happens in the correct order relative to tmpfs mounting.