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.baktmpfs /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 0noatimeon 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.confPitfalls to avoid#
A rule referencing a system user that doesn’t exist yet fails the entire
tmpfiles.dapplication. If a rule references a user created by a package not yet installed (e.g. a system account specific to some daemon),systemd-tmpfilesfails withFailed to resolve user '...'. Fix: install the relevant package first, or re-apply thetmpfiles.drules afterward.
- Sizing
tmpfsat 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,tmpfsallocation 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 rebootThe 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.