Backup and restore
What to back up, and what happens if you lose it.
Two things matter
The database. All your content, users, settings and memories.
ENCRYPTION_KEY. Without it, the credentials in a restored database cannot
be decrypted. The backup still restores — every connector just has to be
re-authenticated by hand.
Store ENCRYPTION_KEY somewhere other than the machine it runs on. A backup
you cannot decrypt is a list of things you will have to redo.
Scheduled backups
The compose file has a backup service. It is off until you start it:
docker compose --profile backup up -d backupEvery BACKUP_INTERVAL_HOURS (default 24) it writes one set into
BACKUP_DIR (default ./backups):
| File | Holds |
|---|---|
db.dump | The whole database, pg_dump custom format |
uploads.tar.gz, attachments.tar.gz | Uploaded files and files pulled in by connectors |
SHA256SUMS | Checked before any restore touches anything |
manifest.txt | When, which Postgres, and row counts to compare after a restore |
A set is written under a temporary name and renamed when complete, so a
backup that crashes halfway never looks like a good one. The newest
BACKUP_KEEP sets (default 14) are kept. The schedule goes by the age of
the newest set, so restarting the service neither skips a backup nor takes
an extra one.
BACKUP_DIR is on the LensHub host. Copy it somewhere that host cannot
reach, with whatever you already use (rsync, restic, object storage), so a
compromise does not take the backups with it.
To take a set now:
scripts/backup.shRestoring
scripts/restore.sh lenshub-20260101T020000ZIt asks for confirmation. Then it stops the api, worker and web, checks the
set's checksums, recreates the database from db.dump, and replaces the
uploads and attachments with the set's copies. Then it starts everything
again and prints the backup's row counts next to the restored ones.
Use the same ENCRYPTION_KEY as the instance that made the set.
Test it
An untested backup is a hope. The backup and restore scripts are tested on every change: a round trip against a real schema, where data is damaged, restored and checked, including vectors and files. A tampered set is also refused. That proves the scripts, not your copy. Restore into a throwaway instance occasionally and confirm you can sign in and search.
What you do not need to back up
Container images, cloned repositories, downloaded model files. All re-fetched automatically.