Backup und Restore meines Raspberry Pi mit Openclaw

Words
776
Reading
4 min
Listen
Play
3M

Raspberry Pi Klonen – Wie ich einen zweiten Pi per Backup identisch aufsetze

📑 Inhaltsverzeichnis

  1. Die Idee
  2. Warum Caches raus?
  3. Das Backup-Skript
  4. Ablauf: Neuen Pi einrichten
  5. Das Setup-Skript im Detail
  6. Was passiert mit Daten auf dem alten Pi?
  7. Sicherheit & Wiederherstellbarkeit
  8. Fazit
  9. Backup-Script
  10. Restore-Script

grafik.png


🎯 Die Idee

Ich betreibe einen Raspberry Pi (Debian 13 "Trixie", aarch64) als Heimprovisorium für:

  • OpenClaw – meinen KI-Agenten
  • Meilisearch – Volltextsuche für mein Wiki
  • Ein Wiki – persönliche Wissensdatenbank
  • Himalaya – E-Mail vom Terminal aus
  • Faster-Whisper + Tesseract OCR – Sprach- und Texterkennung

Wenn dieser Pi stirbt, will ich nicht stundenlang neu konfigurieren. Also: tägliches rsync-Backup auf eine exFAT-Platte und ein möglichst Setup-Skript, das aus dem Backup einen funktionsgleichen zweiten Pi macht.

Ich habe zwei Scripte unten angehangen: Backup und Restore. Im folgenden werden diese Scripte beschrieben:

🗑 Warum Caches raus?

Der erste Backup-Lauf war 9,4 GB groß. Eine Analyse zeigte:

OrdnerGrößegehört ins Backup?
/home/achim/.cache/3,2 GB❌ Browser-, pip-, Thumbnail-Cache
/home/achim/.npm/1,3 GB❌ npm-Package-Cache
**/node_modules/je nach Projekt❌ wird per npm ci installiert
Papierkorb?
Summe Caches~4,5 GB
Rest (SSH-Keys, Config, Projekte, ...)~4,9 GBmuss rein

Caches enthalten keine Konfiguration – sie sind das Ergebnis von Tool-Aufrufen. npm install --cache ist überflüssig, wenn man npm install ohnehin laufen lässt. Ähnlich .cache/: Browser-Cache, thumbnails, pip-Wheels – alles wird bei Bedarf automatisch neu erzeugt.

Ausgeschlossen werden daher:

--exclude='.cache/'
--exclude='.npm/'
--exclude='.local/share/Trash/'
--exclude='**/node_modules/'
--exclude='.cargo/registry/'
--exclude='.cargo/git/'
--exclude='.cache/pip/'

Das Backup schrumpft so von 9,4 GB auf ~4,9 GB – und enthält trotzdem alles, was für einen kompletten Restore nötig ist.

📜 Das Backup-Skript

Das Skript liegt unter /home/achim/.openclaw/scripts/backup_home.sh und wird täglich um 5:30 per Cron ausgeführt (crontab -l).

Auszug aus dem rsync-Aufruf:

EXCLUDES=(
    --exclude='.cache/'
    --exclude='.npm/'
    --exclude='.local/share/Trash/'
    --exclude='**/node_modules/'
    --exclude='.cargo/registry/'
    --exclude='.cargo/git/'
    --exclude='.cache/pip/'
)

rsync "${EXCLUDES[@]}" -rltD --no-perms --no-owner --no-group \
    "$BACKUP_SRC/" "$BACKUP_DIR/"

Da die Zielpartition exFAT ist, werden Berechtigungen und Owner nicht mitgesichert – das ist für die reine Datenwiederherstellung auch nicht nötig.

Retention (Aufbewahrung):

  • Tägliche Backups → 7 Tage
  • Sonntags-Backups → 5 Wochen
  • Monatserste-Backups → 12 Monate
    1. Januar-Backups → für immer

Bonus: Jedes Backup enthält automatisch eine setup_new_pi.sh – damit ist das Wiederherstellen auf einem neuen Pi trivial.

🔧 Ablauf: Neuen Pi einrichten

Voraussetzungen

  • Ein frischer Raspberry Pi mit Debian 13 (Trixie) und aarch64 (ARM64)
  • Die exFAT-Platte mit dem aktuellen Backup wird angeschlossen
  • Der Pi hat Internetzugang

Schritt 1: Backup kopieren

# Backup-Quelle prüfen (exFAT-Platte)
ls /media/achim/raspibackup/achimshone_20260609/

# Dateien auf den neuen Pi kopieren
# Entweder direkt per rsync von der Platte nach /home/achim
# oder die Platte im Pi einstecken und kopieren
cp -a /media/achim/raspibackup/achimshome_20260609/* /home/achim/

Wichtig: Der Ziel-Pfad muss /home/achim/ sein – alle Tools und Dienste erwarten diesen Pfad.

Schritt 2: Setup-Skript ausführen

cd /home/achim
sudo bash setup_new_pi.sh

Schritt 3: Fertig

Nach etwa 5–10 Minuten (abhängig von der Internetgeschwindigkeit) ist der Pi einsatzbereit. Das Setup-Skript erledigt automatisch:

🔄 Das Setup-Skript im Detail

Das Skript /home/achim/setup_new_pi.sh (wird bei jedem Backup mitgeneriert) arbeitet in 9 Phasen:

Phase 1 – System-Pakete

apt-get install -y \
    build-essential cmake git curl wget ffmpeg \
    python3 python3-pip python3-venv nginx \
    tesseract-ocr tesseract-ocr-deu exfatprogs

Node.js 22.x wird von NodeSource installiert.

Phase 2 – OpenClaw

npm install -g openclaw clawhub

Phase 3 – Himalaya (E-Mail)

Himalaya ist ein statisches Binary. Die ARM64-Version wird von GitHub geladen:

curl -fsSL -o /tmp/himalaya.tar.gz \
  "https://github.com/soywod/himalaya/releases/download/v1.2.0/himalaya-linux-aarch64-musl.tar.gz"

Phase 4 – Meilisearch

Meilisearch läuft als systemd-Service unter dem User achim. Das Binary (v1.43.0) wird von GitHub geholt:

curl -fsSL -o /tmp/meilisearch.gz \
  "https://github.com/meilisearch/meilisearch/releases/download/v1.43.0/meilisearch-linux-aarch64.gz"

Der Service wird sofort gestartet und auf Autostart gelegt.

Phase 5 – Python-Venvs

Zwei virtuelle Umgebungen werden aufgesetzt:

  • ~/whisper_light/ – Faster-Whisper (Spracherkennung, base-Modell)
  • ~/imgocr/ – OpenCV + numpy (Zählerstand-OCR)

Zusätzlich wird beem (Hive-Blockchain-Zugriff) systemweit installiert.

Phase 6 – Wiki (nginx)

Ein Symlink verknüpft das Wiki-Inhaltsverzeichnis mit dem nginx-Document-Root:

ln -sf /home/achim/.openclaw/workspace/AchimsDaten/wiki_contents /var/www/html/wiki

Phase 7 – Cron-Job

Der Backup-Job wird in die crontab des Users achim eingetragen:

30 5 * * * /home/achim/.openclaw/scripts/backup_home.sh

Phase 8 – Meilisearch-Index

Der Volltextindex für das Wiki wird über index_all_files.py neu aufgebaut.

Phase 9 – Berechtigungen

Zum Schluss werden alle Dateien im Home-Verzeichnis an den User achim übergeben.

💡 Was passiert mit Daten auf dem alten Pi?

Das Backup sichert Daten (Dateien, Konfigurationen, SSH-Keys, Wiki-Inhalte), aber nicht den Systemzustand (installierte Pakete, laufende Dienste). Das ist auch gut so – denn der Systemzustand lässt sich automatisch über das Setup-Skript reproduzieren.

Was bleibt erhalten:

  • SSH-Keys (~/.ssh/) und GPG-Keys (~/.gnupg/)
  • OpenClaw-Konfiguration (~/.openclaw/)
  • Wiki-Daten
  • Himalaya-Konfiguration (~/.config/himalaya/)
  • Alle Projekte und persönlichen Dateien
  • Die Helbardor.env mit API-Keys (passwortgeschützt)

Was wird neu erstellt:

  • Python-Venvs (Whisper, OCR)
  • npm-Package-Cache
  • meilisearch-Datenbank (wird vom Wiki-Index neu befüllt)

🔐 Sicherheit & Wiederherstellbarkeit

Ein Word zur Sicherheit:

  1. Helbardor.env enthält sensible API-Keys (Hive-Posting-Key, OpenRouter-Key). Diese Datei wird komplett mitgesichert – schützt die Platte also physisch.
  2. Das Backup enthält alle SSH-Keys. Ein neuer Pi hat damit sofort Zugriff auf alle Dienste, die der alte Pi hatte. Das ist praktisch, aber auch ein Risiko bei Verlust der Backup-Platte.
  3. Der Restore testet das Backup. Wenn ich heute den neuen Pi aufsetze und er funktioniert, weiß ich, dass das Backup auch morgen noch funktioniert. Regelmäßige Restore-Tests sind Gold wert.

✅ Fazit

Die Kombination aus:

  1. Täglichem rsync-Backup mit klug gewählten Excludes (Größe von 9,4 GB → 4,9 GB)
  2. Einem Setup-Skript, das automatisch alle Abhängigkeiten installiert
  3. Retention-Richtlinie, die alte Backups nicht sofort löscht

…gibt mir die Sicherheit, dass ich nach einem Pi-Totalausfall innerhalb von 30 Minuten wieder online bin. Vom Befehl sudo bash setup_new_pi.sh bis zum ersten Testlauf des Agenten.

Backup Script

achim@raspi:~/.openclaw/scripts $ cat backup_home.sh
#!/bin/bash
# Backup script for /home/achim
#
# Runs daily at 5:30 via cron (crontab -l)
# Creates a full directory copy via rsync to /media/achim/raspibackup/achimshome_YYYYMMDD
#
# EXCLUDED (clean rebuild):
#   .cache/       – Browser-, pip-, thumbnails-Cache → wird bei Bedarf neu erzeugt
#   .npm/         – npm-Package-Cache → wird per npm install neu geholt
#   .local/share/Trash/ – Papierkorb
#   **/node_modules/    – Kann per npm ci installiert werden
#
# Retention policy:
#   - Daily backups: keep 7 days
#   - Weekly backups (Sundays): keep last 5
#   - Monthly backups (1st of month): keep last 12
#   - Yearly backups (January 1st): keep forever

set -euo pipefail

BACKUP_SRC="/home/achim"
BACKUP_BASE="/media/achim/raspibackup"
DATE=$(date +%Y%m%d)
BACKUP_DIR="${BACKUP_BASE}/achimshome_${DATE}"
LOG_FILE="${BACKUP_BASE}/backup.log"

# ─── Exclude-Patterns ───────────────────────────────────────────────
# Caches, Papierkorb, node_modules – alles, was auf einem neuen Pi
# automatisch oder per setup_new_pi.sh neu aufgebaut wird.
EXCLUDES=(
    --exclude='.cache/'
    --exclude='.npm/'
    --exclude='.local/share/Trash/'
    --exclude='**/node_modules/'
    # Falls Rust/Cargo installiert ist → Cargo-Registry raus
    --exclude='.cargo/registry/'
    --exclude='.cargo/git/'
    # Python-Wheel-Cache
    --exclude='.cache/pip/'
)

# Ensure base dir exists
mkdir -p "$BACKUP_BASE"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}

log_stdout() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

log_stdout "=== Backup started ==="

# --- Pre-checks ---
if [ ! -d "$BACKUP_SRC" ]; then
    log_stdout "ERROR: Source $BACKUP_SRC does not exist"
    exit 1
fi

if [ ! -d "$BACKUP_BASE" ]; then
    log_stdout "ERROR: Destination $BACKUP_BASE not accessible"
    exit 1
fi

# --- Create backup ---
log_stdout "Creating backup at $BACKUP_DIR ..."

rsync "${EXCLUDES[@]}" -rltD --no-perms --no-owner --no-group --info=name0 \
    "$BACKUP_SRC/" "$BACKUP_DIR/" >> "$LOG_FILE" 2>&1 || {
    log_stdout "ERROR: rsync failed (exit code $?)"
    exit 1
}

# --- Create setup_new_pi.sh → in das Backup selbst ─────────────────
log_stdout "Generating setup_new_pi.sh ..."
cat > "$BACKUP_DIR/setup_new_pi.sh" << 'SETUP_EOF'
#!/bin/bash
# ===============================================================
# setup_new_pi.sh – Automatische Einrichtung eines neuen Pis
# aus dem Backup /media/.../achimshome_YYYYMMDD/
#
# Annahmen:  Debian 13 (trixie), aarch64 (Raspberry Pi)
# Ziel:      Nach Durchlauf ist der Pi funktionsgleich mit dem
#            alten System (OpenClaw, Wiki, OCR, Whisper, E-Mail)
# ===============================================================
set -euo pipefail
# Sollte innerhalb des restoreten /home/achim laufen, z.B.:
#   cd /home/achim && sudo bash /home/achim/setup_new_pi.sh

log() { echo "[$(date '+%H:%M:%S')] $*"; }

# ─── 1. System-Pakete ───────────────────────────────────────────────
log "=== Phase 1: System-Pakete ==="

apt-get update -qq
apt-get install -y -qq \
    build-essential cmake git curl wget \
    ffmpeg \
    python3 python3-pip python3-venv \
    nginx \
    tesseract-ocr tesseract-ocr-deu \
    exfatprogs

# Node.js 22.x von nodesource
if ! command -v node &>/dev/null; then
    curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
    apt-get install -y -qq nodejs
fi

log "node $(node --version), npm $(npm --version)"

# ─── 2. Globale npm-Pakete ──────────────────────────────────────────
log "=== Phase 2: OpenClaw (npm global) ==="
npm install -g openclaw clawhub 2>&1 | tail -1

# ─── 3. Himalaya (E-Mail) ───────────────────────────────────────────
log "=== Phase 3: Himalaya ==="
if [ ! -f /usr/local/bin/himalaya ]; then
    log "Downloading himalaya v1.2.0 (aarch64 static)..."
    curl -fsSL -o /tmp/himalaya.tar.gz \
        "https://github.com/soywod/himalaya/releases/download/v1.2.0/himalaya-linux-aarch64-musl.tar.gz"
    cd /tmp && tar xzf himalaya.tar.gz himalaya
    mv /tmp/himalaya /usr/local/bin/himalaya
    chmod 755 /usr/local/bin/himalaya
fi

# ─── 4. Meilisearch ─────────────────────────────────────────────────
log "=== Phase 4: Meilisearch ==="
MEILI_DIR="$HOME/.openclaw/meilisearch"
if [ ! -f "$MEILI_DIR/meilisearch" ]; then
    mkdir -p "$MEILI_DIR/data" "$MEILI_DIR/dumps"
    log "Downloading meilisearch v1.43.0 (aarch64)..."
    curl -fsSL -o /tmp/meilisearch.gz \
        "https://github.com/meilisearch/meilisearch/releases/download/v1.43.0/meilisearch-linux-aarch64.gz"
    gunzip -f /tmp/meilisearch.gz
    chmod 755 /tmp/meilisearch
    mv /tmp/meilisearch "$MEILI_DIR/meilisearch"
fi

# Systemd-Service
cat > /etc/systemd/system/meilisearch.service << 'MEILI_SVC'
[Unit]
Description=Meilisearch für Achims Wiki
After=network.target

[Service]
Type=simple
User=achim
WorkingDirectory=/home/achim
ExecStart=/home/achim/.openclaw/meilisearch/meilisearch --db-path /home/achim/.openclaw/meilisearch/data --env development --http-addr 127.0.0.1:7700
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
MEILI_SVC

systemctl daemon-reload
systemctl enable --now meilisearch

# ─── 5. Python-Venvs ────────────────────────────────────────────────
log "=== Phase 5: Python-Venvs ==="

# Whisper (base model → schnell/genügend für Pi)
if [ ! -d "$HOME/whisper_light" ]; then
    python3 -m venv "$HOME/whisper_light"
    "$HOME/whisper_light/bin/pip" install faster-whisper
    mkdir -p "$HOME/.openclaw/speech_models"
fi

# OCR-Venv
if [ ! -d "$HOME/imgocr" ]; then
    python3 -m venv "$HOME/imgocr"
    "$HOME/imgocr/bin/pip" install opencv-python-headless numpy
fi

# ─── 6. Wiki-Dateien (nginx) ────────────────────────────────────────
log "=== Phase 6: Wiki (nginx) ==="
if [ -f "$HOME/.openclaw/workspace/AchimsDaten/wiki_contents/index.html" ]; then
    rm -f /var/www/html/wiki 2>/dev/null
    ln -sf "$HOME/.openclaw/workspace/AchimsDaten/wiki_contents" /var/www/html/wiki
    systemctl restart nginx || true
fi

# ─── 7. Cron-Job für Backup ─────────────────────────────────────────
log "=== Phase 7: Cron-Job ==="
if ! crontab -l 2>/dev/null | grep -q backup_home; then
    (crontab -l 2>/dev/null; echo "30 5 * * * /home/achim/.openclaw/scripts/backup_home.sh") | crontab -
fi

# ─── 8. Meilisearch-Import ──────────────────────────────────────────
log "=== Phase 8: Wiki-Index erneuern ==="
if [ -f "$HOME/.openclaw/agents/helbardor/index_all_files.py" ]; then
    cd "$HOME/.openclaw/agents/helbardor"
    python3 index_all_files.py 2>/dev/null || log "WARNING: Index-Script fehlgeschlagen (Meilisearch noch nicht bereit?)"
fi

# ─── Fertig! ─────────────────────────────────────────────────────────
log ""
log "========================================================"
log "  Setup abgeschlossen!"
log "  Nächste Schritte:"
log "    1. Prüfe dass openclaw läuft:  openclaw gateway status"
log "    2. SSH-Keys testen"
log "    3. Wiki aufrufen:  http://$(hostname -I | awk '{print $1}')/"
log "========================================================"
SETUP_EOF

chmod +x "$BACKUP_DIR/setup_new_pi.sh"

# Touch directory to set a clean timestamp
touch "$BACKUP_DIR"
log_stdout "Backup completed: $BACKUP_DIR"

# ─── Retention cleanup ──────────────────────────────────────────────
log_stdout "=== Retention cleanup started ==="

shopt -s nullglob
backups=("$BACKUP_BASE"/achimshome_*)
shopt -u nullglob

if [ ${#backups[@]} -eq 0 ]; then
    log_stdout "No existing backups found for retention check"
    log_stdout "=== Backup finished ==="
    exit 0
fi

# Sort by directory name (achimshome_YYYYMMDD → oldest first)
IFS=$'\n' sorted_backups=($(sort <<<"${backups[*]}")); unset IFS

today_epoch=$(date +%s)
seven_days_ago=$((today_epoch - 7*24*60*60))

declare -a monthly_dirs=()
declare -a weekly_dirs=()

for dir in "${sorted_backups[@]}"; do
    dirname=$(basename "$dir")
    datestr="${dirname#achimshome_}"

    if ! [[ "$datestr" =~ ^[0-9]{8}$ ]]; then
        log_stdout "WARNING: Skipping non-standard directory: $dirname"
        continue
    fi

    dir_epoch=$(date -d "${datestr:0:4}-${datestr:4:2}-${datestr:6:2}" +%s 2>/dev/null || true)
    if [ -z "$dir_epoch" ]; then
        log_stdout "WARNING: Cannot parse date for $dirname, skipping"
        continue
    fi

    day_of_week=$(date -d "@$dir_epoch" +%u)   # 1=Mon .. 7=Sun
    day_of_month="${datestr:6:2}"
    month="${datestr:4:2}"

    # Skip today's backup (just created) — never delete it
    if [ "$dir" = "$BACKUP_DIR" ]; then
        log_stdout "Retaining (today): $dirname"
        continue
    fi

    if [ "$day_of_month" = "01" ] && [ "$month" = "01" ]; then
        # Yearly backup (Jan 1) – keep forever
        log_stdout "Retaining (yearly): $dirname"
    elif [ "$day_of_month" = "01" ]; then
        # Monthly backup (1st of month)
        monthly_dirs+=("$dir")
    elif [ "$day_of_week" = "7" ]; then
        # Weekly backup (Sunday)
        weekly_dirs+=("$dir")
    elif [ "$dir_epoch" -ge "$seven_days_ago" ]; then
        # Daily backup, younger than 7 days
        log_stdout "Retaining (daily): $dirname"
    else
        # Old daily backup – delete
        log_stdout "Deleting old daily backup: $dirname"
        rm -rf "$dir"
    fi
done

# Keep only the 12 most recent monthly backups
if [ ${#monthly_dirs[@]} -gt 12 ]; then
    delete_count=$(( ${#monthly_dirs[@]} - 12 ))
    for ((i=0; i<delete_count; i++)); do
        log_stdout "Deleting old monthly backup: $(basename "${monthly_dirs[$i]}")"
        rm -rf "${monthly_dirs[$i]}"
    done
fi
for dir in "${monthly_dirs[@]}"; do
    if [ -d "$dir" ]; then
        log_stdout "Retaining (monthly): $(basename "$dir")"
    fi
done

# Keep only the 5 most recent weekly backups
if [ ${#weekly_dirs[@]} -gt 5 ]; then
    delete_count=$(( ${#weekly_dirs[@]} - 5 ))
    for ((i=0; i<delete_count; i++)); do
        log_stdout "Deleting old weekly backup: $(basename "${weekly_dirs[$i]}")"
        rm -rf "${weekly_dirs[$i]}"
    done
fi
for dir in "${weekly_dirs[@]}"; do
    if [ -d "$dir" ]; then
        log_stdout "Retaining (weekly): $(basename "$dir")"
    fi
done

log_stdout "=== Backup finished ===


Restore/Setup-Script


achim@raspi:~/.openclaw/scripts $ cat setup_new_pi.sh 
#!/bin/bash
# ===============================================================
# setup_new_pi.sh – Automatische Einrichtung eines neuen Pis
# aus dem Backup /media/.../achimshome_YYYYMMDD/
#
# Annahmen:  Debian 13 (trixie), aarch64 (Raspberry Pi)
# Ziel:      Nach Durchlauf ist der Pi funktionsgleich mit dem
#            alten System (OpenClaw, Wiki, OCR, Whisper, E-Mail)
#
# Nutzung:   Nachdem das Backup auf den neuen Pi kopiert wurde:
#   cd /home/achim && sudo bash setup_new_pi.sh
# ===============================================================
set -euo pipefail

log() { echo "[$(date '+%H:%M:%S')] $*"; }

# ─── 0. Prüfung ─────────────────────────────────────────────────────
if [ "$(id -u)" -ne 0 ]; then
    echo "❌ Dieses Skript muss als root laufen! (sudo bash $0)"
    exit 1
fi

log "=== Setup für neuen Raspberry Pi gestartet ==="

# ─── 1. System-Pakete ───────────────────────────────────────────────
log "=== Phase 1: System-Pakete ==="

apt-get update -qq
apt-get install -y -qq \
    build-essential cmake git curl wget \
    ffmpeg \
    python3 python3-pip python3-venv \
    nginx \
    tesseract-ocr tesseract-ocr-deu \
    exfatprogs

# Node.js 22.x von nodesource
if ! command -v node &>/dev/null; then
    curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
    apt-get install -y -qq nodejs
fi

log "✓ node $(node --version), npm $(npm --version)"

# ─── 2. Globale npm-Pakete ──────────────────────────────────────────
log "=== Phase 2: OpenClaw (npm global) ==="
npm install -g openclaw clawhub 2>&1 | tail -1
log "✓ OpenClaw installiert"

# ─── 3. Himalaya (E-Mail) ───────────────────────────────────────────
log "=== Phase 3: Himalaya (E-Mail) ==="
if [ ! -f /usr/local/bin/himalaya ]; then
    log "→ Download himalaya v1.2.0 (aarch64 static)..."
    curl -fsSL -o /tmp/himalaya.tar.gz \
        "https://github.com/soywod/himalaya/releases/download/v1.2.0/himalaya-linux-aarch64-musl.tar.gz"
    cd /tmp && tar xzf himalaya.tar.gz himalaya
    mv /tmp/himalaya /usr/local/bin/himalaya
    chmod 755 /usr/local/bin/himalaya
fi
log "✓ Himalaya installiert"

# ─── 4. Meilisearch ─────────────────────────────────────────────────
log "=== Phase 4: Meilisearch ==="
MEILI_DIR="$HOME/.openclaw/meilisearch"
if [ ! -f "$MEILI_DIR/meilisearch" ]; then
    mkdir -p "$MEILI_DIR/data" "$MEILI_DIR/dumps"
    log "→ Download meilisearch v1.43.0 (aarch64)..."
    curl -fsSL -o /tmp/meilisearch.gz \
        "https://github.com/meilisearch/meilisearch/releases/download/v1.43.0/meilisearch-linux-aarch64.gz"
    gunzip -f /tmp/meilisearch.gz
    chmod 755 /tmp/meilisearch
    mv /tmp/meilisearch "$MEILI_DIR/meilisearch"
fi

cat > /etc/systemd/system/meilisearch.service << 'MEILI_SVC'
[Unit]
Description=Meilisearch für Achims Wiki
After=network.target

[Service]
Type=simple
User=achim
WorkingDirectory=/home/achim
ExecStart=/home/achim/.openclaw/meilisearch/meilisearch --db-path /home/achim/.openclaw/meilisearch/data --env development --http-addr 127.0.0.1:7700
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
MEILI_SVC

systemctl daemon-reload
systemctl enable --now meilisearch
log "✓ Meilisearch läuft"

# ─── 5. Python-Venvs ────────────────────────────────────────────────
log "=== Phase 5: Python-Venvs ==="

# Whisper
if [ ! -d "$HOME/whisper_light" ]; then
    python3 -m venv "$HOME/whisper_light"
    "$HOME/whisper_light/bin/pip" install faster-whisper
    mkdir -p "$HOME/.openclaw/speech_models"
    log "✓ Whisper (base) installiert"
fi

# OCR
if [ ! -d "$HOME/imgocr" ]; then
    python3 -m venv "$HOME/imgocr"
    "$HOME/imgocr/bin/pip" install opencv-python-headless numpy
    log "✓ OCR-Venv installiert"
fi

# beem (Hive-Zugriff)
pip3 install beem 2>/dev/null || true
log "✓ Python-Tools (beem) installiert"

# ─── 6. Wiki (nginx) ────────────────────────────────────────────────
log "=== Phase 6: Wiki (nginx) ==="
if [ -f "$HOME/.openclaw/workspace/AchimsDaten/wiki_contents/index.html" ]; then
    rm -f /var/www/html/wiki 2>/dev/null
    ln -sf "$HOME/.openclaw/workspace/AchimsDaten/wiki_contents" /var/www/html/wiki
fi
systemctl restart nginx || true
log "✓ Nginx konfiguriert"

# ─── 7. Cron-Job für Backup ─────────────────────────────────────────
log "=== Phase 7: Cron-Job ==="
if ! crontab -u achim -l 2>/dev/null | grep -q backup_home; then
    (crontab -u achim -l 2>/dev/null; echo "30 5 * * * /home/achim/.openclaw/scripts/backup_home.sh") | crontab -u achim -
    log "✓ Cron-Job eingerichtet"
fi

# ─── 8. Wiki-Index ---────────────────────────────────────────────────
log "=== Phase 8: Meilisearch-Index ==="
if [ -f "$HOME/.openclaw/agents/helbardor/index_all_files.py" ]; then
    cd "$HOME/.openclaw/agents/helbardor"
    su -c "cd $HOME/.openclaw/agents/helbardor && python3 index_all_files.py 2>/dev/null" achim || log "⚠ Index aufbauen später per Hand: cd ~/.openclaw/agents/helbardor && python3 index_all_files.py"
fi

# ─── 9. Berechtigungen ──────────────────────────────────────────────
chown -R achim:achim "$HOME" 2>/dev/null || true

# ─── Fertig! ─────────────────────────────────────────────────────────
echo ""
echo "========================================================"
echo "  ✅ Setup abgeschlossen!"
echo ""
echo "  Nächste Schritte:"
echo "    1. Als achim neu einloggen:   su - achim"
echo "    2. OpenClaw testen:           openclaw gateway status"
echo "    3. SSH-Keys prüfen"
echo "    4. Wiki besuchen:             http://$(hostname -I | awk '{print $1}')/"
echo "========================================================"

Geschrieben am 2026-06-09 für mein persönliches Wiki von mir Achim Mertens mit Hilfe von Openclaw

Backup und Restore meines Raspberry Pi mit Openclaw | Ecency