Restore
Download and decrypt an artifact on your machine, with your key.
View as Markdownsctl restore postgres <artifact-id> --database scratchRestore happens entirely on your machine. The artifact is downloaded through a presigned URL, decrypted with your own private key, decompressed, and reconstructed according to its source type. Neither the target nor its credentials are ever sent to us.
We are not in the path and could not be: we have no private key.
One subcommand per target
Restoring a folder is not the same operation as restoring a database, so the target type is the subcommand and its flags are only the ones that type needs.
# Postgres: replayed into a database
sctl restore postgres <artifact-id> --host localhost --database scratch --user postgres
# MySQL: replayed with the mysql client
sctl restore mysql <artifact-id> --database scratch --user root
# Written to a path
sctl restore file <artifact-id> --path ./uploads.tar
sctl restore folder <artifact-id> --path ./restored.zipThe target is described with the same field names its source type uses, so a source:
block in a manifest and a restore command name things identically.
| Subcommand | Flags |
|---|---|
postgres | --host, --port, --database (required), --user, --password, --ssl-mode |
mysql | --host, --port, --database (required), --user, --password, --ssl-mode |
file | --path (required) |
folder | --path (required) |
file and folder do the same thing: they write the artifact to --path. Neither unpacks
it, because extracting into a tree you have not looked at is not a backup tool's decision.
--key applies to all of them: a private key file, defaulting to your gpg keyring or agent.
The target is validated before anything is downloaded, so a missing --database costs
you nothing:
$ sctl restore postgres <artifact-id>
Error: postgres target: database is requiredWhat it does
download → decrypt → decompress → reconstruct| Step | Detail |
|---|---|
| Download | Presigned URL, into a temporary directory that is removed on exit |
| Decrypt | gpg, if the artifact is encrypted |
| Decompress | gunzip, if the artifact is compressed. Whether or not it was encrypted |
| Reconstruct | pg_restore or psql for Postgres, mysql for MySQL; otherwise the file is moved to --path |
Compression is applied before encryption, so an artifact with both peels in that order and
neither step substitutes for the other. Doing this by hand is where that bites: stopping at
gpg --decrypt hands you a gzip stream, which psql, mysql, tar and the RDB reader all
reject. See the four combinations.
For Postgres it reads the first bytes of the dump to decide: PGDMP means custom format and
pg_restore, anything else means plain SQL and psql. You do not have to know which you
have.
Using a key file
sctl restore file <artifact-id> --path ./uploads.tar --key ./prod-private.ascThe key is imported into a temporary keyring that is deleted when the command exits, so nothing is left behind in your own keyring. That is the right choice on a machine you do not own, such as a recovery box during an incident.
Without --key, your normal gpg keyring and agent are used, and a passphrase prompt appears
if the key has one.
Restoring without the backup definition
sctl restore folder <artifact-id> --path ./data.tarYou name the target yourself, so nothing is looked up from the backup. That matters when the definition has been deleted but the artifact has not: you need the artifact and your key, and nothing else.
Requirements
| Restoring | Needs on your machine |
|---|---|
| An encrypted artifact | gpg, and the matching private key |
A postgres artifact | pg_restore and psql |
A mysql artifact | mysql |
| Anything else | Nothing |
If a tool is missing the command says which one and stops, rather than failing partway through. See installing gpg.
Restore into scratch first
Always, and especially during an incident.
createdb scratch
sctl restore postgres <artifact-id> --host localhost --database scratch
psql -d scratch -c 'SELECT max(created_at) FROM orders;'That last query gives your actual recovery point, which is when the dump started rather than when the run finished. It is the number to report to everyone else.
Restoring straight into a live database is destructive and irreversible. Restore to scratch, confirm the data is what you expect, then decide how to promote it. Most real recoveries want a few rows copied across, not a whole database replaced.
Doing it without sctl
The CLI is a convenience, not a dependency. Every step is a standard tool:
sctl artifact download <artifact-id> --output ./artifact
gpg --decrypt ./artifact > ./app.dump.gz
gunzip ./app.dump.gz
pg_restore --dbname scratch ./app.dumpRehearse that path at least once, so you know the recovery does not depend on us shipping a working binary. See Recover.
Troubleshooting
| Message | Cause |
|---|---|
postgres target: database is required | The target is checked before any download |
this artifact is encrypted and gpg was not found on PATH | Install gpg |
gpg: decryption failed: No secret key | The private key for this artifact's Key is not in your keyring |
restoring a postgres backup needs pg_restore on PATH | Install the Postgres client tools |
restoring a mysql backup needs mysql on PATH | Install the MySQL client |
not_in_our_storage | Delivered only to your own bucket. Fetch it from there |