LensHub/ docs / backup
Self-hosting

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 backup

Every BACKUP_INTERVAL_HOURS (default 24) it writes one set into BACKUP_DIR (default ./backups):

FileHolds
db.dumpThe whole database, pg_dump custom format
uploads.tar.gz, attachments.tar.gzUploaded files and files pulled in by connectors
SHA256SUMSChecked before any restore touches anything
manifest.txtWhen, 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.sh

Restoring

scripts/restore.sh lenshub-20260101T020000Z

It 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.

On this page