diff --git a/.env.demo b/.env.demo index 8e58c068..e6f406a7 100644 --- a/.env.demo +++ b/.env.demo @@ -350,6 +350,20 @@ WEBHOOK_ENABLED=True UPTIME_KUMA_URL=https://status.example.com/api/push/abcdef123456?status=up UPTIME_KUMA_PING_INTERVAL=5 +# Backup & Restore +# Enable automatic scheduled backups (hourly, daily, weekly) +BACKUP_ENABLED=True +# Directory for local backup archives (defaults to /backups) +# BACKUP_DIR=/data/backups +# Optional remote destination: s3, dropbox, google_drive, onedrive, nextcloud, webdav, ftp, sftp, email +# BACKUP_REMOTE_DESTINATION=s3 +# Sub-folder used when uploading backup archives to the remote destination +BACKUP_REMOTE_FOLDER=backups +# Retention: number of snapshots to keep per tier +BACKUP_RETAIN_HOURLY=96 # 4 days of hourly snapshots +BACKUP_RETAIN_DAILY=21 # 3 weeks of daily snapshots +BACKUP_RETAIN_WEEKLY=13 # ~3 months of weekly snapshots + # **Full-Text Search (Meilisearch)** # URL for the Meilisearch instance. # Default is "http://meilisearch:7700" — the Docker Compose / K8s service name — diff --git a/app/models.py b/app/models.py index 99eaf412..811c6fb4 100644 --- a/app/models.py +++ b/app/models.py @@ -384,9 +384,9 @@ class BackupRecord(Base): - ``hourly`` – kept for up to 4 days (96 snapshots) - ``daily`` – kept for up to 3 weeks (21 snapshots) - ``weekly`` – kept for up to 13 weeks (≈ 90 days) - ``location`` is ``local`` when the file is stored on-disk under the - configured backup directory, or ``remote`` when it has been uploaded to - a storage provider or sent via e-mail. + ``local_path`` is the full filesystem path of the local copy (``None`` + once pruned). ``remote_destination`` and ``remote_path`` describe the + remote copy when one has been uploaded to a storage provider or e-mailed. """ __tablename__ = "backup_records" diff --git a/app/views/backup.py b/app/views/backup.py index f4fd2480..4b72c811 100644 --- a/app/views/backup.py +++ b/app/views/backup.py @@ -3,6 +3,7 @@ Backup management dashboard view – admin only. """ import logging +import os from fastapi import Depends, HTTPException, Request, status from sqlalchemy.orm import Session @@ -31,8 +32,6 @@ async def backup_dashboard(request: Request, db: Session = Depends(get_db)): counts[r.backup_type] += 1 # Compute total local size - import os - total_size = sum(r.size_bytes for r in records if r.local_path and os.path.exists(r.local_path)) return templates.TemplateResponse( diff --git a/docs/ConfigurationGuide.md b/docs/ConfigurationGuide.md index 25068635..4da60fe4 100644 --- a/docs/ConfigurationGuide.md +++ b/docs/ConfigurationGuide.md @@ -887,6 +887,33 @@ Configurations are stored in the database and managed through the API (see [API Webhook URLs, secrets, and subscribed events are configured per-webhook via the `/api/webhooks/` endpoints (admin access required). Each delivery includes an optional HMAC-SHA256 signature for verification and is retried with exponential backoff on failure. +### Backup & Restore + +DocuElevate can automatically back up the SQLite database on a scheduled basis. +Backups are managed from the **Admin → Backup & Restore** dashboard. + +| **Variable** | **Description** | **Default** | +|--------------------------------|-----------------------------------------------------------------------------------------------|---------------------| +| `BACKUP_ENABLED` | Enable or disable automatic scheduled backups (`True`/`False`). | `True` | +| `BACKUP_DIR` | Filesystem path where local backup archives are stored. Defaults to `/backups`. | *(workdir/backups)* | +| `BACKUP_REMOTE_DESTINATION` | Storage provider to copy backups to. Options: `s3`, `dropbox`, `google_drive`, `onedrive`, `nextcloud`, `webdav`, `ftp`, `sftp`, `email`. Leave empty for local-only storage. | *(empty)* | +| `BACKUP_REMOTE_FOLDER` | Sub-folder / key prefix used when uploading to the remote destination. | `backups` | +| `BACKUP_RETAIN_HOURLY` | Number of hourly snapshots to keep (1 per hour = 96 covers 4 days). | `96` | +| `BACKUP_RETAIN_DAILY` | Number of daily snapshots to keep (21 = 3 weeks). | `21` | +| `BACKUP_RETAIN_WEEKLY` | Number of weekly snapshots to keep (13 ≈ 3 months). | `13` | + +**Retention schedule:** + +| Tier | Frequency | Default retention | Coverage | +|---------|------------------|-------------------|--------------| +| Hourly | Every hour | 96 snapshots | ~4 days | +| Daily | Daily at 02:00 | 21 snapshots | ~3 weeks | +| Weekly | Sundays at 03:00 | 13 snapshots | ~3 months | + +Archives beyond the retention window are automatically pruned after each new backup. The **Clean Up** button on the dashboard applies retention immediately. When a remote destination is configured, remote copies follow the same retention policy. + +> **Note:** Backup and restore is currently supported only for SQLite databases. + ### Uptime Kuma | **Variable** | **Description** | @@ -1223,6 +1250,15 @@ S3_ACL=private # Uptime Kuma UPTIME_KUMA_URL=https://kuma.example.com/api/push/abcde12345?status=up UPTIME_KUMA_PING_INTERVAL=5 + +# Backup & Restore +BACKUP_ENABLED=True +BACKUP_DIR=/data/backups +BACKUP_REMOTE_DESTINATION=s3 # or dropbox, google_drive, onedrive, nextcloud, webdav, ftp, sftp, email +BACKUP_REMOTE_FOLDER=backups +BACKUP_RETAIN_HOURLY=96 +BACKUP_RETAIN_DAILY=21 +BACKUP_RETAIN_WEEKLY=13 ``` ## Selective Service Configuration diff --git a/frontend/templates/backup.html b/frontend/templates/backup.html index cc8f9f3a..58423eea 100644 --- a/frontend/templates/backup.html +++ b/frontend/templates/backup.html @@ -45,13 +45,38 @@ - -