Run your server

Backups and restore

Keep a copy of your database off the server, and bring it back when you need it.

imbox docs

Your database holds all your mail, contacts, Screener decisions and secrets. A backup of it, plus your SESSION_SECRET and, if you encrypt backups, your backup key, is everything you need to rebuild imbox on a new machine. Attachments are fetched from your mail provider on demand, so a backup stays small.

A backup is not enough on its own

Keep SESSION_SECRET with your backups, in a different place from the server. A restored database with a different secret can't decrypt saved mailbox passwords, AI keys or two-factor secrets.

Backups hold all of your mail

A plain dump can be read by anyone who gets a copy. Encrypt backups so the server never holds a key that opens them. See Encrypt them.

Loading diagram...

What happens on its own

A server set up with the script makes a backup every night at 03:17 server time. Each is a compressed dump in /var/backups/imbox, named imbox-YYYYMMDDTHHMMSSZ.sql.gz, or .sql.gz.age once you encrypt them. They are readable only by root. Files older than 14 days are deleted. The log is /var/log/imbox-backup.log.

These live on the same machine, so they protect you from a mistake, not from losing the server. Copy them somewhere else too.

Encrypt them

A plain dump holds everything, so anyone who gets a copy can read your mail. imbox can encrypt each backup with age before it is written. It encrypts to a public key, so the server never holds anything that can open its own backups. Only the matching private key can, and you keep that somewhere else.

  1. On your own computer, make a key pair. Install age first (brew install age, or sudo apt-get install age).

    age-keygen -o imbox-backup.key

    It prints a line starting Public key: age1.... The file holds the private key.

  2. Put the private key in a password manager and keep a copy off the server. Without it, encrypted backups can't be opened. Never put it on the server.

  3. On the server, add the public key to /etc/imbox/backup.env:

    BACKUP_AGE_RECIPIENT=age1...your-public-key
  4. Run a backup to check. It should say backup ok (encrypted):

    sudo imbox-backup

From then on every nightly file ends in .sql.gz.age, and so does the copy sent to S3. If a backup can't be encrypted, for example because age is missing, it fails and says so in the log. It never falls back to a plain file. Without BACKUP_AGE_RECIPIENT a backup still works but the log line says NOT encrypted.

Servers made with the script before this was added need sudo apt-get install age, and the new imbox-backup from deploy/backup.sh.

Copy them off the server

The script installs the AWS command line tool for this. Create /etc/imbox/backup.env:

S3_BUCKET=your-bucket-name

Each night's file is then copied to s3://your-bucket-name/imbox/. The server needs permission to write to the bucket. The simplest way is an IAM role on the instance. If you use keys instead, put them in the same file as export lines:

export AWS_ACCESS_KEY_ID=your-key
export AWS_SECRET_ACCESS_KEY=your-secret
export AWS_DEFAULT_REGION=eu-west-1

Run one backup by hand to check it works:

sudo imbox-backup

It prints backup ok: and the file name.

Make a backup now

Before a risky change, take one yourself.

Server:

sudo -u postgres pg_dump imbox | gzip > imbox-backup-$(date +%Y%m%d).sql.gz

To encrypt it as the nightly one is, add age with your public key:

sudo -u postgres pg_dump imbox | gzip | age -r age1...your-public-key > imbox-backup-$(date +%Y%m%d).sql.gz.age

Docker Compose:

docker compose exec -T db pg_dump -U inbox inbox | gzip > inbox-backup-$(date +%Y%m%d).sql.gz

Restore

Restoring replaces the whole database with the backup. Anything that arrived after the backup is fetched again from your mail providers at the next sync.

A file ending in .age is encrypted. Decrypt it first with your private key, imbox-backup.key. Do this on a machine you trust, or copy the key to the server only for the restore and delete it after.

age -d -i imbox-backup.key imbox-YYYYMMDDTHHMMSSZ.sql.gz.age > imbox-restore.sql.gz

Then restore the .sql.gz file.

Server:

sudo systemctl stop imbox
sudo -u postgres dropdb imbox && sudo -u postgres createdb -O imbox imbox
gunzip -c imbox-restore.sql.gz | sudo -u postgres psql inbox
sudo systemctl start imbox

For a plain nightly file, use /var/backups/imbox/imbox-YYYYMMDDTHHMMSSZ.sql.gz in place of imbox-restore.sql.gz.

Docker Compose:

docker compose stop imbox
docker compose exec -T db dropdb -U inbox inbox
docker compose exec -T db createdb -U inbox inbox
gunzip -c inbox-restore.sql.gz | docker compose exec -T db psql -U inbox inbox
docker compose start imbox

Then check curl -s http://127.0.0.1:8787/healthz and sign in.

On a new server

  1. Do the install on the new machine.
  2. Before you start the app, put the old SESSION_SECRET in /etc/imbox/imbox.env. Add BACKUP_AGE_RECIPIENT to /etc/imbox/backup.env again, with the same public key.
  3. Restore the dump as above.
  4. Point your domain at the new address.

Test it once

A backup you have never restored is a guess. Once, on a spare machine or a local Docker setup, restore a file, decrypting it with your private key if it is encrypted, and sign in. It takes ten minutes and tells you whether the backup works.