saved.sh
DocsPricingDownloadBlog

By source

  • Database backupsPostgres today, on any of the three paths.
  • Files and foldersDirectories on your own hardware. Local path only.
  • Anything you can scriptThe escape hatch, with no reduced guarantees.

By how it runs

  • Backups you driveCLI or API, driven by whatever you already run.
  • Backups on your infrastructureOur worker, your hardware. We never hold the credential.
  • Fully managed backupsWe execute and orchestrate. Nothing to host.
  • Compliance and custodyYour bucket, your account, our orchestration.

Understand it

  • How it worksThree paths, one artifact lifecycle
  • SecurityWhat we can and cannot see
  • CompareAgainst snapshots, cloud-native and scripts
Get started
saved.sh

External backups for the systems a business actually runs on.

A product of reops.

Product

  • Documentation
  • Solutions
  • Compare
  • How it works
  • Security
  • Pricing
  • Download

Developers

  • CLI
  • REST API
  • Recover

Company

  • Blog
  • Privacy
  • Terms

© 2026 saved.sh

Your data survives what holds it.

All postsEngineering

How to back up a database with no public IP

The database that most needs backing up is usually the one nothing can reach. Most tools answer that with an inbound hole or a VPN. There is a better answer, and it is the one your CI already uses.

8 August 2026·saved.shView as Markdown

The database you care most about is frequently the one sitting on a private subnet with no route in from the internet. That is not an accident, it is the correct configuration, and it is exactly what makes backing it up awkward.

The usual options are all bad in the same way.

OptionWhat it costs you
Give the database a public IPYou undo the decision you made deliberately
Open the port to a vendor's IP rangeAn allowlist that changes when the vendor's does, and one shared secret away from being a hole
Site-to-site VPNWeeks of networking, and a permanent tunnel into your private network
Bastion with a scheduled SSH jobYou are back to a cron job on a box, with the key material to prove it

Every one of them treats the problem as "how do we get in".

Invert it

The pattern that avoids all four is the one your CI runners, your metrics agent and your log shipper already use: the thing inside makes an outbound connection and asks for work.

Nothing listens. No inbound rule, no allowlist, no tunnel, no public IP. The database keeps exactly the network position you gave it, and the only firewall change is the one you almost certainly already permit: outbound HTTPS on 443.

eu-prodyour VPC
us-prodyour VPC
on-premno inbound
laptopa folder
ci runnerpush only
saved.shorchestration

Always outbound

Nothing listens, so nothing needs a firewall change

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Nothing reaches in. A worker on your side dials out, takes a job, and does the dump where the database already is.

How it works here

You run a small worker process next to the database. On start it dials out and polls a queue that belongs only to it. When a run is due, the job comes down that connection, the worker dumps the database locally, and it uploads to your bucket.

Two properties of that arrangement are worth being specific about, because they are what make it safe rather than merely convenient.

Your credentials never leave the machine. The database password is read by the worker, on your side, from your configuration. It is not stored with us and it does not travel to us. Same for the bucket credentials.

Neither do the bytes. The steps of a run hand each other a path to a file on that machine. The dump does not pass through our orchestrator on its way to your bucket. Only metadata does: what ran, how long it took, how large the result was, and where it went.

0

Inbound firewall rules

0

Credentials that leave the machine

443

The only port involved

The one operational rule

A worker's queue is its identity, and only one process should poll it.

If you run two copies of the same worker configuration, the steps of a single run can split across two machines, and step two will look for a file that step one left somewhere else. That is not a subtle failure, it fails loudly, but it is worth knowing before you scale a deployment to two replicas out of habit.

Run one process per worker identity. If you want a second machine backing up different things, give it its own identity.

A useful side effect

Because the worker runs where the database already is, the dump never crosses the network as a database connection. On a large table that is often faster than any hosted option, and it does not consume the connection pool your application is using.

What this does not solve

Being honest about the boundary: an outbound worker does not help if the machine running it is itself the thing you are worried about. If an attacker owns that host, they own the database credentials and the worker process together.

That is the argument for the other half of the setup: send the copy to a bucket in a different account, and turn on Object Lock so that a credential holder cannot delete what is already written. Outbound polling solves the reachability problem. It was never going to solve the custody one.

Read next

How to back up a managed database you do not control

RDS, Neon, Supabase and PlanetScale all take snapshots for you. Those snapshots live in the provider's account, in the provider's format, and usually cannot be restored anywhere else. Here is what to do about it.

Backups that survive the thing that took out production.

How it worksStart free