Skip to Content
OperatingBackup and restore
Operating · Backup and restore

Backup and restore, one archive, both stores, taken together.

Run every command on this page from the installation directory.

What you will achieve

Use this page to back up an installation, check the archive and restore it. The archive holds .novuslens.env with its secrets, so keep it as private as that file.

What it is for

An installation keeps its state in two primary stores. The database holds the evidence bodies, the sealed identity joinSealed identity joinStored links between employee fingerprints and teams or services. The fingerprints replace readable employee identifiers. Product pages do not show the links for individual people. and the audit trail. The three meshMeshA set of connected Mycelium services that exchange updates and keep the NovusLens log. volumes hold the canonical logCanonical logThe permanent history of changes to an organisation’s model. New entries are added at the end. Earlier entries stay when the database is rebuilt. that the read modelRead modelThe database tables used by the map, Ask and Find. NovusLens rebuilds these tables from its history of recorded changes. is rebuilt from. The two must come back together. A backup of one store alone, or of the two at different moments, is a backup the platform cannot reconcile. ./lens backup therefore copies both into one archive, with the mesh nodes paused.

A stop keeps the Docker volumes, but retained volumes are not a backup. They are lost with the host or with ./lens delete.

Before you start

  • The installation is running. A backup reads the database through the running PostgresPostgresThe database software that stores the tables read by the NovusLens screens, along with document bodies, access records and protected personnel records. service.
  • You know where the archive goes. The default is the backups directory in the installation directory. Any destination must be inside the installation directory, because that is the only tree the installer containerContainerA running program with its own packaged software and isolated environment, managed by Docker on the host. sees.
  • You have a place on a different disk or host for a copy of each archive. A backup beside the live data may be lost with that data. Record the location, frequency, retention and the date of the last test restoration in the customer’s handover sheet.
  • You can protect the archive. It holds .novuslens.env, with the secrets and the identity saltIdentity saltA secret value added before employee identifiers are turned into fingerprints. Keep the same value so later imports can still match existing people.. See Secrets.

Steps

1. Take a backup

./lens backup [<destination-directory>]

The backup stops the running mesh nodes, copies the four volumes, dumps the database, then starts the mesh nodes again. Plan it for a quiet period: the canonical log does not accept new records while its nodes are stopped.

2. What the archive contains

The archive is named novuslens-<stamp>.tar.gz. The stamp is the UTCUTCCoordinated Universal Time: a shared time reference that does not change with daylight-saving time. time in the form YYYYMMDDTHHMMSSZ. It contains:

MemberWhat it is
database.sqlA pg_dump of the database, written with --clean --if-exists
volumes/mesh-0-data.tar, volumes/mesh-1-data.tar, volumes/mesh-2-data.tarThe three mesh volumes, the canonical log
volumes/installation-state.tarThe installation-state volume
release-manifest.jsonThe release manifestRelease manifestThe file recording the exact software versions and fingerprints used for a NovusLens release candidate. Installation checks compare files against it. of the installation that took the backup
.novuslens-install-state.jsonThe setup journalInstallation journalA saved record of setup steps, their attempts and whether they started, completed or failed. It records progress, not a backup of application data., when it exists
.novuslens.envThe configuration file, with the secrets that match the restored stores
.lens-install-typeThe installation type that ./lens delete asks for, when it exists
backup.jsonThe backup’s description: when it was taken, the image tag and image identity, the source commit and the checksum of .novuslens.env

Only your user can read the archive (mode 600), because it holds the secrets. Keep each copy as protected as .novuslens.env. The archive does not contain the images or the models. The image tag in backup.json names the release to restore into.

3. Check the archive

Confirm that the archive lists its members before you rely on it:

tar -tzf backups/novuslens-<stamp>.tar.gz

A restore also checks the archive and refuses one with a missing member. Checking now finds damage before you need the archive.

4. Restore

Put the archive inside the installation directory, then restore it. The installation does not need ./lens setup --init first, for example after ./lens delete:

./lens restore backups/novuslens-<stamp>.tar.gz --yes

The restore runs in this order. Nothing changes until step 4 has finished:

  1. It checks that the archive is readable and holds every required member.
  2. If .novuslens.env is missing, it puts back the archive’s copy and the installation type. If the file differs from the archive’s copy, it refuses. Then it checks that this installation runs the same image tag and image as the archive. A refusal removes a file it put back.
  3. It unpacks every member into a staging directory in backups.
  4. It takes a pre-restore backup of the current state into backups, named pre-restore-<stamp>.tar.gz. With no existing volumes, it says so and continues without one.
  5. It stops the services and replaces the contents of the four volumes.
  6. It restores the database in a single transactionTransactionA group of database changes that is saved together. If the group fails, its changes are not saved..
  7. It restores the setup journal, runs initialisation, and starts every service. It waits up to 300 seconds for them to pass their health checks.

If step 5, 6 or 7 fails, the message names the pre-restore backup. Restore that backup with the same command to return to the state before the restore.

Every check, and the pre-restore backup, comes before the first change. A failure after that point names the pre-restore backup to restore.

Restore into a changed installation

Two flags skip a check. Use them only after a deliberate change:

FlagUse it when
--replace-env.novuslens.env differs from the archive’s copy and you want the archive’s copy. The replaced file is kept in backups as pre-restore-<stamp>.novuslens.env. The pre-restore backup holds the replaced file with the stores it matches. lens runs the release the archive records, unless you give --version.
--allow-env-mismatchYou changed .novuslens.env on purpose since the backup and want to keep it. Keep the identity salt the same. See step 5.
--allow-release-mismatchYou restore into another release or image. Initialisation applies any pending migrationsMigrationAn ordered change to a database's tables or rules. Applied migration files are recorded so the same file is not run again. when the installation starts.

5. Keep the identity salt

The sealed personnel hashesHashA fixed-length fingerprint calculated from content. Comparing fingerprints helps detect changes and match records. depend on CONWAY_IDENTITY_SALT. A different saltSaltExtra data mixed into a value before its fingerprint is calculated. It makes matching or guessing the original value harder. breaks every personnel link in the restored data. The archive carries the salt in .novuslens.env, so a restore onto a rebuilt host brings it back. The restore refuses a changed file, which protects the salt unless you add --allow-env-mismatch.

What you will see

A backup prints Backed up the database, 4 volumes and .novuslens.env (<size> bytes). and a reminder that the archive holds the secrets. The last line is the archive’s path, so a script can read it.

A restore prints The state before the restore is kept in <path>., then Restored; the installation is running. Run status to confirm. Run ./lens status to confirm.

When something goes wrong

MessageCauseAction
Postgres is not running, so there is nothing to dump.The installation is stopped.Run ./lens resume, then back up again.
Backup destination <path> is outside <directory>.The destination is not inside the installation directory.Choose a path inside it.
<archive> already exists.Two backups were started in the same second.Wait a second, or choose another destination.
The application image <image> is not on this host.The images were removed.Run ./lens resume to prepare the images, then retry.
Backup failed while <step>: <error>The named step failed. The message says whether the mesh nodes were restarted.Correct the error, then back up again. If the mesh nodes did not restart, run ./lens start.
Restore replaces the database and all four state volumes. Add --yes to confirm.--yes is missing. Nothing was changed.Add --yes when the customer has agreed the restore.
<archive> is outside <directory>, the only tree the installer container sees.The archive is not inside the installation directory. Nothing was changed.Move the archive into the installation directory.
<archive> lacks <member>., is not a readable .tar.gz, has a damaged backup.json or is damagedThe archive is incomplete or damaged. Nothing was changed.Use another copy.
<archive> holds no .novuslens.envThe archive was written before backups carried the configuration, and the installation has none. Nothing was changed.Put the original .novuslens.env in the installation directory, or run ./lens setup --init <mode> first. Then restore again.
Put the original .novuslens.env in <directory>The archive is an older one without the configuration, and .novuslens.env is missing. Nothing was changed.Put the protected copy back.
<file> differs from the configuration in <archive> in: <keys>.novuslens.env changed since the backup. The message names the changed settings, never their values. Nothing was changed.Add --replace-env to use the archive’s copy. If you changed the file on purpose, add --allow-env-mismatch.
<file> differs from the backed-up configurationThe archive is an older one without the configuration, and .novuslens.env changed since the backup. Nothing was changed.Put the original back. If you changed it on purpose, add --allow-env-mismatch.
<archive> names Compose project <name>, but this installation runs <name>With --replace-env, the archive’s configuration names another Compose project. Nothing was changed.Set COMPOSE_PROJECT_NAME in .novuslens.env to the archive’s value, run ./lens stop, then restore again with --replace-env.
<archive> holds the configuration of <directory>The archive comes from an installation in another directory. Nothing was changed.Move the archive under that directory and restore with --directory <directory>.
The configuration runs <tag> but the archive came from <tag>.The installation runs another release. Nothing was changed.For published images, run ./lens start --init ghcr:<tag> with the archive’s tag. Or add --allow-release-mismatch.
The application image here is <image> ... but the archive was taken on <image>The image differs from the one the archive recorded. Nothing was changed.Run ./lens resume to prepare the matching release, or add --allow-release-mismatch.
Restore stopped before changing any data; the pre-restore backup failedThe safety copy failed. Nothing was changed.Correct the error it prints, then restore again.
Restore failed after the stores were touchedA step after the safety copy failed.Restore the pre-restore backup the message names, with the same command. If it names none, run the same restore again.
Restore stopped after the stores were touchedThe restore was cancelled after the safety copy, for example with Ctrl-C.Restore the pre-restore backup the message names, with the same command. If it names none, run the same restore again.
Putting the earlier files back failed for <files>A restore refused, but it did not put back the files it had written. The message names each file and the error.Fix the error, for example a full disk or a read-only directory. If the message names a kept configuration, copy it back to .novuslens.env.
Last updated