Backup and restore
Daily backups of a running Nixt Server node, bringing one person's mail back from them, snapshots of a stopped node, keeping the keys safe, restoring, and practising a restore.
Nixt Server keeps two kinds of backup:
- Daily backups of a running node, taken by the node itself into a directory you name. They are sealed with a backup key of their own, copy only what is new each day, are read back as soon as they are taken, and are what an administrator brings one person’s lost mail back from. See Daily backups.
- Snapshots of a stopped node, taken by hand with
versealx-server backup, which restore a whole node. See Taking a snapshot.
Daily backups
Turning them on
-
Make a backup key. It is written where only the service user can read it, and never printed:
sudo -u versealx versealx-server backups key /etc/versealx-server/backup.keywrote a new backup key to /etc/versealx-server/backup.key. Name it as [backup] key_file, and keep a copy somewhere other than the backups: without it they cannot be read.The command never writes over an existing file.
-
Copy the key somewhere safe, away from where the backups go.
-
Add a
[backup]table to the configuration:[backup] to = "/var/backups/versealx" key_file = "/etc/versealx-server/backup.key" at = "02:00" keep_daily = 14 keep_weekly = 8 keep_monthly = 12Key What it does toWhere backups go: a directory, as an absolute path (a mounted network share or a separate disk), or an S3-compatible bucket as s3://bucket/prefix, reached as[backup.offsite]describes under A copy away from the database’s provider. Everything in the bucket is sealed, so its provider learns nothing from it.key_fileThe backup key. atWhen each day’s backup starts, as HH:MMin UTC.02:00if left out.keep_dailyHow many days’ backups are kept. At least 1; 14 if left out. keep_weeklyHow many weeks, keeping the newest of each. 8 if left out. keep_monthlyHow many months, keeping the newest of each. 12 if left out. test_weeklyWhether the server proves a backup restores each week (see Testing a restore). On if left out. -
Check the configuration and restart the server:
sudo -u versealx versealx-server check --config /etc/versealx-server/versealx-server.toml sudo systemctl restart versealx-server
On a cluster, one node takes each day’s backup, so the directory must be reachable from every node that runs the store role.
What happens each day
At the time at names, or when the node starts if that time has passed and today’s backup has not been taken:
- The store is read in one transaction and sealed into the backup.
- Every message body the store refers to that the backup directory does not yet hold is copied there, sealed. Bodies already there from earlier days are not copied again.
- The manifest is written last. A backup that stops part way has no manifest and is not counted as a backup.
- The backup is read straight back: every record of the store, and fifty message bodies chosen at random, whose hashes are checked.
- Backups older than
keep_daily,keep_weeklyandkeep_monthlyallow are removed, with any message bodies no remaining backup needs.
If a backup fails, the node tries again an hour later. Each attempt, and why one failed, is kept for the backup-failed alert and for doctor.
What is sealed, and with which key
Everything in the backup directory is encrypted with AES-256-GCM under the backup key, in pieces of one mebibyte. Each piece is tied to its backup and its position, so a piece cannot be moved, reordered, dropped or cut short without being refused when it is read.
The names of the files in a backup, and the list of what each backup holds, are made with the backup key too, so whoever can see the backup directory cannot tell whether a given message or attachment is in it. Each backup’s list is signed with the backup key: a list that was changed, or moved from another backup, is refused when the backup is listed, checked, restored or pruned, and the backup is reported as failed. A daily backup copies only what the last good backup does not already hold at its full size, so a file removed from the destination is copied again the next day.
The first backup after upgrading from an earlier release copies everything once, under the new names. Backups taken before still list, check and restore as they did.
Message bodies are also still encrypted under their tenant’s data key, as they are in the store. Reading a person’s mail from a backup therefore needs both the backup key and the node’s key-encryption key.
Checking the backups
List them, newest first:
sudo -u versealx versealx-server backups list --config /etc/versealx-server/versealx-server.toml
20261006T020000Z 48210 records, 1932 blobs, 12 new (1482110 bytes), on mail-1
20261005T020000Z 48007 records, 1920 blobs, 9 new (903392 bytes), on mail-1
Read one back in full — every record and every message body — or the newest if you name none:
sudo -u versealx versealx-server backups verify 20261006T020000Z --config /etc/versealx-server/versealx-server.toml
20261006T020000Z reads back whole: 48210 records, 1932 blobs checked
Add --sample 200 to check only that many message bodies. Neither command opens the store, so both work while the node runs.
versealx-server doctor says how old the newest backup is. It warns when none has been read back whole in 26 hours, and reports a failed newest backup as broken, with the reason.
backups list and backups verify read a bucket the same way when to names one.
Testing a restore
A backup that has never been restored is a hope. Once a week, the node that takes the daily backups restores the newest into a scratch copy of the server that never listens on the network, opens it with the backup key, checks it holds every record the backup says, and compares up to 200 messages byte for byte with the running server. Then it deletes the scratch copy, whether the test passed or not.
Run one now:
sudo -u versealx versealx-server backups test --config /etc/versealx-server/versealx-server.toml
Each result is written to the installation’s audit log, and doctor shows the last one. A failed test raises the backup-test-failed alert, with what failed.
Backups and residency
Daily backups hold every organisation’s mail. Use site under [backup] to say which of your sites the backups rest in. Before each day’s backup is written, that site is checked against each organisation’s residency.
The backup isn’t taken if the site is outside an organisation’s countries, or if no site is named while any organisation has a residency. It is recorded as failed, naming each organisation and why, and the backup-failed alert goes off. doctor says the same.
If you have decided an organisation’s backups may rest outside its countries, for example because its contract allows it, record an exception with the reason:
sudo -u versealx versealx-server backups residency-exceptions add 4 --reason "Contract 2026-17 allows backups in the US" --config /etc/versealx-server/versealx-server.toml
Backups are then taken for that organisation, and the exception is written to the installation’s audit log. To list the exceptions, run backups residency-exceptions. To hold an organisation’s backups to its residency again, run backups residency-exceptions remove 4. Over the API, the exceptions are at GET and POST /api/v1/backups/residency-exceptions, and DELETE /api/v1/backups/residency-exceptions/{organisation} removes one.
Checking stored mail
Disks and buckets can lose or damage data without saying so. The integrity scrub reads all stored mail back on a schedule, by default once every 30 days ([integrity] scrub_days), paced so that it never competes with mail. While a hundred or more messages are waiting to be delivered on the node, it reads at half its pace until they are. One node runs it at a time. Each pass checks:
- that every message’s stored content is there, and is still the message it was;
- that every record reads;
- that every message’s folder exists;
- that every folder’s counts match its messages;
- that every message belongs to a conversation, as mail apps show it.
It repairs what it can and records each repair in the organisation’s audit log:
- Lost or damaged content is fetched from the standby site’s copy, when
[integrity] standby_blobsnames one, and otherwise from the backups. Either copy is checked against what the message should be before it is put back. - Wrong counts are recounted.
- A message whose folder is gone is moved to a folder called Recovered.
- A message outside any conversation is put back into one, by its references and subject, as it would have been when it arrived.
Anything it can’t repair stays listed, with the people affected but never the content. Each lost or damaged message fires the mail-damaged alert. A mail app is never given damaged content as the message: that one message shows as unavailable, and the rest of the mailbox works.
versealx-server storage scrub status
versealx-server storage scrub now --tenant 3
On the console, the operator’s Integrity page, under System, shows a pass under way, the last pass, each organisation’s findings repaired and not, and Start a scrub for every organisation or one.
scrub now starts a pass straight away, for one organisation or for all. An organisation’s administrators see what was found in their mail on the Stored mail integrity card on Settings, or with versealx-server admin integrity show. Through the API, the operator uses GET /storage/integrity and POST /storage/integrity/scrub, and an organisation uses GET /tenants/{tenant}/integrity.
Bringing somebody’s mail back
When somebody has lost a folder, or more, their mail can be brought back as it was in any daily backup. It comes back into a new folder named Restored and the backup’s date, beside what they have now. Nothing they have is changed or replaced, so you can safely do it more than once.
Organisation administrators, domain administrators for their own domains, and the helpdesk can do this. Auditors can see what was restored.
In the console
- Open People and choose the person.
- In the Backups card, choose the backup to bring the mail back from.
- To bring back one folder and the folders inside it, type its name as the person sees it, such as
InvoicesorProjects/2026. Leave it empty for all of their mail. - Choose Bring it back.
The card lists each restore with what was asked for, who asked, and how it went. The server carries a restore out within a minute.
At the command line
List the backups their mail can come back from, and their restores:
versealx-server admin mailbox backups ada@example.com
Bring back one folder:
versealx-server admin mailbox restore ada@example.com --from 20261006T020000Z --folder 'Invoices'
Leave out --folder to bring back all of their mail.
What comes back
- Each folder, and the folders inside it, under
Restored YYYY-MM-DD: for exampleRestored 2026-10-06/Invoices/2026. - Each message with its flags, such as read or flagged, and the date it first arrived.
- Message bodies the server no longer holds, copied back from the backup.
A restore that would not fit in the person’s or the organisation’s storage limit is refused before anything is written, and says how much room it needs. A folder name the backup does not hold is refused, naming the folder.
Every request, and how it ended, is in the organisation’s audit log.
Snapshots of a stopped node
versealx-server backup writes a snapshot of a node to a directory: the whole store, every message body the store still refers to — including mail waiting in the queue — and a manifest with a hash of every piece. versealx-server restore puts a snapshot back and refuses to write anything if a single hash does not match.
Before you start
- Stop the node. Both commands work on a node that is not running. A snapshot taken while mail is arriving could record a message whose body is not in it.
- Run as the service user, so the files you read and write have the right owner.
- Keep the key file separately. A snapshot does not contain it, and without it the messages in a snapshot cannot be read. See The key file.
Taking a backup
-
Stop the server:
sudo systemctl stop versealx-server -
Take the snapshot into a directory. The directory is created if it does not exist:
sudo -u versealx versealx-server backup /var/backups/versealx/2026-09-14 --config /etc/versealx-server/versealx-server.tomlIt prints what it wrote:
wrote 48210 keys and 1932 blob(s) to /var/backups/versealx/2026-09-14 -
Start the server again:
sudo systemctl start versealx-server -
Copy the snapshot directory somewhere off the machine.
If a message body the store refers to is missing from the blob store, the snapshot is still taken, the log says a referenced blob is missing; it cannot be backed up, and that one message will not come back on restore.
What a snapshot contains
2026-09-14/
manifest.json
store.dat
blobs/
1-<64 hexadecimal characters>
…
| File | Contents |
|---|---|
manifest.json | The format version, when the snapshot was taken, the node’s name, the number of keys, the store file’s size and hash, and each message body’s tenant, id, length and hash. |
store.dat | Everything in the store, read in one transaction. |
blobs/ | Every message body still referred to by a mailbox or a queue entry, named by tenant and id, exactly as stored — still encrypted. |
What is in the store, and so in the snapshot
- Tenants, domains, accounts, groups and aliases.
- Mailboxes, the message index and flags.
- Queued mail waiting for delivery.
- Sieve scripts, vacation settings and identities.
- Password hashes and sign-in state.
- Runtime settings and their history.
- The audit log, message traces and received reports.
- Calendars and address books.
- The server’s own keys: DKIM private keys, the ACME account and certificate, the key that signs sign-in tokens, and each tenant’s data key in wrapped form.
What is not in a snapshot
| Not included | What to do about it |
|---|---|
The key file ([keys] path) | Back it up separately. See below. |
| The configuration file | Back up /etc/versealx-server/versealx-server.toml separately. |
Certificate files ([tls] kind = "files") | Back them up separately, or reissue them. |
| Environment variables such as a relay password | Keep them in your secrets store. |
The key file
Every message body is encrypted with its tenant’s data key, and every tenant’s data key is stored wrapped by the key-encryption key in the file named by [keys] path — /var/lib/versealx-server/kek on a node set up with init.
- The node creates the file the first time it starts and logs
generated a new key-encryption key; back it up. - The file must be readable only by the service user (mode
0600). - A snapshot without the key file is unreadable bytes. The key file without a snapshot unlocks nothing. Store them in different places.
- Restore onto a node that uses the same key file. A node that starts without the file at its path generates a new key, and none of the restored messages can be read with it.
Back it up once, right after the first start:
sudo cp /var/lib/versealx-server/kek /secure/location/versealx-kek
The file does not change unless you rotate the key.
Rotating the key-encryption key
Rotating the key-encryption key wraps every tenant’s data key again under a new key. No message is read or rewritten, so it takes seconds, however much mail the store holds. Stop every node first: a running node would make new tenants’ data keys under the key it started with. The command refuses while a node is running, and says how it knows.
With a key file, name the new key’s file. It is made there if it does not exist:
sudo -u versealx versealx-server keys rotate --new-key-file /var/lib/versealx-server/kek-2026 --config /etc/versealx-server/versealx-server.toml
Made a new key-encryption key at /var/lib/versealx-server/kek-2026.
The store is marked as being rotated: no node starts on it until this is done.
tenant 0 (the installation's own): re-wrapped under the new key
tenant 1: re-wrapped under the new key
tenant 2: re-wrapped under the new key
1 kept receive key(s): under the new key
The key-encryption key is rotated: 3 tenant data key(s) re-wrapped under the new key; 1 kept receive key(s) re-sealed. The store names the new key now. Point [keys] file at /var/lib/versealx-server/kek-2026 and start the nodes. A backup made before the rotation can only be read with the old key, so keep the old key file for as long as you keep those backups.
Then set path in [keys] to the new file on every node, back the new file up, and start the nodes.
With a KMS, the KMS makes the new key and wraps it, by the same KMS key, or by another one if you name it:
sudo -u versealx versealx-server keys rotate --kms
sudo -u versealx versealx-server keys rotate --kms --kms-key arn:aws:kms:eu-west-1:111122223333:key/<new key id>
With the same KMS key, nothing changes in the configuration. With another, set key_id in [keys] to it before starting the nodes.
A rotation that stops part way — a crash, a lost connection to the KMS — loses nothing. The store stays marked, some tenants’ data keys under the new key and the rest under the old, and no node starts on it until it is finished: each refuses with a key rotation is half done; run versealx-server keys rotate again with the same keys. Run the same command again, with the same new key, and it carries on from where it stopped. A different new key is refused while a rotation is half done.
versealx-server doctor says when the key was last rotated, and reports a half-done rotation as broken.
Keep the old key for as long as you keep backups made before the rotation: they can only be read with the key they were taken under. With a KMS, that means keeping the old KMS key enabled, not scheduled for deletion.
Rotating without stopping
With a key file, a cluster can rotate its key with every node running.
-
Make the new key, then copy it to every node and back it up:
sudo -u versealx versealx-server keys new --file /var/lib/versealx-server/kek-2027It is made readable only by its owner, and an existing file is never written over.
-
A node at a time, name the new key in
[keys]and keep the old one beside it, then restart that node:[keys] kind = "file" path = "/var/lib/versealx-server/kek-2027" previous_file = "/var/lib/versealx-server/kek"A node holding both reads mail under either key. Until every node holds both, new keys are still made under the old key, so a node not yet restarted can read everything.
-
Once every node holds both, rotate:
sudo -u versealx versealx-server keys rotate --onlineIt refuses while any node is missing the new key, and names the node. Otherwise it wraps every organisation’s data key again under the new key, a page at a time, while mail keeps flowing, then marks the store as written under the new key. If it stops part way, run it again and it carries on.
-
When
versealx-server doctorsays the previous key is no longer needed, removeprevious_filefrom[keys], a node at a time.
Keep the old key file for as long as you keep backups made before the rotation, as above.
Under a KMS
A key held in a KMS rotates with every node running too.
-
Make the new KMS key, and give every node’s role the same use of it as of the current one.
-
On every node, name the new KMS key in
key_idand the current one inprevious_key_id:[keys] kind = "kms" key_id = "arn:aws:kms:eu-west-1:111122223333:key/new-key" previous_key_id = "arn:aws:kms:eu-west-1:111122223333:key/current-key" -
Run the rotation:
sudo -u versealx versealx-server keys rotate --onlineThe first run has the new KMS key make the new key-encryption key and keeps the KMS’s ciphertext of it in the store. A node started after that holds both keys, so now restart the nodes, a node at a time. Until every node holds both, the rotation goes no further, and names the node that does not.
-
Run
keys rotate --onlineagain. It wraps every organisation’s data key again under the new key while mail keeps flowing, and carries on where it stopped if it is interrupted. -
When
versealx-server doctorsays the previous KMS key is no longer used, removeprevious_key_idfrom[keys], a node at a time. Keep the previous KMS key enabled for as long as you keep backups made before the rotation.
Restoring
restore refuses to write into a node that already holds data, so it cannot overwrite a working server by accident.
-
Install the server on the machine you are restoring to, but do not run
init. -
Put the configuration file back at
/etc/versealx-server/versealx-server.toml, or write a new one naming the store, blob directory and key file where you want them. -
Put the key file back at the path in
[keys] path, owned byversealx, mode0600. -
Put certificate files back if you use them.
-
Make sure the store and blob paths are empty.
-
Restore, as the service user:
sudo -u versealx versealx-server restore /var/backups/versealx/2026-09-14 --config /etc/versealx-server/versealx-server.tomlrestored 48210 keys and 1932 blob(s) from /var/backups/versealx/2026-09-14 -
Start the server and run
doctor.
Before writing anything, restore checks the manifest’s version, hashes the store file and every message body, and compares the counts. If anything differs, nothing is written. The store is then written back in pages; if a restore is interrupted, run it again.
Restoring into a node that holds data
sudo -u versealx versealx-server restore /var/backups/versealx/2026-09-14 --merge --config /etc/versealx-server/versealx-server.toml
--merge writes everything in the snapshot over what is there. Anything in the node that is not in the snapshot stays. Use it deliberately — for example, to finish a restore that was interrupted.
Messages
| Message | Meaning |
|---|---|
say which directory, as `backup <directory>` or say which directory, as `restore <directory>` | The directory argument is missing. |
this node already holds data; restore into an empty one, or ask for a merge | The target store is not empty. Empty it, or use --merge. |
this snapshot is version <n>; this build reads version 1 | The snapshot came from a different version. |
store.dat does not match the manifest: hashed <hash>, manifest says <hash> | The store file is damaged or was changed. |
store.dat does not match the manifest: holds <n> keys, manifest says <m> | The same. |
store.dat does not match the manifest: a record ends inside its body | The store file was cut short. |
blob <id> does not match the manifest: hashed <hash>, manifest says <hash> | A message body is damaged or missing. |
manifest.json does not match the manifest: <reason> | The manifest cannot be read. |
this snapshot holds a key this build does not understand | The snapshot came from a later version. |
<path>: <reason> | A file could not be read or written. |
Practising a restore
A backup you have never restored is a hope, not a backup. Try one on a spare machine or virtual machine regularly:
- Install the server there without running
init. - Copy over the configuration, the key file and the latest snapshot.
- In the copied configuration, set
roles = ["store", "admin"]. The snapshot holds the queue, and a test machine runningrelaywould try to deliver that mail again. Remove any[listeners]tables for roles you left out, and if[tls]uses ACME, switch it to certificate files for the test. Do not point your DNS at the test machine. - Restore, start the server, and run
doctor. - Check that
versealx-server admin get tenantslists your tenants, and that an account’s mail can be read over IMAP. - Throw the test machine away.
Backups of a cluster
A cluster keeps its mail in two places: the PostgreSQL database and the bucket. The database’s own point-in-time recovery, from RDS, pgBackRest or Barman, is the cluster’s backup of the first. For a restored database to be whole, the bucket must still hold every message the database names at the moment you restore to.
The recovery window
Tell the nodes how far back the database can be restored:
[backup]
point_in_time_days = 7
It takes 0 to 35 days, and 0 is the default. Normally the bytes of a message are deleted an hour after the last copy of it goes. With a window, they are kept for the whole window instead, so a database restored to any moment inside it finds all of its mail. A window set later also protects messages deleted before it was set.
Turn on versioning for the bucket, with object lock in compliance mode for at least the window. versealx-server doctor asks the bucket whenever a window is set and the mail is in a bucket, and reports it as broken when its default retention is shorter than the window, or when it has none.
Named restore points
Before a change you might want to undo, such as an upgrade or a large import, mark the moment:
versealx-server backup mark "before the upgrade"
versealx-server backup points
Each point records its name, when it was marked and by whom, and adds a line to the installation’s audit log. A name can be used once. To go back, restore the database’s point-in-time recovery to the moment the point shows. The same points are on the console’s Cluster page, in Backups of the cluster, where you can mark one, and at GET and POST /api/v1/backups/points, for the operator.
Checking a restored database
Before any node starts on a restored database, check it:
versealx-server restore check --store postgres://versealx@db.internal/restored
versealx-server restore check --store postgres://versealx@db.internal/restored --full
The check reports:
- whether this node’s key-encryption key opens the store;
- how many messages and attachments the store names;
- how many were looked up, and how many are missing from the bucket.
By default it looks up a sample of 200. --full looks up every one, paced so a bucket in use is not flooded. The first missing ones are named. The check ends with “whole: a node may start on it” and exits 0, or ends with NOT WHOLE and exits 1. A store it cannot open exits 2.
A SQLite store is checked the same way, with its file’s path for --store.
Starting on a restored database
Start the first node on the restored database with --as-restore:
sudo -u versealx versealx-server run --as-restore
The node gives the restored cluster a new identity, so it can’t be mistaken for the one it was restored from if both are running, and holds all outgoing mail. Mail arriving from outside, mail between your own people, and sign-ins all work as usual; mail to other servers waits in the queue. Nodes started after the first, with or without the flag, keep the hold.
The hold matters because mail queued at the moment you restored to may have been delivered since, and sending it again would reach people twice. List what is held:
versealx-server restore held
Outbound mail is held since 2026-09-30 21:04:11 UTC, when node mail-1 started on this store as a restore of cluster 3f2a… (now 9c41…).
2 message(s) wait to be sent. Any delivered before the restore will be delivered again: remove those (`admin queue`), then `versealx-server restore release`.
0000018f2c… <b7e1@example.com> from alex@example.com to sam@partner.example
0000018f2d… <c912@example.com> from mo@example.com to info@supplier.example
Each line gives the message’s queue id, its Message-ID and the recipients it still has to reach, so you can compare with the sent items of the people concerned or the other server’s logs. Remove any already delivered with the queue commands, then release the rest:
versealx-server restore release
Every node starts sending at its next pass. Both the restore and the release are recorded in the installation’s audit log, and doctor warns for as long as mail is held.
A copy away from the database’s provider
Point-in-time recovery keeps the cluster’s backup with the database’s provider, often in the same region. To keep a copy somewhere else too, one that the server itself can restore, copy the running cluster into a directory on another disk, or into an S3-compatible bucket at another provider:
versealx-server backup --cluster /mnt/offsite/versealx
versealx-server backup --cluster s3://offsite-backups/versealx
For a bucket, say how to reach it in the configuration, as [blobs] does for the mail’s own bucket:
[backup.offsite]
endpoint = "https://s3.storage.example" # leave out for AWS
region = "eu-central-1"
access_key_env = "OFFSITE_ACCESS_KEY_ID" # AWS_ACCESS_KEY_ID when left out
secret_key_env = "OFFSITE_SECRET_ACCESS_KEY" # AWS_SECRET_ACCESS_KEY when left out
lock_days = 30 # refuse a bucket that does not keep copies this long
With lock_days set, the copy first asks the bucket for its object lock. A bucket that does not keep every new object for at least that many days by default is refused before anything is written, saying what it lacks. Turn on object lock with a default retention when you create the bucket: objects then cannot be deleted or overwritten by anybody, including whoever holds the server’s credentials, until the retention ends.
The keys themselves are read from those environment variables when the command runs, never from the file or the command line. Give the copy keys of its own that can write only to that bucket.
The copy holds every organisation’s mail, so it is checked against each organisation’s residency before anything is copied. Say which of your sites the copy rests in, with site in [backup.offsite] or --site on the command. A copy to a site outside an organisation’s countries is refused, naming the organisation, and so is a copy that names no site while any organisation has a residency. To copy anyway, add --outside-residency. That is recorded in the installation’s audit log, with each organisation named, before anything is copied.
The copy uses the same format, sealing and key as the daily backups: the key from [backup] key_file, or the one named with --key-file <path>. versealx-server backups key <path> makes one.
The copy reads every record of the database at one moment. Mail that arrives while it runs is not in it, and nothing in it is half-written. The database is held at that moment only while the records are read, usually minutes. Then the message files that moment names are copied. A file already in the directory, from an earlier copy, is not copied again, so later copies take only what is new. When it’s done, the command says:
- how many records and message files the copy holds;
- how many files it copied and how many were already there;
- how long it held the database;
- the command that restores it.
Each copy adds a line to the installation’s audit log. versealx-server doctor shows when the last copy was made, and warns when some message files were already gone before they could be copied. The last thirty copies, with what each holds and copied, are listed on the console’s Cluster page and at GET /api/v1/backups/offsite, for the operator.
To bring a copy back, restore it into an empty node, on SQLite or PostgreSQL:
versealx-server restore /mnt/offsite/versealx --backup <name>
versealx-server restore s3://offsite-backups/versealx --backup <name>
<name> is the one the copy printed. Without --backup, the newest copy there is restored. The restore checks every message file before writing anything, and refuses a node that already holds data unless you add --merge.
A single node on SQLite doesn’t need this: its daily backups already are its copy, and backup --cluster says so.
Backing up several nodes
Nodes that share a store — PostgreSQL and a bucket — are backed up once, from any node configured for that store, with every node stopped. For PostgreSQL and the bucket, you can also use their own backup tools; keep the key file with the same care.
Something unclear or out of date on this page? Tell us.