Files and folders

The folder nobody has a plan for

Databases get backed up because somebody owns them. The directory on one machine that the whole thing quietly depends on usually does not, and it is the case a cloud-only backup product structurally cannot reach.

One static binary. Outbound HTTPS only.

What people actually back up

Four directories, and none of them are in your runbook

The config directory

nginx, Caddy, a systemd unit somebody wrote in 2021. Small, boring, and the reason a rebuild takes three days instead of an hour.

User uploads

The folder your application writes to that was never migrated to object storage, because it worked.

Certificates and keys

The ones not in a secrets manager yet. They regenerate, until the one that does not.

A working directory on one machine

The build server, the reporting box, the machine one person understands. This is the case with no plan at all.

How it reaches us

Nothing listens, so nothing needs opening

The worker polls outward for work. A machine behind NAT, on a factory floor, in a colo with no public address, or under somebody’s desk behaves exactly like one in a VPC. There is no inbound port, no firewall exception and no VPN to arrange.

eu-prodyour VPClaptopa folderus-prodyour VPCci runnerpush onlyon-premno inboundsaved.shorchestrationALWAYS OUTBOUNDnothing listens, so nothing needs a firewall change

One worker per machine

A worker is a credential that lets a machine claim work, not a per-directory agent. Point as many backups at it as that machine can see.

Encrypted before it leaves the disk

Your public key is applied locally. What crosses the network is already ciphertext, and it stays that way at rest.

The credential stays local

Paths and any source configuration live in the worker's own config file. Our API rejects a source payload sent for a local backup.

Setting it up

Two binaries, and only one of them stays

savedthe CLIyou run it, it exitsterminal, CI, apply a YAML filesaved-workerthe workerruns, polls for worknext to the data, on your hardwaresaved.shoutbound HTTPS onlyNEITHER ONE LISTENS. NO INBOUND PORT, NO FIREWALL CHANGE.Both are single static binaries with no runtime to install.

on the machine that holds the data

curl -fsSL https://saved.sh/worker.sh | sh

saved worker provision reporting-box
saved-worker --config ./config.yaml &

saved backup create nginx-conf \
  --kind local --source folder \
  --path /etc/nginx --worker reporting-box \
  --schedule "0 3 * * *" --keep-last 14
Retention

Config directories are where holds earn their keep

A compromised machine is often a compromised backup schedule too. A hold is stamped onto each artifact as it is written and can be lengthened but never shortened, so loosening the policy afterwards cannot reach what is already stored.

LOCKED FOR 90 DAYSwrittenexpiresswept on scheduleCANNOT BE SHORTENED, BY YOU OR BY US
Limits

Where this does not fit

Local only, permanently

The source is your filesystem, so there is nothing for our cloud to connect to. A remote copy of your disk would be a different product with a different trust story, and we would rather not sell it.

The machine has to be awake

A worker that is off when the schedule fires does not run. A non-issue on a server, a real constraint on a laptop.

Full copies, not incremental

Each run produces a complete artifact. That costs more storage and buys a property worth having: every artifact stands alone, so no restore depends on an unbroken chain of earlier ones.

What it costs

Compression matters more here than anywhere

Config, logs and text often compress an order of magnitude, and you are billed on what is stored rather than on what you pointed at. A 2 GB directory of mostly text can be a couple of hundred megabytes on the meter.

What you need

  • A machine you control that is on when the schedule fires
  • Outbound HTTPS from that machine
  • A GPG public key uploaded to the workspace

No inbound port, no VPN, and no agent that phones home between runs. The worker polls and is otherwise idle.

Questions

Pick the machine you would least like to lose