#!/usr/bin/env bash # Homeio factory reset # # Wipes all application state and user data, then reboots the machine into a # clean installation. This script is scheduled as a transient systemd unit by # power-service.ts and must never be run interactively. # # Required environment variables (injected via systemd-run --setenv): # DATABASE_URL PostgreSQL connection string # HOMEIO_RESET_DATA_ROOT Path to the data root directory (e.g. /DATA) # HOMEIO_RESET_STACKS_ROOT Path to the Docker Compose stacks root # HOMEIO_RESET_WORKDIR Working directory of the Homeio application # HOMEIO_RESET_NPM_BIN Absolute path to the npm binary # # Subdirectories recreated under HOMEIO_RESET_DATA_ROOT must stay in sync with # DATA_SUBDIRECTORIES in lib/server/storage/data-root.ts. # -uo pipefail: fail on unbound vars and pipe errors. # -e is intentionally omitted: individual step failures are logged but do not # abort the reset — the machine must always reach the reboot step. set -uo pipefail FACTORY_RESET_LOG='/var/log/homeio-factory-reset.log' sleep 2 mkdir -p "$(dirname "${FACTORY_RESET_LOG}")" exec >> "${FACTORY_RESET_LOG}" 2>&1 echo "[$(date -Is)] Starting Homeio factory reset" # ── Validate required env vars ──────────────────────────────────────────────── : "${DATABASE_URL:?DATABASE_URL is required}" : "${HOMEIO_RESET_DATA_ROOT:?HOMEIO_RESET_DATA_ROOT is required}" : "${HOMEIO_RESET_STACKS_ROOT:?HOMEIO_RESET_STACKS_ROOT is required}" : "${HOMEIO_RESET_WORKDIR:?HOMEIO_RESET_WORKDIR is required}" : "${HOMEIO_RESET_NPM_BIN:?HOMEIO_RESET_NPM_BIN is required}" cd "${HOMEIO_RESET_WORKDIR}" export DATABASE_URL # ── Step 1: Stop the application ────────────────────────────────────────────── systemctl stop home-server.service || true # ── Step 2: Reset the database (before any destructive file ops) ────────────── # Running db:reset first ensures the DB is wiped even if the data root is later # inaccessible. Failure is logged but does not abort — we keep going. echo "[$(date -Is)] Resetting database" "${HOMEIO_RESET_NPM_BIN}" run db:reset --silent \ && echo "[$(date -Is)] Database reset OK" \ || echo "[$(date -Is)] WARNING: database reset failed, continuing" # ── Step 3: Remove stacks root ──────────────────────────────────────────────── # STORE_STACKS_ROOT may live outside the data root (e.g. /var/lib/home-server/stacks). # Removing it explicitly ensures no orphaned compose files survive the wipe. rm -rf "${HOMEIO_RESET_STACKS_ROOT}" || true # ── Step 4: Docker cleanup ──────────────────────────────────────────────────── if command -v docker >/dev/null 2>&1; then docker ps -aq | xargs -r docker rm -f || true docker volume ls -q | xargs -r docker volume rm -f || true docker network ls --format '{{.Name}}' \ | grep -vxE 'bridge|host|none' \ | xargs -r docker network rm || true docker images -aq | sort -u | xargs -r docker rmi -f || true docker builder prune -af || true docker system prune -af --volumes || true fi # ── Step 5: Wipe data root ──────────────────────────────────────────────────── # Use find -mindepth 1 to delete everything inside without removing the root # directory itself, so the mount point survives if it is a separate partition. if [ -d "${HOMEIO_RESET_DATA_ROOT}" ]; then find "${HOMEIO_RESET_DATA_ROOT}" -mindepth 1 -maxdepth 1 -exec rm -rf {} + else mkdir -p "${HOMEIO_RESET_DATA_ROOT}" fi # ── Step 6: Recreate fresh-install directory structure ──────────────────────── # Mirrors DATA_SUBDIRECTORIES in lib/server/storage/data-root.ts. mkdir -p \ "${HOMEIO_RESET_DATA_ROOT}/AppData" \ "${HOMEIO_RESET_DATA_ROOT}/Documents" \ "${HOMEIO_RESET_DATA_ROOT}/Media" \ "${HOMEIO_RESET_DATA_ROOT}/Download" \ "${HOMEIO_RESET_DATA_ROOT}/.Shared" \ "${HOMEIO_RESET_DATA_ROOT}/.Network" \ "${HOMEIO_RESET_DATA_ROOT}/.Trash" echo "[$(date -Is)] Factory reset complete; rebooting" # ── Step 7: Reboot ──────────────────────────────────────────────────────────── systemctl reboot