Backup & Restore
A backup is a single portable .qbak archive bundling the two kinds of state that together
make a working deployment. It is one file: nothing else has to travel with it.
What is in a backup
| Kind | Contents |
|---|---|
| Database entities | Connections, the namespace tree (nodes, tags, protocol bindings), alarm definitions, user-defined types, users, and the project registry — each dumped as a JSON section |
| File trees | Per-project artifacts: views, scripts, named queries and assets |
| File Manager and uploaded files | The file list always travels. The bytes are opt-in — see Media. Changed in 1.0.6 |
| Not in a backup | Where it lives |
|---|---|
| Tag history | QuestDB — back it up with your database procedures |
| The audit journal | The external audit database — deliberately separate |
| Execution and system logs | Diagnostic data, not configuration |
| Live runtime values | Reconstructed on start |
.env | Back it up separately; it holds ENCRYPTION_KEY |
Encryption and secrets
This is the part to get right.
| Backup | Contains connection secrets | Anyone opening it sees |
|---|---|---|
| Passphrase-encrypted | Yes, protected by the encryption | Nothing without the passphrase — an opaque blob |
| Unencrypted | No | Configuration, with credentials blank |
An unencrypted backup deliberately omits secrets so an unprotected archive cannot leak plant access. An encrypted backup is sealed whole — no usernames, no password hashes, no configuration, no secrets are readable without the passphrase.
An unencrypted backup restores with blank credentials — every connection must be re-entered. That is the right trade for an archive you cannot fully protect, and the wrong one for disaster recovery. For DR, use a passphrase and store it in your secrets manager.
Media: the File Manager and uploaded files New in 1.0.6
Two file stores sit outside the project trees — the File Manager library, and the uploads folder behind style backgrounds, widget assets and anything a script wrote. Both are unbounded: they hold videos and 3D models, and can be a hundred times the size of the configuration beside them. A nightly backup dragging 400 MB of video is a backup that stops being run.
So Include File Manager & uploaded files is a checkbox on the export, and it is off by default. What that flag decides is the content, not the record:
| Off (default) | On |
|---|---|
| The archive carries the file list and every reference to it. | It carries the list and the bytes. |
A view pointing at Manuals/P-101.pdf still points at it after the restore. | The same, with the file already in place. |
| Copy the two storage folders across and everything reconnects, with nothing further to do. | Nothing further to do. |
| Kilobytes. | However large the two folders are. |
The checkbox says what it will cost. New in 1.0.7 Its label carries the size of the two folders — Include File Manager & uploaded files — adds 362 MB (363 files) — measured from the folder listing before anything is downloaded. Until 1.0.7 the only way to learn the size was to tick the box and watch the download. A folder that cannot be measured is said in amber under the label, never counted as zero: "0 MB" and "I could not look" must not look the same, because only one of them means the backup will be small. A failed estimate never blocks the backup.
The list is kept even when the bytes are missing, and that is what makes the default safe. A view references a library file by its id; dropping the row would destroy the id, so an operator who later configured the storage folder and copied the library across would get nothing back, with no remedy short of restoring the whole archive again. Keeping the row makes the obvious repair work — record and file find each other the moment the content lands.
Both folders are effectively immutable, which is exactly what rsync and an incremental file
backup are good at and what a ZIP rebuilt from scratch every night is bad at. Tick the flag for a
deliberate full disaster-recovery copy; leave it off for the nightly.
If the target has no storage folder configured — a fresh install restoring from the setup
wizard, which is the ordinary case — the restore says so once, with the remedy (Settings → Storage, then copy the folder across or restore again), rather than once per file.
The File Manager stopped being an internal catalogue and became an ordinary folder on the server before the backup learned about it, so an archive from an earlier build carried an empty set and said nothing — "0 files" being indistinguishable from an installation that never used the feature. If you are relying on a pre-1.0.6 archive for File Manager content, take a fresh one with the flag ticked, or copy the folder across by hand.
Portability
Backups are portable across machines because secrets are re-keyed in transit:
- On export, each connection is decrypted with the source machine's key.
- On restore, it is re-encrypted under the target machine's key.
The archive therefore never carries machine-key-encrypted blobs, which is exactly why copying the configuration database between machines does not work but a backup does.
Moving between Linux, Windows and macOS New in 1.0.6
The two ends do not have to agree about what a filename is. Linux stores almost any byte sequence;
Windows refuses ? * < > " | outright, folds upper and lower case together, and silently drops a
trailing dot. So an ordinary Linux instance could produce an archive a Windows instance could not
write back — and the three silent cases were the dangerous ones, because a trailing dot, a case
variant or two Unicode spellings of the same word collapse two files into one with no error at
either end.
A backup now reports them, at three points:
| Where | What happens |
|---|---|
| Export | Warns about every name that would not survive somewhere else. This is the only end where you can still rename the thing. |
| Import | Pre-flights before a byte moves. A project, view, script or named-query name that cannot be written is refused, and the message names the files. An asset name is a warning: those trees already degrade by skipping one file, and trading a disaster-recovery restore for an image is the wrong way round. |
| Creation | An asset filename is repaired on upload — nothing refers to it. A view, script or named-query name is refused with the reason, because the name is a key and the repair is not reversible: Flow? and Flow* would both become Flow_. |
The rules belong to the filesystem, not the operating system, so the target's behaviour is measured by writing to it rather than assumed from the platform — a FAT32 stick on Linux folds case, and a case-sensitive volume on macOS does not. The check fails open: a pre-flight whose only power is to refuse must never refuse because it could not measure.
An accented passphrase typed on a Mac and on Windows produces two different byte sequences for the same word. Passphrases are now normalised before the key is derived, so the two open the same archive. Archives sealed by an earlier build still open — the original bytes are tried as a fallback.
Which builds can read an archive New in 1.0.5
An archive is forward-compatible and backward-refused: it restores into the build that made it and into every later one, and a build that predates it will refuse rather than read it wrongly.
The refusal is measured from what the archive actually contains, not from the version that produced it. An estate that never touched a newer feature keeps producing archives an older build accepts — gating on the version number would refuse a 1.0.5 backup on a 1.0.4 gateway over a stylesheet fix, and a guard that refuses safe things is a guard people learn to override.
A refusal names the producing build, this build, and the part of the archive responsible:
This backup cannot be imported by this build.
Created by QUBIQ 1.0.5 on 2026-09-08 14:12 UTC
This installation QUBIQ 1.0.4
Importing it would silently drop settings this build does not recognise.
designer views use schema 3; this build understands 2
Today the things that can raise the floor are Designer view schema, pipeline schema, the shape of the database sections, an account carrying a pending password reset — a build without that column would restore the account and let the old password keep working, silently undoing the reset — and the File Manager library as a folder. 1.0.6
That last one is the clearest case of why the floor exists at all. An older build does not know the prefix the library now travels under, so it would ignore those entries, restore everything else and report success over an empty File Manager. Silent and total. An installation with no library folder configured, or an empty one, keeps producing archives an older gateway restores.
Two things follow:
- An archive with no compatibility envelope is adopted, not refused. Every backup taken before this shipped restores exactly as it did.
- The same rule covers view packs and namespace exports, each measured against its own contents.
Every archive at or below this build's level, indefinitely. There is no lower bound and no expiry.
Taking a backup
Settings → Backup & Restore, which has a tab per scope:
| Tab | Covers |
|---|---|
| Full instance | Everything — connections, the namespace, alarms, users, and every project |
| Project | One project's resources and assets |
| Views | Individual Designer views |
Download backup (.qbak) writes the archive to your device. Give it a passphrase first if the backup is to carry connection secrets, and decide whether to tick Include File Manager & uploaded files — off by default, and the difference between kilobytes and gigabytes. → Media
While it runs, the row beside the button says which of two phases it is in. Changed in 1.0.7 Building the archive comes first, with a spinner — the server assembles the whole archive before it sends a byte, and on a large instance that is the slow part. Then the bytes arriving, 48 MB of 362 MB. There is deliberately no percentage bar: it would sit at 0 through the build and sprint to 100, and a bar that lies about where the time goes invites somebody to cancel a backup that is fine — which is what the old single Preparing… label did. Taking a backup holds no lock; the gateway keeps running normally while it builds.
| Scope | Permission |
|---|---|
| Export or restore a full instance backup | Manage backups |
| Export or restore one project | Manage projects |
| Import a project as a new project | Create projects |
Manage backups is super-admin-only by default: a backup can move an entire configuration off the machine.
Every export and restore is recorded in the audit journal.
When to take one
- Before every upgrade. Schema migrations are not reversible.
- At each commissioning milestone, so there is a known-good point to return to.
- Before any bulk operation — a large namespace import, a UDT sync across many instances, a bulk delete.
- On a schedule, retained off the machine.
Restoring
-
Stop what you can safely stop — pipelines, ideally the whole gateway for a full restore.
-
Choose the archive, supply its passphrase if it is encrypted, and choose the conflict policy.
-
Verify connections: enable each one and check it reaches connected, and re-enter credentials if the backup was unencrypted.
A restore puts things back as they were, including what was switched off: a disabled connection stays disabled, a disabled tag stays disabled, and a suspended user stays suspended. Changed in 1.0.5 Earlier builds turned all three back on.
-
Verify the namespace: check binding statistics for unbound tags.
-
Verify projects: open each and confirm views load.
-
Start pipelines.
How large an archive can be restored Changed in 1.0.7
| Archive | Restore limit |
|---|---|
| Unencrypted | Up to 4 GB, read from disk rather than held in memory |
| Passphrase-encrypted | 512 MB |
Before 1.0.7 every restore was capped at 512 MB and read whole into memory, while export had no limit at all — so an instance could produce a nightly backup it was structurally unable to restore, and find that out on the one day it mattered. Media-inclusive archives made that easy to reach.
An encrypted archive keeps the lower limit because of how it is sealed: the encryption authenticates the whole file before any of it can be trusted, so it has to be decrypted in one piece. An encrypted archive over the limit is refused with the reason, rather than exhausting the gateway's memory. To restore one, export again without the media flag — the usual cause of the size — or, where secrets need not travel, without a passphrase.
The conflict policy
This is the setting to get right. It decides what happens to what is already on the machine.
| Policy | What it does | Use it for |
|---|---|---|
| Overwrite | Replaces existing connections, namespace entries and project files whose identifiers match. | A restore — putting a machine back the way it was. |
| Merge | Keeps what is there and adds only what is new. Existing connections, folders and tags are matched by name or path, so nothing is duplicated. | Bringing one machine's configuration onto another that already has its own. |
| Abort | Refuses unless the instance is empty. | A first restore onto a fresh install, when you want to be told rather than to find out. |
Overwrite is the default, and it is the destructive one. Take a backup of the current state before restoring, even when you are confident — especially then.
The restore report
A restore reports what it actually did: a count per section (connections, projects, namespace nodes, tags, protocol bindings, alarms, UDT definitions, members, instances and overrides), the number of files, and any warnings.
Read the unresolved connections list if there is one. Project resources reference a connection by name, so a project restored onto a machine that has no connection by that name lands with those references dangling — which shows as a broken binding rather than as a failed restore.
Migrating to a new machine
1. Take a passphrase-encrypted backup on the source
2. Install QUBIQ on the target and complete first-run setup
3. Restore the backup
4. Point the historian at its QuestDB store (take ownership if the source is retired)
5. Configure the audit journal's storage connection
6. Check every connection reaches connected
7. Start pipelines, verify screens, then decommission the source
Step 4 matters: the historian records physical ownership inside the QuestDB store, so a restored configuration will refuse to write to a store the old machine still claims. Confirm the source is truly retired before taking ownership.
Project backups
A project backup carries one project's resources and assets, not the instance's connections or namespace. Use it to promote an application between environments.
Settings → Backup & Restore → Project offers three actions:
| Action | Does |
|---|---|
| Export | Writes the chosen project as a .qbak. |
| Restore | Puts a project archive back in place, under its original slug. |
| Import as new | Creates a copy under a name you give it — the way to clone a project, or to bring a second copy of one onto a machine that already has it. |
The prerequisite for all three is that the target already has connections and tags with the same names — project resources reference them by name, not by internal identifier. A restore says so in its report when they are missing.
For the plant model itself, use namespace export/import.
Disaster recovery
A recoverable QUBIQ deployment needs six things, and losing any one leaves you rebuilding:
| Item | Store where |
|---|---|
| Passphrase-encrypted configuration backup | Off-machine backup storage |
| The File Manager and uploads folders — in the archive with the media flag ticked, or copied by your file-backup tool | Off-machine, alongside the archive |
.env (or at least ENCRYPTION_KEY) | Secrets manager, separate from the backup |
| The database recovery key | On paper, off the machine |
| QuestDB backup | Your database backup procedures |
| Audit database backup | Its own procedures, under separate administration |
Test the restore. A backup that has never been restored is a hypothesis, not a plan. Restore into a scratch machine at least once per commissioning cycle.