Duplicati-Backup auf dem Raspi mit SFTP speichern

🧰 Voraussetzungen

  • Raspberry Pi läuft mit SSH-Server (`openssh-server`)
  • SSD ist bereits gemountet unter `/media/san2tb`
  • Dein Client (der Duplicati ausführt) ist Linux

🔐 1. SSH-Schlüsselpaar auf dem Client erstellen

Auf dem Rechner, auf dem Duplicati läuft, wird ein Schlüsselpaar erstellt

ssh-keygen -t ed25519 -f ~/.ssh/sftpusr_key -N ""

Ergebnis:
Private Key: `~/.ssh/sftpusr_key`
Öffentlicher Key: `~/.ssh/sftpusr_key.pub`

Der Parameter `-N „“` sorgt für kein Passwort.

👤 2. Neuen Benutzer auf dem Raspberry Pi erstellen

Optional: Verhindere SSH-Login mit Passwort:

sudo adduser --disabled-password --gecos "" sftpusr
sudo passwd -l sftpusr 
# sudo usermod -d /home/sftpusr sftpusr 
sudo usermod -s /usr/sbin/nologin sftpusr

🔑 3. SSH-Zugang mit Schlüssel einrichten

1. Verzeichnisse erstellen:

sudo mkdir -p /home/sftpusr/.ssh
sudo chown sftpusr:sftpusr /home/sftpusr/.ssh
sudo chmod 700 /home/sftpusr/.ssh

2. Öffentlichen Schlüssel auf Pi übertragen:

ssh-copy-id -i ~/.ssh/sftp_user_key.pub sftp-user@raspi

Oder manuell:

cat ~/.ssh/sftpusr_key.pub | ssh pi@ "sudo tee /home/sftpusr/.ssh/authorized_keys"
sudo chown sftpusr:sftpusr /home/sftpusr/.ssh/authorized_keys
sudo chmod 600 /home/sftpusr/.ssh/authorized_keys

📁 4. Schreibrechte auf externe SSD einrichten

Angenommen, das Backup-Ziel ist: `/media/san2tb/backup_x13g3`

Ordner erstellen und Besitzerrechte auf `sftpusr` ändern:

sudo mkdir -p /media/san2tb/backup_x13g3
sudo chown -R sftpusr:sftpusr /media/san2tb/backup_x13g3

`sftpusr` braucht Schreibrechte in diesem Ordner – ohne Zugriff auf andere SSD-Bereiche.

🔐 5. Optional: Nur SFTP (kein SSH-Terminal)

Den User auf reines SFTP einschränken. Das ist empfohlen für Backup-Ziele. SSH-Konfiguration auf dem Pi anpassen:

sudo nano /etc/ssh/sshd_config

Am Ende einfügen:

Match User sftpusr
    ForceCommand internal-sftp
    ChrootDirectory /home/sftpusr
    PermitTTY no
    AllowTcpForwarding no
    X11Forwarding no

Das sperrt `sftpusr` in `/home/sftpusr`. Dann muss das Backup-Verzeichnis darin sein.

⚠️ WICHTIG:
`ChrootDirectory` muss root gehören, sonst funktioniert SFTP nicht.

sudo chown root:root /home/sftpusr
sudo chmod 755 /home/sftpusr

sudo mkdir -p /home/sftpusr/backup
sudo chown sftpusr:sftpusr /home/sftpusr/backup

Temporär zum testen:

sudo mount --bind /media/san2tb/backup_x13g3 /home/sftpusr/backup

sudo systemctl restart ssh

Mount dauerhaft via /etc/fstab einbinden.
Am Ende der Datei einfügen:

/media/san2tb/backup_x13g3 /home/sftpusr/backup none bind 0 0

🔄 6. In Duplicati einrichten

Neues Backup erstellen

  1. Zieltyp: `SFTP (SSH)`
  2. Server und Pfad:
    Server: IP des Raspberry Pi
    Pfad:
    Wenn `ChrootDirectory` gesetzt: /backup
    Sonst (z. B. ohne Chroot): /home/sftpusr/backup
  3. Authentifizierung:
    Benutzername: sftpusr
    Passwort: bleibt leer
    SSH Private Key (ohne Passphrase):
    Lade `/source/.ssh/sftpusr_key` hoch oder kopiere den Inhalt rein.
  4. Testverbindung klicken

✅ Fertig!

Neuer Massespeicher im Laptop

So langsam aber sicher wird der Speicherplatz für den Massespeicher auf dem Laptop zu klein, das ganze KI-Zeug braucht relativ viel Speicherplatz.
Da wir mit LVM / LUKS arbeiten, sind ein paar Schritte mehr notwendig…

  • Booten mit CloneZilla und Festplatte auf externe HDD klonen
  • neue SSD einbauen
  • Booten mit CloneZilla und Image zurück auf Festplatte spielen, Partitionen wie im Original belassen und nicht prozentual anpassen.
  • Live-USB stick booten und mit gparted die LVM-Partition entsperren und vergrößern. Gparted sieht nur die LVM-Partition und nicht die darin enthaltenen ‚logischen Volumen‘
  • Live-System beenden und ins normale System booten

Einen Überblick über die einzelnen Volume erhalten wir mit lvdisplay

Zunächst entfernen wir die Swap-Partition:

# Swap deaktivieren
swapoff -a
# mit lvremove die die logische Partionion 
lvremove /dev/vgmint/swap_1

Ermittel nun den freien Platz in der Partition: vgdisplay. Wenn die Einheit nicht ganz passt, kann sie mit vgdisplay --unit G angepasst werden.

Nachdem der Versuch das ganze mit GB anzugeben wegen Umrechnungsungenauigkeiten nicht geklappt hat, rechnen wir das ganze in Extends aus:

1 Extent = 4 MiB = 0,00390625 GB
32 GB / 0.00390625 ≈ 8192 Extents

715128 (verfügbar) - 8192 (für Reserve) = 706936 Extents

# Befehl zur Vergrößerung des Volumens
lvextend -l +706936 /dev/vgmint/root

Anschließend muss noch das Dateisystem vergrößert werden:

resize2fs /dev/vgmint/root

Und die Swap-Partion wieder hergestellt (es wird der komplette leere Platz verwendet) werden:

lvcreate -l 100%FREE -n swap_1 vgmint
mkswap /dev/vgmint/swap_1
swapon /dev/vgmint/swap_1

# Zum Überprüfen ob alles läuft:
swapon --show
free -h

Lokale LLM im Docker

Wir verwenden Ollama (https://ollama.com/)

Installation über docker compose.

docker-compose.yaml

services:
  ollama:
    image: docker.io/ollama/ollama:rocm
    container_name: ollama
    volumes:
      - ollama:/root/.ollama
    ports:
      - 11434:11434
    devices:
      - /dev/kfd:/dev/kfd
      - /dev/dri:/dev/dri
#    environment:
#      - OLLAMA_KEEP_ALIVE=1h
#      - OLLAMA_HOST=127.0.0.1
    pull_policy: always
    tty: true
    restart: unless-stopped

volumes:
  ollama:
    driver: local

Umgang mit Models:

# Modell installieren
docker exec -it ollama ollama pull llava:v1.6
# Modell entfernen
docker exec -it ollama ollama rm llava:v1.6
# Modell aus dem Speicher entladen
docker exec -it ollama ollama stop llava:v1.6
# Modell auflisten
docker exec -it ollama ollama list

Multimodal-Model (die sich u.a. für die Bildanalyse eignen)

  • llava:v1.6; llava:13b : LLaVA is a novel end-to-end trained large multimodal model that combines a vision encoder and Vicuna for general-purpose visual and language understanding.
  • DeepSeek-Janus-Pro-7B

Modelle für Übersetzungen:

BIOS-Update

Um die aktuelle Version anzuzeigen:
sudo dmidecode -s bios-version

Update der Firmware-Infos:
sudo fwupdmgr refresh --force

Geräte anzeigen lassen:
sudo fwupdmgr get-devices

Alle verfügbaren Updates herunterladen:
fwupdmgr get-updates

Firmeware-Update durchführen, sofern notwenig:
sudo fwupdmgr update

beruhigend…

Es ist sehr beruhigend wenn die Personalabteilung zur Einführung der digitalen Personalakte mit den Worten informiert:

Durch den Wegfall des Versands von Personalakten zu den jeweiligen hamburgischen Behörden, werden Ressourcen eingespart und der Datenschutz wird zudem zukünftig sicherer gewahrt, da es nahezu ausgeschlossen ist, dass Unberechtigte an die Daten gelangen können.

Raspi neu aufsetzten

Grundinstallation

Mit dem Raspberry Pi Imager das Raspberry Pi OS Lite (hier verwende ich die 64-bit-Version [Debian 12 – bookworm]) installieren.
Bei den erweiterten Einstellungen hostname festlegen, ssh mit public-key aktivieren sowie Spracheinstellungen festlegen…

  • Raspi booten, das dauert dann erstmal ein bisschen.
  • .bash_aliases anpassen
  • nano configurieren in .config/nano/nanorc
  • staticIP-Adresse mit den NetworkManager festlegen

Watchdog einrichten

In der /boot/firmeware/config.txt den Hardware-Watchdog aktivieren:

dtparam=watchdog

Installation des Watchdog

sudo apt update
sudo apt install watchdog

In der Datei /etc/watchdog.conf folgende Zeilen aktivieren

watchdog-device = /dev/watchdog
watchdog-timeout = 15
log-dir = /var/log/watchdog
max-load-1 = 24

Der Raspi hat wohl als maximales timeout 15 Sekunden!
Anschließend der Service aktivieren und starten

sudo systemctl enable watchdog
sudo systemctl start watchdog
sudo systemctl status watchdog

Unattended-Upgrades einrichten

Original hier: www.elektronik-kompendium.de/sites/raspberry-pi/2002101.htm

sudo apt-get install unattended-upgrades
# Aktivieren/Deaktivieren:
sudo dpkg-reconfigure -plow unattended-upgrades

# genaue Config:
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Schreibzugriff auf SD-Karte reduzieren

siehe Artikel dort…

Migration von Bootstrap 3 auf 5

Zentrale Dokumente für die Migration sind hier zu finden:

Der Text kommt von hier: https://nodebb.org/blog/nodebb-specific-bootstrap-3-to-5-migration-guide/

Grundsätzliches

  • pull-left changed to float-start
  • pull-right changed to float-end
  • text-right changed to text-end
  • img-responsive changed to img-fluid

Buttons

  • Vertically stacked buttons change from .btn-block to using display/spacer classes.
<div class="d-grid gap-2">
  <button class="btn btn-primary" type="button">Button</button>
  <button class="btn btn-primary" type="button">Button</button> 
</div>
  • btn-xs removed use btn-sm
  • btn-default removed use btn-outline-secondary

Grid/Breakpoints

  • col-xs-<n> changed to col-<n>
  • col-md-offset-<n> changed to offset-md-<n>

Display

  • inline-block changed to d-inline-block

Media Component

… has been removed completely, use flex display classes instead:

<div class="d-flex">
  <div class="flex-shrink-0">
    image
  </div>
  <div class="flex-grow-1 ms-3">
    text
  </div>
</div>

Navbar

  • navbar-toggle changed to navbar-toggler

Panels, Wells, and Jumbotrons

… have all been removed in favour of the “card” component.

To convert a panel into a card:

<div class=”card”>
  <div class=”card-header”>header</div>
  <div class=”card-body”>body</div>
  <div class=”card-footer”>footer</div>
</div>
  • <div class="well"> changed to <div class="card card-body text-bg-light">

Forms

  • <select class="form-control"> changed to <select class="form-select">
  • Add form-label class to labels
  • Add form-check-input to checkboxes. Sample checkbox with label:
<div class="”form-check”">
  <input class="”form-check-input”" type="”checkbox”" />
  <label class="”form-check-label”">a checkbox</label>
</div>
  • form-group, .form-row, or .form-inline are removed use spacing utilities
  • help-block changed to form-text

Dropdowns

  • data-toggle="dropdown" changed to data-bs-toggle="dropdown"
  • Add dropdown-item to dropdown list item <a class="dropdown-item">Item 1</a>
  • dropdown-menu-right changed to dropdown-menu-end
  • Divider changed to dropdown-divider

Collapse

  • data-toggle="collapse" changed to data-bs-toggle="collapse"
  • data-target=".classname" changed to data-bs-target=".classname"

Modals

  • data-dismiss="modal" changed to data-bs-dismiss="modal"

Responsive Breakpoints

Instead of using media queries using old Bootstrap 3 variables (e.g. @media (max-width: @screen-sm-max) { ... }), Bootstrap 5 introduces a new mixin for breakpoints.

Read more about it in Bootstrap 5’s article re: responsive breakpoints.

raspi Arthur

Da der Raspi im Dauerbetrieb laufen sollen einiges hiervon umgesetzt:
https://www.3dh.de/raspberry-pi-fit-fuer-dauerbetrieb-machen/
https://www.datenreise.de/raspberry-pi-stabiler-24-7-dauerbetrieb/

Schreibzugriff auf SD-Karte reduzieren

  • Log2Ram installieren
    (siehe hier: github.com/azlux/log2ram/) um die Zugriffe auf /var/log/ zu reduzieren.
    echo "deb [signed-by=/usr/share/keyrings/azlux-archive-keyring.gpg] http://packages.azlux.fr/debian/ bullseye main" | sudo tee /etc/apt/sources.list.d/azlux.list
    sudo wget -O /usr/share/keyrings/azlux-archive-keyring.gpg  https://azlux.fr/repo.gpg
    sudo apt update
    sudo apt install log2ram
  • tmp ins Ram legen
    sudo nano edit /etc/fstab
    # beim Eintrag für / (etx4) noatime hinzufügen
    tmpfs     /tmp      tmpfs   nosuid,nodev,noatime   0  0
    tmpfs     /var/tmp    tmpfs   nosuid,nodev,noatime   0  0
  • Swapping deaktivieren
    sudo dphys-swapfile swapoff
    sudo systemctl disable dphys-swapfile
    sudo apt-get purge dphys-swapfile

Watchdog installiert

Der auf dem Raspberry Pi verbaute BCM2708 von Broadcom verfügt standardmäßig bereits über einen Hardware-Watchdog, der das System im Problemfall neu starten kann. Um diesen zu nutzen, wird ein Kernelmodul und ein Daemon benötigt.

Funktionsweise:
Der Daemon teilt dem Watchdog in regelmäßigen Intervallen mit, dass das System funktioniert. Kommt es nun zu einem Problem und das System hängt sich auf, erhält der Watchdog keine Nachrichten mehr und setzt daraufhin das System zurück.

sudo apt-get install watchdog
sudo modprobe bcm2835_wdt
echo "bcm2835_wdt" | sudo tee -a /etc/modules

# config anpassen
sudo nano /etc/watchdog.conf
# Minimaleinstellung
watchdog-device        = /dev/watchdog
max-load-1             = 24

Unattended-Upgrades einrichten

Original hier: www.elektronik-kompendium.de/sites/raspberry-pi/2002101.htm

sudo apt-get install unattended-upgrades
# Aktivieren/Deaktivieren:
sudo dpkg-reconfigure -plow unattended-upgrades

# genaue Config:
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Aktualisieren von .bashrc

alias up='sudo apt update && sudo apt upgrade'

static IPv6 für den pihole

Als Statische IPv6-IP-Adresse wird der Prefix ‚fd00::‘ verwendet, eine Local Unicast Adressen (LUA) [vgl hier: www.ipv6-portal.de/informationen/einfuehrung/adressbereiche.html]. Im hinteren Teil verwenden wir (zur Übersichtlichkeit bei den Statischen Adressen) die IPv4-Adressen (von 192.168.130.8 nehmen wir ‚::130:8‘).

cat < /etc/network/interfaces.d/ipv6
# IPv6
auto eth0
iface eth0 inet6 static
pre-up modprobe ipv6
address fd00::130:8
netmask 64
EOF

Nach dem Reboot des pihole muss die Adresse in die Fritzbox eingetragen werden (Heimnetz -> Netzwerk -> Netzwerkeinstellungen -> IP6-Einstellungen)
– aktiviere ULA-Präfix manuell festlegen: [fd00:: /64]
– aktiviere DNSv6-Server auch über Router Advertisement bekanntgeben (RFC 5006) [fd00::130:8]

Jetzt noch auf dem pihole die Config bearbeiten:

sudo nano /etc/pihole/setupVars.conf
# Eintragen:
IPV6_ADDRESS=fd00::130:8/64
AAAA_QUERY_ANALYSIS=yes

… und dafür sorgen dass die Änderungen übernommen werden

pihole -g

Gruslig

„Diese Deep-Learning-Systeme machen coole Sachen. Wir verstehen sie kaum, aber sie funktionieren“ sagt Ryan Adams, Informatik-Professor an der Harvard University.