Skip to main content

Azure Blob Offsite Backup Setup

Azure Blob Offsite Backup Setup

Overview

Purpose: Offsite backup for ALAI system databases and git bundles
Region: North Europe (Dublin) — geographic separation from primary Sweden Central VM
Retention: 365 days with lifecycle policies (Hot → Cool → Archive → Delete)
Recovery Time Objective: 4 hours (manual restore)

Azure Resources

Resource TypeNamePurpose
Resource Groupalai-backups-rgIsolation boundary for backup storage
Storage Accountalaibackups0ebbBlob storage (LRS, Standard tier)
Containersystem-db-backupsSQLite databases (hivemind.db, mission-control.db, etc.)
Containersystem-git-bundlesGit repository bundles
Service Principalalai-backup-writerScoped write-only access (Storage Blob Data Contributor)

Service Principal Setup

# Create service principal
az ad sp create-for-rbac --name alai-backup-writer --skip-assignment

# Assign Storage Blob Data Contributor to SA only (not subscription)
STORAGE_ID=$(az storage account show --name alaibackups0ebb --query id -o tsv)
az role assignment create \
  --assignee <service-principal-app-id> \
  --role "Storage Blob Data Contributor" \
  --scope "$STORAGE_ID"

# Store credentials in ~/system/config/azure-backup.env
cat > ~/system/config/azure-backup.env <

Lifecycle Policy

Hot → Cool: 30 days
Cool → Archive: 90 days
Archive → Delete: 365 days
Delete blobs: Last modified > 365 days

az storage account management-policy create \
  --account-name alaibackups0ebb \
  --policy @lifecycle-policy.json

lifecycle-policy.json:

{
  "rules": [
    {
      "enabled": true,
      "name": "archive-old-backups",
      "type": "Lifecycle",
      "definition": {
        "actions": {
          "baseBlob": {
            "tierToCool": {"daysAfterModificationGreaterThan": 30},
            "tierToArchive": {"daysAfterModificationGreaterThan": 90},
            "delete": {"daysAfterModificationGreaterThan": 365}
          }
        },
        "filters": {"blobTypes": ["blockBlob"]}
      }
    }
  ]
}

Backup Scripts

LightRAG to Azure Blob

#!/bin/bash
# ~/system/tools/migrate-lightrag-to-azure.sh

source ~/system/config/azure-backup.env
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="/tmp/lightrag-backup-$TIMESTAMP.tar.gz"

tar -czf "$BACKUP_FILE" ~/system/lightrag/
az storage blob upload \
  --account-name alaibackups0ebb \
  --container-name system-db-backups \
  --name "lightrag-$TIMESTAMP.tar.gz" \
  --file "$BACKUP_FILE" \
  --auth-mode login

rm "$BACKUP_FILE"

Ollama Models Export

#!/bin/bash
# ~/system/tools/ollama-models-export.sh --azure

source ~/system/config/azure-backup.env
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
EXPORT_DIR="/tmp/ollama-export-$TIMESTAMP"

mkdir -p "$EXPORT_DIR"
ollama list | tail -n +2 | awk '{print $1}' > "$EXPORT_DIR/model-list.txt"

while read -r model; do
  ollama show "$model" --modelfile > "$EXPORT_DIR/$model.modelfile"
done < "$EXPORT_DIR/model-list.txt"

tar -czf "$EXPORT_DIR.tar.gz" "$EXPORT_DIR"
az storage blob upload \
  --account-name alaibackups0ebb \
  --container-name system-db-backups \
  --name "ollama-models-$TIMESTAMP.tar.gz" \
  --file "$EXPORT_DIR.tar.gz"

rm -rf "$EXPORT_DIR" "$EXPORT_DIR.tar.gz"

Disaster Recovery Path

  1. List available backups:
az storage blob list \
  --account-name alaibackups0ebb \
  --container-name system-db-backups \
  --output table
  1. Download latest backup:
az storage blob download \
  --account-name alaibackups0ebb \
  --container-name system-db-backups \
  --name "lightrag-20260420-143000.tar.gz" \
  --file /tmp/restore-lightrag.tar.gz
  1. Verify SHA-256 checksum:
shasum -a 256 /tmp/restore-lightrag.tar.gz
  1. Restore to target system:
tar -xzf /tmp/restore-lightrag.tar.gz -C ~/system/

Monitoring

  • Cron: Hourly backup at :15 (15 * * * *)
  • Log: ~/system/logs/azure-backup.log
  • Alert: HiveMind alert if backup fails 2 consecutive runs
node ~/system/agents/hivemind/hivemind.js post john alert \
  "Azure backup failed 2 consecutive runs — check ~/system/logs/azure-backup.log"