Recovery
Recover backups as they stood on a date — rebuild a whole DLE, or browse and pick individual files, with no index server in the loop.
- Whole-DLE restore (
--all) - File-level recovery (browse + pick)
- Efficient partial reads (archive shapes)
- Egress on a cloud restore
nb recover recovers from backups as they stood on a date, in two modes:
rebuild an entire DLE, or browse its filesystem and pull back individual files.
A DLE is identified by host:path (e.g. app01:/home) — that is what the tables
show and what --dle (and the interactive setdisk) accept.
Whole-DLE restore (--all)
nb recover --dle app01:/home --date 2026-06-21 --all --dest /tmp/out
This rebuilds an entire DLE: it replays the most recent full at or before the date, then every later incremental up to it, in run order, using GNU tar’s incremental extraction.
Because the incrementals carry directory census data, deletions are applied —
a file removed between the full and the date is absent after the restore — and
extraction prunes the destination to match the backup. So --dest must be
empty, or pass --force to restore into a populated directory, replacing its
contents.
Omit --dle to restore every DLE, each into its own subdirectory of --dest:
nb recover --date 2026-06-21 --all --dest /tmp/out
Restore onto a remote client
--all can restore straight onto a remote client instead of a local --dest,
with --to host:path (the host must be one of the config’s hosts:):
nb recover --dle app01:/home --date 2026-06-21 --all --to app01:/restore
tar runs on the client, so the bytes land there directly; for a client DLE encrypted
with encrypt.at: client, decryption also happens on the client and the key never
leaves it. --to and --dest are mutually exclusive — --to carries its own
destination path.
File-level recovery (browse + pick)
Without --all, recover browses a DLE’s filesystem and pulls back individual
files or directories. The browse view merges the restore chain — the full
plus every later incremental up to the date — so each path shows its newest
version on or before the date, recovered from the archive that holds it.
There is no separate index server: browsing reads the member index every archive already records, so it touches only the catalog and reaches media only when you extract.
One-shot, scriptable
nb recover --dle app01:/home --date 2026-06-20 --list --path /etc
nb recover --dle app01:/home --date 2026-06-20 \
--path /etc/hosts --path /etc/nginx --dest /tmp/out
Interactive shell
nb recover with no arguments opens a shell that tracks a current DLE and date;
set those, then navigate and select:
recover> setdisk app01:/home
recover> setdate 2026-06-20
recover app01:/home:/> cd etc
recover app01:/home:/etc> ls
hosts nginx/ passwd
recover app01:/home:/etc> add hosts nginx
recover app01:/home:/etc> extract /tmp/out
recovered 12 file(s) from 2 archive(s) into /tmp/out
Paths are relative to the DLE’s backed-up root. Selecting a directory pulls its whole subtree (each file from the archive that last changed it).
On a real terminal the shell is a full line editor: command history, cursor and
word editing, and tab-completion of both command words and paths (a path with a
space completes as one argument). During an extract, a live progress bar tracks
the bytes pulled off the medium — so a large ranged read shows movement rather than a
silent pause — and clears itself when the extraction finishes. On a pipe it falls
back to plain reads with a clean, non-interactive transcript.
Selected-file recovery never deletes — you get exactly what you ask for, and
nothing in --dest is pruned. One fidelity consequence: GNU tar records
deletions in its snapshot, not the member index, so a file deleted at a later
incremental still shows in the browse view. Recover the whole DLE with
--all when you need deletion-accurate state.
Efficient partial reads (archive shapes)
Pulling one file out of a large archive normally costs the whole archive: decompression is stateful, so reaching a late member means streaming every byte before it through the decoder — real egress on a cloud store. NBackup records enough metadata at write time (decode-restart points) that a selective recover fetches only the bytes it needs, without changing what the archive looks like to a whole-stream reader or to the stock-tools one-liner.
Which optimization applies falls out of the pipeline — the archive’s shape, stamped in its commit footer so a reader decodes it with no config:
| Pipeline | Shape | Selective read | Whole restore |
|---|---|---|---|
Server-side compress, no encryption (zstd/gzip/none) |
framed | ranged GET of the covering frames — in one measurement a small-file extract touched 0.3% of the archive | reads it all |
Encrypted (gpg) |
atomic | fetch only the atoms (sealed .pNNN gpg messages) covering the members |
reads it all |
| Client-placed transform, or a non-restartable scheme | stream | whole archive, as before | reads it all |
A framed archive is byte-for-byte identical to a plain stream — the compressor
just restarts every frame_size of input, an invisible restart point — so nb copy,
nb verify, and the stock one-liner are all unchanged; the frame table rides in the
per-archive index. An atomic archive stores each part as one complete gpg message
(a concatenation of gpg messages can’t be re-decrypted as one stream, so encryption
can’t be frame-invisible), and selective restore decrypts only the covering atoms.
Tape streams whole regardless — it has no egress meter, and a within-file skip buys little — so ranged reads pay off on cloud (and, less, local disk). A whole-DLE restore reads every member whatever the shape; the win is in single-file recovery.
Tuning encrypted-restore granularity
For an encrypted (atomic) dumptype, part_size sets the atom size — the unit a
selective restore and a key-proving drill fetch:
part_size: 10GiB # global default atom size (matches the cloud slice size)
dumptypes:
vm-images:
encrypt: { scheme: gpg, recipient: backups@example.com }
part_size: 2GiB # smaller atoms → finer restore, cheaper drills, more objects
Smaller atoms mean finer selective-restore granularity and a cheaper key-proving drill
sample, at the cost of more objects on the medium. Because a sealed atom can’t shrink
without the key, it also can’t land on a medium whose per-part ceiling is below it —
flagged at nb plan time and refused per-archive by nb sync, never a silent failure.
Unencrypted framed archives carry no atom size; they are re-sliced freely and take each
medium’s own part_size. frame_size (default 256 MiB) is the framed shape’s
restart interval — an advanced knob that is right for almost everyone as-is. The full
design is in docs/design/archive-shapes.md.
Egress on a cloud restore
Pulling from a cloud store costs egress. nb recover estimates the egress $
before it reads and warns — and, interactively, confirms — when the amount is
material. See Cost forecasting.
See also Verification & drills to prove a restore will work before you need it, Restore by hand for the stock-tools path that needs no NBackup, and Replication to restage an offsite copy back to disk first.