# 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

<table id="bkmrk-resource-typenamepur"><thead><tr><th>Resource Type</th><th>Name</th><th>Purpose</th></tr></thead><tbody><tr><td>Resource Group</td><td>`alai-backups-rg`</td><td>Isolation boundary for backup storage</td></tr><tr><td>Storage Account</td><td>`alaibackups0ebb`</td><td>Blob storage (LRS, Standard tier)</td></tr><tr><td>Container</td><td>`system-db-backups`</td><td>SQLite databases (hivemind.db, mission-control.db, etc.)</td></tr><tr><td>Container</td><td>`system-git-bundles`</td><td>Git repository bundles</td></tr><tr><td>Service Principal</td><td>`alai-backup-writer`</td><td>Scoped write-only access (Storage Blob Data Contributor)</td></tr></tbody></table>

## 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 <<eof azure_client_id="<sp-app-id>" azure_client_secret="<sp-secret>" azure_storage_account="alaibackups0ebb" azure_storage_connection_string="<connection-string>" azure_tenant_id="<tenant-id>" chmod="" eof=""></eof>
```

## Lifecycle Policy

**Hot → Cool:** 30 days  
**Cool → Archive:** 90 days  
**Archive → Delete:** 365 days  
**Delete blobs:** Last modified &gt; 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
```

2. **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
```

3. **Verify SHA-256 checksum:**

```
shasum -a 256 /tmp/restore-lightrag.tar.gz
```

4. **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"
```