Spaces:
Runtime error
Runtime error
File size: 4,855 Bytes
46252cd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | #!/usr/bin/env bash
#
# OpenWA backup.
#
# Captures the load-bearing state needed to restore a working install:
# - main.sqlite β auth (API keys) + audit log, ALWAYS SQLite (see app.module.ts)
# - data store β openwa.sqlite (SQLite) OR a pg_dump (when DATABASE_TYPE=postgres)
# - sessions/ β whatsapp-web.js LocalAuth session data
# - baileys/ β Baileys engine authentication state
# - media/ β locally-stored media (skipped automatically when using S3)
# - plugin-packages/ β installed plugin packages from PLUGINS_DIR
# - plugin-state/ β registry and persisted ctx.storage state under OPENWA_DATA_DIR
# - .env.generated and .api-key β dashboard config and plaintext bootstrap admin key
#
# The previous runbook backed up the wrong file (openwa.db) and omitted main.sqlite,
# so a "successful" backup silently lost every API key and all audit history.
#
# Usage:
# ./scripts/backup.sh
# Environment:
# OPENWA_DATA_DIR data directory (default: ./data)
# BACKUP_DIR where archives are written (default: ./backups)
# DATABASE_TYPE sqlite (default) | postgres
# SESSION_DATA_PATH, BAILEYS_AUTH_DIR, STORAGE_LOCAL_PATH, PLUGINS_DIR
# override the corresponding state directories
# For postgres: DATABASE_URL, or DATABASE_HOST/PORT/USERNAME/PASSWORD/NAME
#
set -euo pipefail
# The archive now contains bootstrap credentials and generated database secrets. Never inherit a
# permissive operator umask for newly-created backup artifacts.
umask 077
DATA_DIR="${OPENWA_DATA_DIR:-./data}"
BACKUP_DIR="${BACKUP_DIR:-./backups}"
DATABASE_TYPE="${DATABASE_TYPE:-sqlite}"
TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
MAIN_DB="$DATA_DIR/main.sqlite"
DATA_DB="$DATA_DIR/openwa.sqlite"
SESSIONS_DIR="${SESSION_DATA_PATH:-$DATA_DIR/sessions}"
BAILEYS_DIR="${BAILEYS_AUTH_DIR:-$DATA_DIR/baileys}"
MEDIA_DIR="${STORAGE_LOCAL_PATH:-$DATA_DIR/media}"
PLUGIN_PACKAGES_DIR="${PLUGINS_DIR:-./plugins}"
PLUGIN_STATE_DIR="$DATA_DIR/plugins"
GENERATED_ENV="$DATA_DIR/.env.generated"
ADMIN_KEY_FILE="$DATA_DIR/.api-key"
log() { echo "[backup] $*"; }
STAGE="$(mktemp -d)"
trap 'rm -rf "$STAGE"' EXIT
# Online SQLite backup (consistent without stopping the app) when sqlite3 is present,
# else a plain copy with a warning.
backup_sqlite() {
src="$1"
dest="$2"
if [ ! -f "$src" ]; then
log "WARN: $src not found β skipping"
return 0
fi
if command -v sqlite3 >/dev/null 2>&1; then
sqlite3 "$src" ".backup '$dest'"
else
log "WARN: sqlite3 not found β plain-copying $src (stop the app first for a consistent copy)"
cp "$src" "$dest"
fi
}
log "Backing up auth/audit DB (main.sqlite) β the API-key + audit store"
backup_sqlite "$MAIN_DB" "$STAGE/main.sqlite"
if [ "$DATABASE_TYPE" = "postgres" ]; then
log "Backing up data store via pg_dump"
if ! command -v pg_dump >/dev/null 2>&1; then
log "ERROR: DATABASE_TYPE=postgres but pg_dump is not installed"
exit 1
fi
if [ -n "${DATABASE_URL:-}" ]; then
pg_dump "$DATABASE_URL" >"$STAGE/database.sql"
else
PGPASSWORD="${DATABASE_PASSWORD:-}" pg_dump \
-h "${DATABASE_HOST:-localhost}" \
-p "${DATABASE_PORT:-5432}" \
-U "${DATABASE_USERNAME:-openwa}" \
"${DATABASE_NAME:-openwa}" >"$STAGE/database.sql"
fi
else
log "Backing up data store (openwa.sqlite)"
backup_sqlite "$DATA_DB" "$STAGE/openwa.sqlite"
fi
if [ -d "$SESSIONS_DIR" ]; then
log "Backing up whatsapp-web.js sessions"
cp -pR "$SESSIONS_DIR" "$STAGE/sessions"
else
log "WARN: $SESSIONS_DIR not found β skipping sessions"
fi
if [ -d "$BAILEYS_DIR" ]; then
log "Backing up Baileys authentication state"
cp -pR "$BAILEYS_DIR" "$STAGE/baileys"
elif [ "${ENGINE_TYPE:-}" = "baileys" ]; then
log "WARN: ENGINE_TYPE=baileys but $BAILEYS_DIR was not found β restored sessions will require pairing"
fi
if [ -d "$MEDIA_DIR" ]; then
log "Backing up local media"
cp -pR "$MEDIA_DIR" "$STAGE/media"
fi
if [ -d "$PLUGIN_PACKAGES_DIR" ]; then
log "Backing up installed plugin packages"
cp -pR "$PLUGIN_PACKAGES_DIR" "$STAGE/plugin-packages"
fi
if [ -d "$PLUGIN_STATE_DIR" ]; then
log "Backing up plugin registry and persisted state"
cp -pR "$PLUGIN_STATE_DIR" "$STAGE/plugin-state"
fi
if [ -f "$GENERATED_ENV" ]; then
log "Backing up dashboard-generated configuration"
cp -p "$GENERATED_ENV" "$STAGE/.env.generated"
fi
if [ -f "$ADMIN_KEY_FILE" ]; then
log "Backing up plaintext admin key"
cp -p "$ADMIN_KEY_FILE" "$STAGE/.api-key"
fi
mkdir -p "$BACKUP_DIR"
ARCHIVE="$BACKUP_DIR/openwa-backup-$TIMESTAMP.tar.gz"
tar -czf "$ARCHIVE" -C "$STAGE" .
log "Backup complete: $ARCHIVE"
log "SECURITY: this archive can contain database passwords, plugin secrets, and an admin API key; restrict and encrypt it"
log "Contents:"
tar -tzf "$ARCHIVE" | sed 's/^/[backup] /'
|