jfreundJFBackup
JFBackup

Architecture & security

How the parts of JFBackup talk to each other, what happens to your data on its way into the repository, who holds which key and what JFBackup does when something goes wrong. Written for admins, from the app's own documentation and source.

Four programs

Console · server · agent · bcctl, each for Windows and Linux

JFBackup is not one program but four. The server does the work; the console and bcctl only talk to it; agents give it access to the machines it protects. Server and agent run as a Windows service or a systemd unit and log to standard output and to log files of 10 MB, keeping five older ones.

ProgramWhat it does
Consolethe desktop appOverview, jobs, restore, servers and agents, repositories, credentials, monitoring, settings and the wizards. Its setup assistant sets up a server, connects to one or turns the computer into an agent.
Serverbc-server, port 7642The REST API, the scheduler (every 15 seconds: due jobs, expired tokens, old operations), the backup and restore engine, repositories, users, roles, the audit log and its own certificate authority. Long actions run as operations, at most eight at once, and can be cancelled.
Agentbc-agent, port 7680Shares folders of one machine with one server over mutual TLS and reports every 30 seconds.
bcctlthe command-line clientEverything scripts need: setup, login, status, run, wait, restore, verify, logs, audit, updates and release signing. It reads tapes without a server.

The server's data folder

Everything the server knows lives in one folder. A server that was set up does not start without its keys: it could not read its own secrets or prove its restore points.

  • data/
  • db/the datastore: snapshot and write-ahead journal, crash-safe
  • journal/audit and session logs
  • keys/master, signing and recovery keys
  • pki/CA, server and client certificates, their keys sealed
  • logs/10 MB per file, five older files kept
  • config_backups/encrypted configuration backups
  • setup.tokenonly until the first administrator exists

Connections

HTTP/1.1 and JSON · TLS 1.3 · its own certificate authority · pinned certificates

The server brings its own certificate authority (Ed25519, valid for ten years). It issues the server's TLS certificate for the machine's names and addresses, renewed when they change or 30 days before it expires, a client certificate that the server shows to agents, and one certificate per agent, valid for a year. On the first connection the console and bcctl show the CA's SHA-256 fingerprint and keep it once you trust it.

Clients
  • Consolebearer token, 24 h
  • bcctlbearer token, 24 h
Serverown CA
  • API certificate from its CA
  • Client certificate towards agents
  • Agent certificates, pinned
Agents
  • Own certificateissued at pairing, one year
  • Heartbeatevery 30 seconds
Repositories
  • Folders of the serverlocal disks or a NAS mount
Who connects to whom. Plain HTTP is accepted only on the loopback address of the server's own machine.
From, toHowTrust
Console, bcctl to the serverHTTP/1.1 with JSON and a bearer token; TLS 1.3 on the network, plain HTTP only on loopbackThe server's CA, confirmed by its fingerprint or given as a file
Server to agentMutual TLS on port 7680, one kept-alive session per agentThe server shows its client certificate and accepts exactly the agent certificate it issued
Agent to serverA heartbeat every 30 seconds: last seen, address, shared foldersThe agent's own certificate
Central server to other serversTheir report once a minuteA fleet token per server, its CA pinned by fingerprint
Server to mail and web hooksSMTP with STARTTLS or TLS, never a password in clear; JSON over HTTPSThe system's certificate authorities, plus a company CA if you add one

Pairing agents

A one-time code on Windows and Linux · an SSH push on Linux

An agent belongs to exactly one server. It joins with a one-time code or is installed by the server itself over SSH. Either way it ends up with its own key, a certificate from the server's CA, and a server it checks by fingerprint.

With a pairing code

  1. Install the agentwith the setup on Windows or the .deb package on Linux.
  2. Create a code in the consolevalid for 15 minutes and usable once, shown with the server's address and the fingerprint of its CA.
  3. Pair on the machinebc-agent pair reads the CA from the TLS handshake and compares its fingerprint, or asks you to.
  4. Get a certificateThe agent makes a new Ed25519 key and enrols with the code; the server's CA issues its certificate. From then on: mutual TLS.

bc-agent service install runs it as a Windows service or a systemd unit, or pair … --service does both at once.

Over SSH

  1. Enter the addressThe console shows the machine's SSH host key to compare before anything is sent.
  2. Choose the loginstored credentials, a password or an Ed25519 key, or a password typed once.
  3. Upload and pairThe server uploads the agent, pairs it with a fresh one-time code and passes its CA fingerprint along, so the agent checks this server.
  4. StartAs root, a systemd service; otherwise a background process of that user. A second push updates the program and keeps the pairing.

For Linux computers with OpenSSH on x86-64. Windows machines pair with a code.

From a file to a restore point

FastCDC · keyed BLAKE3 · LZ4 or zstd · XChaCha20-Poly1305 · Ed25519

The engine walks the job's sources on the server or through an agent. A file with the same size, modification time and file id as in the previous restore point takes over its chunks without being read; an "active full" reads everything again. Every restore point is still a full image: "incremental" only means that unchanged files cost nothing.

What happens to new data

  1. Cut by contentFastCDC with normalized chunking. Boundaries depend only on the content, so an insertion early in a file moves one boundary and the later chunks stay deduplicated. The gear table comes from the repository key: chunk sizes do not reveal known files.
  2. Named by a keyed hashA chunk's id is the keyed BLAKE3 hash of its content. Identical data is stored once, and without the key the ids reveal nothing.
  3. Compressed, then encryptedLZ4 or zstd (level 3, or 6 for "High"), only when that saves something; then XChaCha20-Poly1305 with a fresh 24-byte nonce, the chunk's id, kind and codec authenticated with it.
  4. Packed with an indexSealed chunks go into pack files with a sealed index. The end of each pack repeats its index, so a lost index file can be rebuilt.
  5. TreesFolders become tree chunks. An unchanged folder produces the same tree chunk and is stored once.
  6. A signed snapshotThe restore point names its roots, is signed with the server's Ed25519 key and encrypted.
  7. Committed in orderPacks, synced; then indexes, synced; then the snapshot by an atomic rename. A crash leaves at most packs nobody refers to, which clean-up removes. Then the retention runs.

The repository

Format bcrepo-1 · check · clean-up · immutability

A repository is a folder of the server, on a local disk or a mounted NAS, and one process holds it at a time. Retention keeps restore points by number and by grandfather-father-son. Immutability is set per repository in days and can only be made longer; while it lasts, deleting a restore point is refused.

  • repository/
  • repo.jsonthe repository key, wrapped three times
  • data/xx/<pack>.packsealed chunks, the index repeated at the end
  • index/<pack>.idxthe sealed index of each pack
  • snapshots/<id>.snaprestore points, signed and encrypted
  • LOCKone process at a time
  • Verify a restore point: every chunk is read, decrypted and compared with its id.
  • Check a repository: snapshots, signatures, references and every blob.
  • Clean up: mark and sweep, repacking packs that became sparse.
  • Copies to a second repository rebuild every tree there, because chunk ids are keyed per repository; a map of copied trees keeps later copies incremental.

Keys and the recovery kit

One random key per repository, wrapped three times

Every repository has one random key. It is never stored in the clear: repo.json holds it wrapped for the server's master key, for the passphrases of encrypted jobs and for the recovery kit. The keys for chunk ids, data, indexes, snapshots and the gear table are derived from it.

Server master key32 random bytes in the keys folder, readable only by the owner
Job passphraseat least 12 characters, stretched with Argon2id
Recovery kitan X25519 key pair; the private key is shown exactly once
Repository keyrandom, one per repository
chunk idsdataindexsnapshotsgear table
Three ways to the same repository key, and what is derived from it.

The master key also seals the secrets in the server's database, credentials and job passphrases, which the API never returns, and the key of the CA. A separate signing key signs the restore points. The recovery kit is for the day the server is gone: the server keeps only its public key and seals every repository key to it, while the private key opens every encrypted backup, and encrypted tapes too, without this server. Keep it offline and separate.

A configuration backup holds the database, without tokens and failed logins, and the keys in one file, encrypted with a passphrase (Argon2id and XChaCha20-Poly1305). Restoring it takes effect at the next start.

The encryption step of the job wizard: the switch to encrypt restore points with XChaCha20-Poly1305, the passphrase twice, the note that the recovery kit opens the data even without it, and the compression levels off, fast, balanced and high.
Encryption and compression of a job.

Users, roles and the audit log

Argon2id · tokens kept as a digest · four roles · every change logged

Nobody signs up: the first administrator is created with the server's one-time setup token, every other account by an administrator. Passwords have at least 12 characters and are stored with Argon2id. A login gives a token valid for 24 hours, of which the server keeps only the BLAKE3 digest. Too many failed logins within a minute lock the user name, and the count survives a restart.

RoleMay
Viewersee the overview, jobs, restore points, sessions and their logs, hosts and repositories; change their own password
Restorealso browse restore points and restore files, but only into allowed folders, never to the original place and never replacing a file
Operatoralso create, change, start, enable and disable jobs, verify restore points, cancel operations, check hosts and repositories, and restore to the original place, replacing files
Administratoralso delete jobs and restore points (never immutable ones); pair, install and remove agents; manage repositories, credentials, users and settings; read the audit log; create the recovery kit and configuration backups

Every change gets an entry in the audit log, also those made by agents. bcctl docs lists every route of the API with the role it needs; the server routes by that same table.

What an agent may do

Shared folders only · no links · no commands

An agent is built to be harmless even if the server were not. It never runs commands, and the rules below hold on the agent itself, not only in the server.

  • It reads only inside its backup folders and writes only inside its backup and restore folders.
  • It never follows a symbolic link below them, for reading, listing folders or restoring.
  • It writes restored files to temporary files it names itself and renames them when they are complete.
  • Its port accepts only the server's client certificate, issued by the CA it paired with. Removing the host revokes the agent's own certificate.
  • bc-agent roots --add DIR --restore-add DIR changes the shared folders on the machine, and --lock forbids the server to change them.

Restores follow the same care everywhere: every name from a restore point is checked (no separators, no "..", no drive), a link planted in the target stops that entry instead of redirecting it, and existing files are skipped, renamed or, for operators, replaced.

Signed updates

An Ed25519-signed manifest · SHA-256 per package · installed by an admin

New versions come from an update channel. The channel may be HTTPS or plain HTTP: the signature and the digest protect the content either way.

  1. The publisher signsbcctl release keygen makes a publisher key; bcctl release manifest writes the manifest and its signature for the packages of a release, without a server.
  2. The server checksby hand or once a day: it fetches the manifest and its signature and checks it against the official release keys or the key in the setting update.key.
  3. The server downloadsthe package for its own platform, Windows or Linux on x86-64; size and SHA-256 must match the manifest.
  4. An administrator installsThe console shows the new version; the setup or the package manager installs it and restarts the service.
The updates card in the settings: this version 0.1.0, a newer version 0.2.0 available, the buttons to check and download, the address of the update channel, the field for the publisher's Ed25519 key and the switch for a daily check.
The updates card with demo data.

When something fails

What JFBackup does, case by case

Ifthen
the server stops in the middle of a backupits datastore is crash-safe (snapshot and write-ahead journal), the commit order leaves at most unreferenced packs, and sessions and operations that were running are marked interrupted at the next start.
a protected machine failsa replica, kept up to date after every new restore point, takes over (failover). Failback backs up the replica's folders as a point of the job and writes them back to the original places without deleting anything there; undo drops the failover. Failover plans switch several replicas in order, with a pause between them.
a file was deleted or overwrittenany restore point brings it back, to its place or into another folder.
a backup was damaged or changedverify and check notice it: every chunk is authenticated and compared with its id, every restore point's signature is checked.
an index file is lostit is rebuilt from the end of its pack.
the backup server itself is losta configuration backup brings its database and keys to a new server; the recovery kit or the job's passphrase open the repositories without it; tapes are read with bcctl tape extract without any server.
a virtual machine's backup would not startboot checks find out before you need it.
a machine with an agent is stolenremove the host: its certificate is revoked.
someone tries to delete backupsimmutable restore points cannot be deleted while the lock lasts, and the lock can only be made longer.

Known limits

What JFBackup does not do yet, as its README lists it

  • Virtual machines, instant start, boot checks and volume backups run on the backup server itself (a Linux server with QEMU/KVM for virtual machines), not on agents. Hyper-V is not supported.
  • Backups of running virtual machines are crash-consistent: no agent in the guest quiesces its file systems.
  • Volume backups need administrator (VSS) or root (LVM) rights, read the whole volume each time (deduplication keeps the storage small) and are restored as an image file.
  • Tapes are virtual, files on disk; real tape drives are not driven.
  • TLS to public servers does no revocation checks (CRL or OCSP).
  • Agent certificates are valid for a year; renewing one means pairing again for now.
  • The SSH push installs on Linux x86-64 only.
  • No official release keys are built in yet: a server trusts update manifests only with the setting update.key.
  • Failback writes the replica's state back but deletes nothing at the original.
Part of jfreund.orgBuilt with JFLibLegal noticePrivacy