Achim Mertens avatar

Backup und Restore meines Raspberry Pi mit Openclaw

achimmertens

Published: 10 Jun 2026 β€Ί Updated: 10 Jun 2026Backup und Restore meines Raspberry Pi mit Openclaw

Backup und Restore meines Raspberry Pi mit Openclaw

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 GBβœ… muss 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

Leave Backup und Restore meines Raspberry Pi mit Openclaw to:

Written by

Love also your next but one and create more than you destroy.

Read more #doku posts


Best Posts From Achim Mertens

We have not curated any of achimmertens's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From Achim Mertens