Zum Inhalt

Read-Only RootFS & Stromausfallsicherheit

In industriellen Umgebungen und IoT-Installationen werden Einplatinencomputer häufig an Orten betrieben, an denen ein sauberes Herunterfahren über sudo poweroff in der Praxis nicht stattfindet. Gabelstapler trennen Batterieladestationen, Sicherungen im Schaltschrank lösen aus oder Techniker ziehen ohne Vorwarnung den Netzstecker.

Auf einem standardmäßig beschreibbaren Linux-System führen abrupte Stromausfälle während laufender Schreibvorgänge zu unvollständigen Journal-Einträgen im ext4-Dateisystem, zerstörten Superblöcken und Inkonsistenzen im Flash Translation Layer (FTL) der Speicherkarte. Binnen weniger Wochen schlägt der Bootvorgang fehl, das System bootet nur noch in eine Notfall-Shell oder die SD-Karte ist physisch unbrauchbar.

Indem Raspberry Pi OS mithilfe von OverlayFS und tmpfs in eine zustandslose Read-Only-Appliance verwandelt wird, finden im laufenden Betrieb keinerlei Schreibzugriffe auf das Speichermedium statt. Das System wird damit zu 100 % immun gegen plötzliche Stromausfälle.


1. Schadensmechanik: Warum Stromausfälle Flash-Speicher zerstören

Um die Notwendigkeit eines unveränderlichen Dateisystems zu verstehen, lohnt sich ein Blick auf die physikalischen Vorgänge im Flash-Speicher bei plötzlichem Spannungsverlust:

%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
    subgraph Danger["Klassisches beschreibbares OS (Gefaehrdet)"]
        direction TB
        W1["Anwendung schreibt Daten"] --> W2["Page Cache (RAM)"]
        W2 -->|Verzoegerter Flush| W3["ext4 Dateisystem-Journal"]
        W3 -->|NAND-Schreibzyklus| W4["Speichermedium (SD/NVMe)"]
        POWER1["Ploetzlicher Stromausfall!"] -.->|Unterbricht Schreibzyklus| W4
        W4 ==> CORRUPT["Beschaedigter Superblock /<br/>Dateisystem defekt"]
    end

    subgraph Safe["OverlayFS-Architektur (Ausfallsicher)"]
        direction TB
        RO_BASE["Unterste Ebene (Flash):<br/>Strikter READ-ONLY Mount"]
        RAM_UPPER["Oberste Ebene (tmpfs im RAM):<br/>Alle dynamischen Daten"]
        OVERLAY["Vereinte Sicht (/):<br/>Transparent fuer systemd & Apps"]
        RO_BASE --> OVERLAY
        RAM_UPPER --> OVERLAY
        POWER2["Stromausfall zu jedem Zeitpunkt!"] -.-> RAM_UPPER
        RAM_UPPER ==> SAFE_REBOOT["RAM leert sich sofort.<br/>Flash unberuehrt, sauberer Boot!"]
    end

    Danger -->|"Haertungsmethode: OverlayFS"| Safe

Die Physik des NAND-Flash-Speichers: Löschblöcke & Verschleiß

Flash-Speicher kann einzelne Speicherzellen nicht direkt überschreiben. Der interne Controller muss stets einen gesamten Löschblock (typischerweise 128 KB bis 4 MB) leeren, bevor neue 4-KB-Seiten programmiert werden können. Bricht die Versorgungsspannung genau in dem Moment ein, in dem die interne Ladungspumpe des Flash-Controllers aktiv ist: 1. Verbleiben Speicherzellen in einem undefinierten Zwischenladungszustand (Partial Write). 2. Geht die Zuordnungstabelle (Flash Translation Layer, FTL) im RAM des Speicherkontrollers verloren. 3. Erkennt der Speichercontroller beim nächsten Start inkonsistente Blockprüfsummen – die Partitionstabelle ist beschädigt oder das gesamte Medium sperrt sich irreversibel im Nur-Lese-Modus.


2. Die Linux-OverlayFS-Architektur

OverlayFS ist ein moderner Union-Mount-Dateisystemtreiber des Linux-Kernels. Er legt zwei verschiedene Verzeichnisse transparent übereinander:

  • Untere Schicht (lowerdir): Das physische Betriebssystem auf der SD-Karte oder NVMe-SSD. Es wird strikt im Read-Only (ro)-Modus gemountet. Physische Schreibvorgänge auf diesen Datenträger sind vom Kernel blockiert.
  • Obere Schicht (upperdir): Ein flüchtiges Dateisystem, das ausschließlich im Arbeitsspeicher (tmpfs) liegt.
  • Zusammengeführte Sicht (merged): Das Wurzeldateisystem (/), das Anwendungen und Dienste sehen.

Modifiziert ein Prozess eine Datei (z. B. Konfiguration in /etc/ oder Installation von Paketen), kopiert der Kernel die Originaldatei in den RAM-Bereich (Copy-on-Write - CoW). Auf dem physischen Festspeicher verändert sich kein einziges Bit. Bei einem Stromausfall verflüchtigt sich der RAM-Inhalt sofort, und beim Neustart startet das System garantiert im ursprünglichen, fehlerfreien Zustand.


3. Umsetzung A: Das native raspi-config Overlay

Für kompakte Edge-Geräte stellt Raspberry Pi OS ein kernelintegriertes OverlayFS-Feature bereit, das direkt per raspi-config aktiviert werden kann.

Schritt 1: System vorbereiten und bereinigen

Vor der Aktivierung sollten temporäre Altlasten und Swap-Dateien bereinigt werden, um unnötigen RAM-Verbrauch zu verhindern:

# Pakete aktualisieren und Paket-Cache leeren
sudo apt update && sudo apt autoremove -y
sudo apt clean

# Swap-Speicher dauerhaft deaktivieren (OverlayFS operiert im RAM)
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo systemctl disable dphys-swapfile

Schritt 2: OverlayFS aktivieren

Befehl im non-interactive Modus ausführen:

# OverlayFS fuer das Root-Dateisystem aktivieren
sudo raspi-config nonint enable_overlayfs

# Optional auch /boot/firmware schreibschuetzen
sudo raspi-config nonint enable_bootro

System neu starten:

sudo reboot

Schritt 3: Schreibschutz überprüfen

Nach dem Wiederverbinden per SSH den Root-Mount prüfen:

mount | grep "on / "

Erwartete Ausgabe:

overlay on / type overlay (rw,noatime,lowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work)

Test auf Stromausfallsicherheit: Datei anlegen und harten Kernel-Absturz simulieren:

# Test-Datei erzeugen
touch ~/stromausfall_test.txt
ls -l ~/stromausfall_test.txt

# Sofortigen, unvorbereiteten Kernel-Neustart erzwingen (entspricht Stecker ziehen)
echo b | sudo tee /proc/sysrq-trigger

Nach dem erneuten Booten das Verzeichnis prüfen:

ls -l ~/stromausfall_test.txt
# Ausgabe: ls: Zugriff auf '...' nicht moeglich: Datei oder Verzeichnis nicht gefunden

Die Datei ist spurlos verschwunden, und der Datenträger hat keinerlei Schäden davongetragen!


4. Umsetzung B: Manuelle tmpfs-Umleitungen in /etc/fstab

Benötigt eine Anwendung gezielte Lese-/Schreibrechte in bestimmten Pfaden, können temporäre Verzeichnisse auch gezielt in /etc/fstab als tmpfs ausgelagert werden.

Datei /etc/fstab bearbeiten:

sudo nano /etc/fstab

Folgende Mount-Punkte für flüchtige Daten im RAM ergänzen:

# Temporaere Verzeichnisse im RAM anlegen
tmpfs   /tmp         tmpfs   nodev,nosuid,size=128M        0  0
tmpfs   /var/tmp     tmpfs   nodev,nosuid,size=64M         0  0
tmpfs   /var/log     tmpfs   nodev,nosuid,size=64M         0  0
tmpfs   /var/run     tmpfs   nodev,nosuid,size=32M         0  0

Systemd Journal auf RAM umstellen

Standardmäßig schreibt systemd-journald Logs auf die Festplatte. Stelle den Dienst so ein, dass er Protokolle nur im RAM vorhält:

sudo nano /etc/systemd/journald.conf

Eintrag anpassen:

[Journal]
Storage=volatile
RuntimeMaxUse=32M

Dienst neu starten:

sudo systemctl restart systemd-journald

5. Wartung im Read-Only-Modus: Updates sicher einspielen

Ein häufiges Hindernis bei schreibgeschützten Systemen ist die Wartung: Wie lassen sich Updates einspielen, ohne das System neu aufzusetzen?

Der ro / rw Wartungs-Workflow

Über zwei kurze Hilfsskripte lässt sich das System kontrolliert zwischen Wartungsmodus und Schutzmodus umschalten.

Skripte /usr/local/bin/ro und /usr/local/bin/rw anlegen:

/usr/local/bin/rw (In den Wartungsmodus wechseln)
#!/usr/bin/env bash
set -euo pipefail

echo "[*] Deaktiviere OverlayFS fuer Wartungsarbeiten..."
sudo raspi-config nonint disable_overlayfs
sudo raspi-config nonint disable_bootro

echo "[+] Wartungsmodus aktiv. Starte neu in beschreibbaren Modus..."
sudo reboot
/usr/local/bin/ro (Schutzmodus reaktivieren)
#!/usr/bin/env bash
set -euo pipefail

echo "[*] Aktiviere OverlayFS Schutzmodus..."
sudo raspi-config nonint enable_overlayfs
sudo raspi-config nonint enable_bootro

echo "[+] System gehaertet. Starte neu in unzerstoerbaren Read-Only Modus..."
sudo reboot

Skripte ausführbar machen:

sudo chmod +x /usr/local/bin/rw /usr/local/bin/ro

Ablauf für Updates:

  1. Per SSH einloggen und rw ausführen (System startet beschreibbar neu).
  2. Updates durchführen: sudo apt update && sudo apt upgrade -y oder Konfigurationen editieren.
  3. Änderungen testen.
  4. ro ausführen (System startet geschützt als Read-Only-Appliance neu).

6. Architektur-Muster: Getrennte Datenpartition

Die meisten Industrie-Anwendungen müssen ausgewählte Daten dauerhaft über Stromausfälle hinweg speichern: TLS-Zertifikate, SQLite-Messwertdatenbanken oder Netzwerkkonfigurationen.

Hierfür wird das Split-Partition-Muster eingesetzt:

%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
    subgraph Disk["Physischer Speicher (NVMe / eMMC / SD)"]
        direction TB
        P1["Partition 1: /boot/firmware<br/>(FAT32, Read-Only)"]
        P2["Partition 2: RootFS /<br/>(ext4, OverlayFS RO + tmpfs)"]
        P3["Partition 3: /data<br/>(ext4, Crash-Resistent RW)"]
    end

    subgraph System["Laufzeitumgebung"]
        direction TB
        OS["Betriebssystem & Programme<br/>(/usr, /bin)"]
        LOGS["System-Logs<br/>(/var/log -> RAM tmpfs)"]
        DB["SQLite Zeitreihen-Datenbank<br/>(/data/telemetrie.db)"]
    end

    Disk --> System
    P2 --> OS
    P3 --> DB
    P2 -.-> LOGS

Robuste Datenpartition einrichten

Partition 3 mit ext4 und maximal robuster Journal-Konfiguration formatieren:

Eintrag in /etc/fstab:

# Robuste Datenpartition fuer Messwerte und Konfiguration
PARTUUID=deine-uuid-03  /data  ext4  noatime,data=journal,commit=1,barrier=1,errors=remount-ro  0  2
  • data=journal: Metadaten und Nutzdaten werden zwingend vor dem Schreiben ins Dateisystem im Journal protokolliert. Verhindert unvollständig geschriebene Dateien bei plötzlichem Stromausfall.
  • commit=1: Schreibt das Journal im Sekundentakt auf den Flash-Speicher (Standard: alle 5 Sekunden).
  • errors=remount-ro: Schaltet die Partition bei einem erkannten Fehler sofort auf schreibgeschützt, um weitere Schäden zu verhindern.

Nächste Schritte

Nachdem das Dateisystem vor Hardware-Stromausfällen geschützt ist, sorgen wir für Ausfallsicherheit bei Software-Hängern: