Raspberry Pi Security Setup
Nach der kompletten Neuinstallation wollte ich den Raspberry Pi 5 nicht direkt als Experimentiermaschine nutzen. Erst sollte die Basis stimmen: klarer SSH-Zugang, kein Passwort-Login, Firewall, automatische Updates und nur das Netzwerk, das wirklich gebraucht wird.
Der Pi soll mein lokales Lab für KI-Experimente und Agent-Harnesses werden. Die Website selbst wird weiter lokal auf der Workstation gebaut. Der Raspberry Pi ist dafür die Experimentierumgebung, nicht der Webserver für newwaves.dev.
Ausgangspunkt
Nach der Neuinstallation hatte der Pi den Hostnamen raspberrypi5 und eine feste lokale IP über die DHCP-Reservierung im Router. Gearbeitet wird über einen normalen Benutzer mit sudo, nicht direkt als Root.
hostname: raspberrypi5
ip: feste DHCP-Reservierung im Heimnetz
user: normaler sudo-Benutzer
system: Debian/Raspberry Pi OS, aarch64
Zuerst habe ich geprüft, ob der Benutzer wirklich der Admin-User ist und nicht direkt als Root gearbeitet wird.
whoami
id
groups
sudo whoami
sudo -l
Das Ergebnis war genau richtig: Der Benutzer ist ein normaler Account, Mitglied der Gruppe sudo und kann administrative Befehle über sudo ausführen.
Gleiche Checkliste, anderes Spielfeld
Für meinen VPS habe ich bereits ein Security Setup dokumentiert, und der Plan war: Checkliste rausholen, abarbeiten, fertig. Ganz so einfach war es nicht, denn das Bedrohungsmodell ist ein anderes. Ein VPS steht mit öffentlicher IP direkt im Internet und wird ab der ersten Minute gescannt. Der Pi steht hinter dem Router im Heimnetz: Solange dort keine Portfreigabe existiert, ist er von außen schlicht nicht erreichbar. Die dichteste Außengrenze ist der Router selbst. Deshalb übersetzt sich die VPS-Checkliste nicht eins zu eins, und der Router gehört mit auf die Liste, dazu unten mehr.
SSH-Keys statt Passwort
Bevor ich Passwort-Logins abschalte, brauche ich funktionierende SSH-Keys. Deshalb kamen zuerst zwei getrennte Zugänge in authorized_keys: einer für Termius auf der Workstation und einer für die Codex App.
raspberrypi5-workstation
raspberrypi5-codex
Termius ist mein manueller Zugriff. Die Codex App bekommt einen eigenen lokalen OpenSSH-Key, damit ich später Systeminformationen, Logs und Projektdateien direkt auslesen kann, ohne alles per Copy/Paste durch den Chat zu schieben.
Host raspberrypi5
HostName <lokale-ip>
User <pi-user>
Port <ssh-port>
IdentityFile ~/.ssh/raspberrypi5-codex
IdentitiesOnly yes
SSH härten
Der frische SSH-Stand war noch zu offen: Standard-Port, Passwort-Login erlaubt und Root-Login nicht vollständig deaktiviert. Nach dem erfolgreichen Key-Test habe ich die SSH-Konfiguration schrittweise geändert. Die konkrete Portnummer ersetze ich hier bewusst durch einen Platzhalter.
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
Port <ssh-port>
Eine Besonderheit auf dem frischen Pi war die Datei /etc/ssh/sshd_config.d/50-cloud-init.conf. Dort stand zusätzlich PasswordAuthentication yes, wodurch meine erste Änderung in sshd_config überschrieben wurde. Erst nachdem diese Datei ebenfalls auf no stand, war SSH wirklich key-only. Der Hintergrund ist eine sshd-Eigenheit, die in kaum einer Anleitung steht: Bei doppelten Optionen gewinnt der zuerst eingelesene Wert, und die Dateien unter sshd_config.d werden vor der Hauptdatei geladen. Verlassen sollte man sich deshalb nie auf das Lesen der Config-Dateien, sondern nur auf sudo sshd -T, das die effektiven Werte zeigt.
sudo sshd -t
sudo systemctl reload ssh
sudo sshd -T | grep -Ei 'port|permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractiveauthentication'
Der finale SSH-Zustand:
port <ssh-port>
permitrootlogin no
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
Ob ein Login wirklich über den Key lief, verrät nicht das Bauchgefühl, sondern das Journal. Solange im SSH-Client Key und Passwort hinterlegt sind, sieht man dem Login von außen nicht an, welcher Weg benutzt wurde.
sudo journalctl -u ssh -n 30 --no-pager | grep -i accepted
→ Accepted publickey for <pi-user> ... ED25519 SHA256:...
Und gegen das Aussperren gibt es eine einfache Routine: die alte Session offen lassen, die Änderung machen und den Login in einem neuen Tab testen. Erst wenn der neue Login sauber durchkommt, wird die alte Session geschlossen.
Firewall nur fürs Heimnetz
Der Pi steht im Heimnetz. Deshalb muss SSH nicht für beliebige Netze offen sein. UFW blockiert eingehend alles und erlaubt nur SSH aus dem lokalen Netzbereich.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from <heimnetz-cidr> to any port <ssh-port> proto tcp comment 'SSH LAN'
sudo ufw enable
sudo ufw status verbose
Damit bleibt der Pi im lokalen Netz erreichbar, aber die Firewall-Regel ist enger als ein pauschales allow <ssh-port>/tcp.
Updates und Fail2ban
Danach kamen automatische Sicherheitsupdates und Fail2ban. Beides ist keine Magie, aber eine solide Basisschicht: Updates werden nicht vergessen und wiederholte SSH-Fehlversuche landen im Fail2ban-Jail.
sudo apt install unattended-upgrades apt-listchanges -y
sudo dpkg-reconfigure -plow unattended-upgrades
apt-config dump APT::Periodic
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = <ssh-port>
Der Kontrollstatus war sauber: ein aktives SSH-Jail, keine fehlgeschlagenen Versuche und keine gebannten IPs.
Zwei Kleinigkeiten, die Einsteiger verunsichern können: Direkt nach dem Start meldet fail2ban-client unter Umständen einen Socket-Fehler. Das ist kein Defekt, der Dienst ist schlicht noch am Hochfahren, ein paar Sekunden später läuft alles. Und falls man sich doch einmal selbst bannt, hilft sudo fail2ban-client set sshd unbanip <ip>.
Unnötige Dienste rausnehmen
Beim Blick auf die offenen Dienste fiel avahi-daemon auf. Das ist für mDNS und Namen wie raspberrypi5.local praktisch. Ich nutze aber die feste DHCP-Reservierung im Router, also brauche ich Avahi aktuell nicht.
sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now avahi-daemon.socket
Danach war per TCP nur noch SSH auf dem konfigurierten Port sichtbar.
Ethernet-only
Der Pi hatte nach der Neuinstallation zwei aktive Interfaces im gleichen Netz: eth0 über Ethernet und wlan0 über WLAN. Da die feste IP im Router an der Ethernet-MAC hängt, habe ich WLAN deaktiviert.
sudo nmcli radio wifi off
sudo rfkill block wifi
Für den rebootfesten Zustand kam zusätzlich ein Overlay in die Raspberry-Pi-Boot-Config.
# Disable onboard Wi-Fi; Ethernet is used with a fixed DHCP reservation.
dtoverlay=disable-wifi
Nach dem Reboot war WLAN wirklich weg:
WIFI-HW WIFI WWAN-HW WWAN
missing disabled missing enabled
default via <gateway-ip> dev eth0 proto dhcp src <lokale-ip>
Der Router gehört zum Server
Der Abschnitt, den es im VPS-Artikel nicht gibt: Wenn die Außengrenze der Router ist, gehört er mit zur Härtung. Im Experten-Modus der Box habe ich vier Dinge geprüft. Portfreigaben: keine vorhanden, und das bleibt so. UPnP: war ab Werk deaktiviert, gut so, denn sonst könnten Geräte im Netz sich selbst Ports öffnen. Ping auf das WAN-Interface: war an und ist jetzt aus, damit der Anschluss für Scanner unsichtbar bleibt. Und das IPv6-Pendant zur Portfreigabe (bei meiner Box heißt es Host Exposure): leer. Dazu kommt die DHCP-Reservierung, damit der Pi seine feste Adresse behält.
Kontrolle statt Vertrauen
Härtung ist kein einmaliges Ritual. Etwa einmal im Monat laufen fünf Befehle, die den Zustand in zwei Minuten sichtbar machen: Firewall-Regeln, fehlgeschlagene Dienste, offene Ports, Fail2ban-Status und die letzten Logins.
sudo ufw status verbose
sudo systemctl --failed
sudo ss -tulpn
sudo fail2ban-client status sshd
last -20
Endzustand
Damit ist der Pi noch keine fertige KI-Maschine, aber eine gute Projektbasis. Genau das war das Ziel für diesen Schritt.
- Hostname
raspberrypi5 - feste lokale IP per DHCP-Reservierung
- SSH nur per Key
- eigener SSH-Port
- Root-SSH deaktiviert
- Passwort-SSH deaktiviert
- UFW aktiv, SSH nur aus dem Heimnetz
- unattended-upgrades aktiv
- Fail2ban aktiv
- Avahi/mDNS deaktiviert
- WLAN rebootfest deaktiviert
- Ethernet-only über
eth0 - Router: keine Portfreigaben, UPnP aus, WAN-Ping aus
Roadmap
Nach dem Security Setup ging es um die eigentliche Agent-Arbeit, und die ist inzwischen dokumentiert:
- Hermes Agent einsperren: Least Privilege für einen autonomen Agenten mit Shell-Zugriff.
- Shorts-Pipeline mit Hermes Agent: die komplette Kurzvideo-Produktion, dreimal täglich per Cron.
- Als Nächstes: TikTok und Instagram Reels als weitere Plattformen.