Backup & Restore

Hugin’s data lives in a single SQLite file (~/.hugin/hugin.db) plus the auxiliary directories under ~/.hugin/. The built-in Backup subsystem snapshots the SQLite database — atomically, via SQLite’s VACUUM INTO — into ~/.hugin/backups/ (or a custom directory).

🔗What Gets Backed Up

A database backup contains the live SQLite snapshot at the moment the backup ran:

  • All flows, findings, projects, scope, intercept rules
  • Repeater history, intruder configs, organiser entries
  • Environments, scheduled jobs
  • Any other data persisted in hugin.db

What’s not in a database backup:

  • config.toml — config-as-code; back up your ~/.hugin/config.toml separately
  • CA certificate + private key (Hugin-Proxy-CA.pem + -key.pem)
  • Lua extensions (~/.hugin/extensions/)
  • Synaps modules (~/.hugin/modules/)
  • Dynamic MCP plugins (~/.hugin/plugins/)
  • Hosted files (~/.hugin/hosted/)
  • Wordlists (~/.hugin/wordlists/)

For a full disaster-recovery snapshot, archive the entire ~/.hugin/ directory.

🔗Configuration

The [backup] section of ~/.hugin/config.toml:

[backup]
enabled = false              # off by default; flip to true for auto-backup
interval_minutes = 30        # auto-backup interval when enabled
max_backups = 10             # retention — older backups auto-pruned
# backup_dir = "/custom/path"  # default: ~/.hugin/backups/

When enabled = true, Hugin runs a background task that snapshots the database every interval_minutes. Older snapshots beyond max_backups are deleted to bound disk usage.

🔗Manual Backup (UI / API)

There’s no hugin backup CLI command. Backups are triggered through the desktop UI or the REST API.

🔗REST API

GET    /api/backup           List existing backups
POST   /api/backup/create    Create a backup now
POST   /api/backup/restore   Restore from a named backup
POST   /api/backup/delete    Delete a specific backup

backup_create calls HuginStore::backup_to() which uses SQLite’s VACUUM INTO — atomic, non-blocking, safe to run while the proxy is active.

🔗UI

Settings → Advanced exposes the backup operations: list, create, restore, delete.

🔗Restore

Restoring replaces the live hugin.db with the chosen backup. The proxy briefly pauses while the file is swapped, then resumes. Active proxy connections may need to reconnect.

Restore is invoked via POST /api/backup/restore with the backup’s filename. Done from the UI’s backup list with a Restore action.

🔗CA Backup

The CA cert and private key under ~/.hugin/ are not in the database backup. To preserve them across re-installs (so existing browsers continue trusting Hugin’s MITM):

cp ~/.hugin/Hugin-Proxy-CA.pem ~/secure-vault/
cp ~/.hugin/Hugin-Proxy-CA-key.pem ~/secure-vault/

To restore on a fresh install, copy them back into ~/.hugin/ before the first hugin start — Hugin uses the existing CA instead of generating a new one.

🔗Off-Site Backups

Hugin doesn’t ship cloud backup. Common patterns:

  • rsync to a NAS — schedule a cron job that rsyncs ~/.hugin/backups/ (or the whole ~/.hugin/) to a NAS or remote host
  • Duplicity / restic / Borg — run any standard backup tool against ~/.hugin/
  • Encrypted archivetar -czf - ~/.hugin | gpg -c > hugin-$(date +%F).tar.gz.gpg

For automated backup-then-ship workflows, combine the auto-backup feature with a Scheduler job that runs an rsync / upload command after each backup interval.

🔗Project Bundle vs Database Backup

Two different things:

Database Backup.huginproject Bundle
ScopeAll projects, all dataOne project
MechanismVACUUM INTO SQLite snapshotzstd-compressed JSON export
Use caseDisaster recovery / point-in-timeHand-off / archive of one engagement
Restore replacesThe live databaseImports as a new project

For periodic disaster-recovery snapshots: use database backup. For sharing one engagement with a teammate: use project bundle export.

🔗Database Size

Healthy database sizes:

  • 100 MB — small project (~10k flows, no large bodies)
  • 1 GB — medium project (~100k flows, mixed body sizes)
  • 10 GB+ — large engagement (heavy crawling, long retention)

If the database grows faster than expected, check [storage].max_body_size in your config — large response bodies are the usual culprit. Default is 10 MB; lower it for projects where bodies don’t matter.