Back to Blog

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.

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.

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

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.

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>

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

Roadmap

Nach dem Security Setup geht es im Raspberry Pi Projekt um die eigentliche Agent Arbeit:

  • Hermes Agent auf dem Raspberry Pi 5 installieren.
  • Hermes Agent mit OpenAI/Codex OAuth verbinden.
  • Telegram anbinden, damit der Agent vom iPhone aus erreichbar ist.
  • Lokale LLMs evaluieren, die auf kleiner Hardware realistisch laufen und sich für lokale Workflows lohnen.