config
Config archive export and import.
Export a config archive
Builds and returns the `hoserva-config-*.tar.zst` configuration archive.
Back up the config to the destinations now
Queues a `config_backup` job (service class): the config archive the nightly chain writes, taken now. It writes one archive to every enabled backup destination, verifies it, and prunes each destination's own retention, counting the archive like a scheduled one — it never takes the slot of a pre-import, pre-update or pre-topology archive. It is serialized with the other config backups, so one asked for while another runs queues rather than failing. The job succeeds when at least one destination was written and its log names each destination written and each that failed (the stale-destination alert covers one that keeps failing), and fails, with a `config_backup_failed` notification, when none was. Refused with 409 `backup_no_destination` before anything is queued while no destination is enabled, and with 501 `not_configured` when this daemon has no backup service. To download an archive instead of writing one to the destinations, use `exportConfig`.
Import a config archive
Restores from a configuration archive. Requires `confirm: true` — this replaces the running configuration: the database, the custom config files (`*.custom.conf`), the installed app templates and each stack's compose and `meta.json` files, after which every managed config file is regenerated from the restored database and the result applied to the running pool. It also restores the passphrase-protected part of the archive, its stacks' `.env` files: with the optional `passphrase` if one is given, otherwise with the configured backup passphrase. Without a passphrase that opens it, everything else is restored and the report says the `.env` files were not. When the import restores `.env` files, the pre-import archive's own `secrets.age` is sealed with the passphrase that opened the imported archive's, so it holds every `.env` the import replaces; a failure to write it refuses the import. The answer is the restore report: what was restored per category, what was not and why, the name of the pre-import archive and which passphrase seals its secrets. Every refusal happens before anything is written, including the pre-import backup: 400 `invalid_archive` (it does not unpack or checksum, holds a file its manifest does not list or lacks one it lists, holds a link, device, FIFO or duplicate entry, or has a `secrets.age` or `identity.age` that is not readable, which shows once a passphrase is tried against it), 400 `backup_passphrase_incorrect` (a `passphrase` was given and it does not open the archive's `secrets.age` or, for an archive with an `identity.age` and no `secrets.age`, its `identity.age`; one that opens `secrets.age` but not `identity.age` is not refused), 400 `incompatible_archive` (another schema version), 409 `job_in_progress`, 409 `archive_other_installation` (its machine key check value differs from this installation's or is missing; a different installation's archive is restored only onto a fresh install) and 409 `archive_array_mismatch` (its disks, their removal state or the relocation in flight differ from the live array; the message names each difference), and 409 `restore_path_unsafe` (a file it would restore lands on a symbolic link or on something that is not a regular file, or it names a path outside the directory it is restored into; nothing is followed). A bare-metal restore that would replace a Samba or NFS file already on this server also refuses with 409 `host_files_not_saved` when no backup destination is enabled to take the copy of it that the pre-import archive carries. A failure to stage the files answers 500 `import_failed` with nothing changed; a failure once the database has been replaced answers 500 `import_failed` naming the pre-import archive to restore from and which of the file categories were restored and which left as they were. The array's own state, running, in maintenance mode or stopped, is kept as it is, never restored from the archive, so an import cannot return a stopped array to normal operation.
Preview a config import
Reads the same archive upload as `importConfig` and reports what an in-place import would change, without changing anything: it writes no database row, no pre-import archive, takes no job hold, and leaves no file behind. `blockers` lists the refusals `importConfig` would return for this archive, with the same codes and messages (400 `incompatible_archive`, 409 `archive_other_installation`, 409 `archive_array_mismatch`, 409 `restore_path_unsafe`); `groups` compares the archive's database with the live one per category, and lists the custom config files, app templates and app stack files the import would replace, add and remove; it is empty when the archive's schema version differs, since the two cannot be compared. `secrets` says whether the archive has a passphrase-protected section (`status`, for `secrets.age`) and whether the passphrase available opens it and `identity.age` (`identity`), and if not, which stacks' `.env` files would not be restored. The optional `passphrase` is tried as `importConfig` tries it: one that does not open the archive's `secrets.age`, or, for an archive with an `identity.age` and no `secrets.age`, its `identity.age`, is refused as 400 `backup_passphrase_incorrect`; one that opens `secrets.age` but not `identity.age` is not refused, and `identity` reports `passphrase_incorrect`. Without a `passphrase` the configured one is tried, and one that is absent or does not open the files shows only in `secrets`, never as a refusal; an archive with neither file has nothing to check a `passphrase` against. An archive that cannot be read is refused as `importConfig` refuses it (400 `invalid_archive`, 413 `archive_too_large`), and a daemon with no config backup wired answers 501 `not_configured`. Nothing on a data disk is read.