PG-BKUP backs up, restores and migrates PostgreSQL databases. It streams pg_dump output through compression and encryption straight into the storage: no temporary dump file, constant memory, whatever the database size.
Documentation: https://jkaninda.github.io/pg-bkup · MySQL: mysql-bkup
- Storage: local, Amazon S3 and S3-compatible (MinIO, Wasabi, R2...), Google Cloud Storage, Azure Blob, SFTP, FTP/FTPS.
- Streaming:
pg_dump | gzip/zstd | GPG/age | upload, and back for restores. Nothing is written to disk. - Encryption: GPG (passphrase or public key) and age (recipients or passphrase).
- Safe restores:
psql -v ON_ERROR_STOP=1 --single-transaction(custom archives too, throughpg_restore -f -): a failing or corrupted backup changes nothing, and a dump from another server is not stopped by its roles or itspg_dumpversion. - Every PostgreSQL version: the image ships the 16, 17 and 18 clients and picks, per server, the lowest
pg_dumpthat is not older than the server (servers 9.2 and newer). No more "server version mismatch". - Backup index and retention: by age (
BACKUP_RETENTION_DAYS) or count (BACKUP_RETENTION_COUNT); only backups recorded in the index are ever deleted. - Commands:
backup,restore,migrate,verify,list,delete,prune,reconcile,config,health. - Scheduling:
--cron-expressiondaemon with a DockerHEALTHCHECKand optional Prometheus metrics. - Notifications: email, Telegram, Slack, Discord, ntfy, generic webhook, healthchecks.io pings.
- Formats: plain SQL (default,
.sql) or custom (PG_DUMP_FORMAT=custom,.dump); schema-only, data-only, selected or excluded tables, all databases one file each, or the whole instance withpg_dumpall.
docker run --rm --network your_network \
-v $PWD/backup:/backup \
-e DB_HOST=postgres -e DB_USER=postgres -e DB_PASSWORD=password \
jkaninda/pg-bkup backup -d database_nameThe last line of a successful backup always names the artifact:
level=INFO msg="Backup completed" database=database_name file=database_name_20261027_031500.sql.gz size=12.3MiB duration=2.1s storage=local location=/backup
Restore it (the target database must exist):
docker run --rm --network your_network \
-v $PWD/backup:/backup \
-e DB_HOST=postgres -e DB_USER=postgres -e DB_PASSWORD=password \
jkaninda/pg-bkup restore -d database_name -f database_name_20261027_031500.sql.gzrestore accepts .sql, .sql.gz, .sql.zst, .dump (custom format) and any of them encrypted (.gpg, .age). The format is detected from the content, not the name.
A connection URL works too: DB_URL=postgres://user:p%40ss@host:5432/db?sslmode=require or the 1.x JDBC form jdbc:postgresql://host:5432/db?user=user&password=pass.
| Command | File name |
|---|---|
backup -d shop |
shop_20261027_031500.sql.gz |
backup -d shop --schema-only |
shop_schema_20261027_031500.sql.gz |
backup -d shop --data-only |
shop_data_20261027_031500.sql.gz |
backup -d shop -t users -t orders (or --tables users,orders) |
shop_tables_2_20261027_031500.sql.gz |
backup -d shop --exclude-table audit_log |
shop_20261027_031500.sql.gz |
backup -d shop --custom-name nightly |
nightly.sql.gz (overwritten each run) |
PG_DUMP_FORMAT=custom backup -d shop |
shop_20261027_031500.dump.gz |
backup --all-databases --exclude-db _aiven,defaultdb |
one file per database |
backup --all-in-one --no-role-passwords |
all_databases_20261027_031500.sql.gz (pg_dumpall: roles, tablespaces, every database) |
--all-databases skips templates and the postgres database; databases are listed from DB_AUTH_DATABASE (default postgres).
An --all-in-one file is restored with restore -f all_databases_....sql.gz (no -d): it is replayed without a single transaction and, by default, without ON_ERROR_STOP, because pg_dumpall output always contains statements such as CREATE ROLE postgres that fail on an existing server (RESTORE_ON_ERROR_STOP).
The custom format is dumped with pg_dump -Fc -Z0 and compressed by the pipeline (parallel gzip or zstd), so COMPRESSION applies to both formats and every artifact is decompressed the same way. Custom-format archives are turned into SQL by pg_restore --no-owner -f - and replayed by the same psql as plain dumps (RESTORE_NO_OWNER=false keeps ownership).
migrate pipes pg_dump into psql on the target (TARGET_DB_*), with no intermediate file:
docker run --rm --network your_network \
-e DB_HOST=old -e DB_USER=postgres -e DB_PASSWORD=pw -e DB_NAME=shop \
-e TARGET_DB_HOST=new -e TARGET_DB_USER=postgres -e TARGET_DB_PASSWORD=pw -e TARGET_DB_NAME=shop \
jkaninda/pg-bkup migratemigrate --all-databases(-a) copies every database into the same name, creating missing ones.migrate --entire-instance(-I) copies roles, tablespaces and every database withpg_dumpall(add--no-role-passwordsto keep the target's passwords).- A single database is copied in one transaction; the target database is created if it does not exist.
TARGET_DB_URL,TARGET_DB_SSL_MODE,TARGET_DB_SSL_CA/CERT/KEYandTARGET_DB_AUTH_DATABASEare honoured.
# S3 / MinIO
-e AWS_S3_ENDPOINT=https://s3.amazonaws.com -e AWS_S3_BUCKET_NAME=backups -e AWS_REGION=us-east-1 \
-e AWS_ACCESS_KEY=... -e AWS_SECRET_KEY=... \
jkaninda/pg-bkup backup --storage s3 -d shop --path /prod/shop
# MinIO: add AWS_DISABLE_SSL=true (plain http) and AWS_FORCE_PATH_STYLE=true.
# Without keys, the AWS default credential chain (IAM role, IRSA, profile) is used.
# SFTP (host keys are verified: mount a known_hosts file)
-e SFTP_HOST=backup.example.com -e SFTP_USER=backup -e SFTP_IDENTITY_FILE=/config/id_ed25519 \
-e SFTP_KNOWN_HOSTS=/config/known_hosts \
jkaninda/pg-bkup backup --storage sftp -d shop --path /home/backup/shop
# FTP, Azure Blob, Google Cloud Storage
jkaninda/pg-bkup backup --storage ftp -d shop --path /backups # FTP_HOST, FTP_USER, FTP_PASSWORD [FTP_TLS]
jkaninda/pg-bkup backup --storage azure -d shop --path backups # AZURE_STORAGE_ACCOUNT_NAME, _KEY (or _SAS_TOKEN), _CONTAINER_NAME
jkaninda/pg-bkup backup --storage gcs -d shop --path backups # GCS_BUCKET, GCS_CREDENTIALS_FILErestore takes the same --storage and --path plus the bare file name: restore --storage s3 --path /prod/shop -d shop -f shop_20261027_031500.sql.gz.gpg.
| Mode | Backup | Restore |
|---|---|---|
| GPG passphrase | GPG_PASSPHRASE |
GPG_PASSPHRASE |
| GPG public key | GPG_PUBLIC_KEY (path or inline), or /config/gnupg/public_key.{asc,gpg} |
GPG_PRIVATE_KEY (+ GPG_PRIVATE_KEY_PASSPHRASE, defaults to GPG_PASSPHRASE) |
| age recipients | AGE_RECIPIENTS (age1..., ssh-ed25519 ...) or AGE_RECIPIENTS_FILE |
AGE_IDENTITY / AGE_IDENTITY_FILE (default /config/age/identity.txt) |
| age passphrase | AGE_PASSPHRASE |
AGE_PASSPHRASE |
ENCRYPTION=auto (default) picks from the keys that are set; GPG wins when both are set. Encryption fails closed: a configured but unusable key aborts the backup. Encrypted files end in .gpg or .age.
Each storage directory holds an index (BACKUP_INDEX_NAME, default pg-bkup-metadata.json, placeholders {tool} {engine} {name} {db}) and a <artifact>.meta.json sidecar per backup, with size, sha256, server version and encryption.
BACKUP_RETENTION_DAYS=7and/orBACKUP_RETENTION_COUNT=10prune after each backup; the newest backup is always kept.- Only files recorded in the index are deleted. Backups made before the index existed are imported with
BACKUP_RETENTION_ADOPT_LEGACY=true;BACKUP_INDEX=falsefalls back to name-pattern retention. list,verify -f FILE,delete -f FILE,prune [--dry-run]andreconcilework from the index.
docker run -d --name pg-bkup --network your_network -v $PWD/backup:/backup \
-e DB_HOST=postgres -e DB_USER=postgres -e DB_PASSWORD=password -e BACKUP_RETENTION_DAYS=7 \
jkaninda/pg-bkup backup -d database_name --cron-expression "@daily"Cron expressions take 5 or 6 fields, @daily/@hourly/... or @every 6h. BACKUP_RUN_ON_START=true runs one backup immediately. A failed run is logged and notified and the daemon keeps running. docker inspect shows the health status (pg-bkup health); METRICS_ADDR=:9090 serves Prometheus metrics.
On Kubernetes, prefer a CronJob running a one-shot backup (see the docs).
# /config/config.yaml (or --config / BACKUP_CONFIG_FILE)
cronExpression: "@daily" # optional
databases:
- host: lldap-db
name: lldap
user: lldap
password: ${LLDAP_DB_PASSWORD} # ${VAR} and ${VAR:-default} are expanded
path: /s3-path/lldap
- name: keycloak # host/user/password from DB_HOST_KEYCLOAK or KEYCLOAK_DB_HOST, ... then DB_HOST
path: /s3-path/keycloak
sslMode: requireFor each entry: the YAML field wins, then <KEY>_<NAME> / <NAME>_<KEY> env vars (e.g. DB_PASSWORD_KEYCLOAK, KEYCLOAK_DB_PASSWORD), then the global variable.
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | failure (dump, restore, ...) |
| 2 | configuration or usage error |
| 3 | connection or authentication error |
| 4 | storage error |
| 5 | encryption error |
--result-file PATH writes the result as JSON; LOG_FORMAT=json makes the logs machine-readable.
pg-bkup backup [-d DB | -a | -A] [--storage S] [--path P] [--cron-expression E]
pg-bkup restore -f FILE [-d DB] [--storage S] [--path P]
pg-bkup migrate [-d DB | -a | -I]
pg-bkup verify -f FILE # download, decrypt, decompress, check sha256
pg-bkup list [--json] [--storage-scan]
pg-bkup delete -f FILE
pg-bkup prune [--dry-run]
pg-bkup reconcile [--from-index OLD] [--dry-run]
pg-bkup config [--all] [--env-docs]
pg-bkup health
pg-bkup version
The image also provides backup, restore and migrate wrapper scripts and the bkup alias, so docker run jkaninda/pg-bkup backup ... and docker exec pg-bkup bkup backup ... both work.
Every 1.x variable and flag still works; renamed variables log a deprecation warning once. What changed:
- Restores are atomic. Database dumps are replayed with
ON_ERROR_STOP=1 --single-transaction: the first error rolls everything back and the command fails (1.x continued after errors). v2 dumps includeDROP ... IF EXISTSstatements (PG_CLEAN, default on), so restoring one over an existing database replaces its objects inside that transaction. A 1.x dump (no drops) restored into a database that already contains its tables now fails instead of half-applying: restore it into an empty database, or setRESTORE_SINGLE_TRANSACTION=falseand/orRESTORE_ON_ERROR_STOP=falsefor the 1.x behaviour. - Restores into another server still work. Ownership statements are skipped (
RESTORE_NO_OWNER), and grants to roles the server does not have, or aSETof a parameter it does not know (transaction_timeouton PostgreSQL 16 and older), are skipped with a warning rather than stopping the restore. Apg_dump --createdump is restored into the named database, never into or over its source database. Any other error still rolls it back. --schema-onlyand--tablesbackups are compressed (shop_schema_<timestamp>.sql.gz; 1.x wrote.sql).--data-onlyfiles get a_data_infix. Use--disable-compressionfor the old extension.- Client versions:
pg_dump16, 17 or 18 is chosen per server;PG_CLIENT_VERSIONforces one. Dumps of servers older than 17 are taken withpg_dump16, so they restore on those servers. DB_SSL_MODEis passed topg_dump,psqlandpg_restore(1.x only used it for the connection test). The default is now libpq's own (prefer) instead ofdisable;DB_SSL_CA,DB_SSL_CERTandDB_SSL_KEYare new.DB_URLalso acceptspostgres://URIs (credentials percent-encoded). An explicit-d/DB_NAMEnow wins over the URL's database.- Migrate is a direct pipe (no temp file) and honours
TARGET_DB_SSL_MODEandTARGET_DB_AUTH_DATABASE, which 1.x ignored. - Retention only deletes backups recorded in the index (see above). Set
BACKUP_RETENTION_ADOPT_LEGACY=trueonce to adopt 1.x backups. STORAGEis honoured (1.x always used the flag's defaultlocalunless--storagewas given). Unknown storage names are errors instead of falling back to local.- SFTP variables are renamed, and the old names are no longer read:
SSH_HOST/SSH_HOST_NAME→SFTP_HOST,SSH_PORT→SFTP_PORT,SSH_USER→SFTP_USER,SSH_PASSWORD→SFTP_PASSWORD,SSH_IDENTIFY_FILE/SSH_IDENTITY_FILE→SFTP_IDENTITY_FILE,SSH_REMOTE_PATH→REMOTE_PATH. - SFTP host keys are verified. Set
SFTP_KNOWN_HOSTS, orSFTP_INSECURE_IGNORE_HOST_KEY=truefor the 1.x behaviour.SFTP_PORTdefaults to 22. MAIL_SKIP_TLSnow means what it says (trueskips certificate verification); 1.x inverted it. PreferMAIL_INSECURE_SKIP_VERIFYandMAIL_TLS=starttls|tls|none.AWS_REGIONdefaults tous-east-1;AWS_ACCESS_KEY/AWS_SECRET_KEYmay be omitted to use the AWS credential chain.- The
templatesdirectory is built in; custom notification templates go inTEMPLATES_DIR(default/config/templates). - The image runs
tinias PID 1 and has aHEALTHCHECK(daemon mode only). Tags:latest,vX.Y.Z,vX.Y,vX; pin a version in production.
Generated with pg-bkup config --env-docs. Every secret also accepts <NAME>_FILE (Docker/Kubernetes secrets). Resolution order: flag > variable > deprecated name > config file > default.
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
STORAGE |
--storage -s |
local |
Storage backend: local, s3, gcs, azure, sftp (ssh), ftp (local, s3, gcs, azure, sftp, ssh, ftp, remote) | |
STORAGE_PATH |
/backup |
Root directory of the local storage backend | ||
REMOTE_PATH |
--path -P |
AWS_S3_PATH (deprecated), S3_PATH (deprecated) |
Folder inside the storage backend (without file name) |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
BACKUP_NAME |
--name -n |
Base name of the artifact; a timestamp is appended (default: the database or volume name) | ||
BACKUP_CUSTOM_NAME |
--custom-name |
Fixed artifact name without timestamp (overwrites the previous one) | ||
FILE_NAME |
--file -f |
Backup file to restore, verify or delete | ||
BACKUP_CONFIG_FILE |
--config -c |
YAML configuration file (default /config/config.yaml if present) | ||
BACKUP_TIMEOUT |
Abort a backup after this duration (0 = none) | |||
RESTORE_TIMEOUT |
Abort a restore after this duration (0 = none) | |||
TMP_DIR |
/tmp/backup |
BACKUP_TMP_DIR (deprecated) |
Scratch directory (only for secret files and disk-based modes) | |
COMPRESSION |
--compression |
gzip |
Compression: gzip, zstd or none (gzip, zstd, none) | |
COMPRESSION_LEVEL |
Compression level (0 = default) | |||
DISABLE_COMPRESSION |
--disable-compression |
Same as COMPRESSION=none | ||
RESTORE_VERIFY_FIRST |
--verify-first |
auto |
Verify the whole artifact before restoring (auto: on for GPG-encrypted volumes) (auto, true, false) | |
LOG_LEVEL |
info |
Log level (debug, info, warn, error) | ||
LOG_FORMAT |
text |
Log format (text, json) | ||
TIME_FORMAT |
2006-01-02 15:04:05 |
Time layout used in notifications | ||
RESULT_FILE |
--result-file |
Write the run result as JSON to this path |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
BACKUP_CRON_EXPRESSION |
--cron-expression -e |
Run as a daemon on this cron schedule (5 or 6 fields, @daily, @every 6h) | ||
BACKUP_RUN_ON_START |
In daemon mode, run one backup immediately at start | |||
BACKUP_RESCUE_MODE |
Deprecated: runs always continue with the remaining targets after a failure | |||
METRICS_ADDR |
Serve Prometheus /metrics and /healthz on this address in daemon mode (e.g. :9090) | |||
HEALTH_FILE |
/tmp/bkup-health.json |
State file read by the health command | ||
HEALTH_MAX_AGE |
health fails when the last success is older than this (default: 2x the schedule interval) |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
BACKUP_RETENTION_DAYS |
0 |
Delete backups older than N days (0 = keep) | ||
BACKUP_RETENTION_COUNT |
0 |
Keep only the newest N backups (0 = no limit) | ||
BACKUP_RETENTION_ALLOW_ROOT |
Allow pattern-based retention at the storage root (index disabled) | |||
BACKUP_RETENTION_ADOPT_LEGACY |
Import pre-index backups matching this tool's naming into the index | |||
BACKUP_INDEX |
true |
Keep the backup index file and per-backup .meta.json sidecars | ||
BACKUP_INDEX_NAME |
--index-name |
{tool}-metadata.json |
Index file name; placeholders {tool} {engine} {name} {db} |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
AWS_S3_ENDPOINT |
S3_ENDPOINT (deprecated), AWS_ENDPOINT_URL_S3, AWS_ENDPOINT_URL |
S3 endpoint (empty = AWS) | ||
AWS_S3_BUCKET_NAME |
BUCKET_NAME (deprecated), AWS_BUCKET_NAME (deprecated) |
S3 bucket | ||
AWS_REGION |
us-east-1 |
AWS_DEFAULT_REGION |
S3 region | |
AWS_ACCESS_KEY |
ACCESS_KEY (deprecated), AWS_ACCESS_KEY_ID |
S3 access key (empty = default AWS credential chain) | ||
AWS_SECRET_KEY |
SECRET_KEY (deprecated), AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY_FILE |
S3 secret key | ||
AWS_SESSION_TOKEN |
AWS_SESSION_TOKEN_FILE |
S3 session token | ||
AWS_PROFILE |
AWS shared config profile | |||
AWS_DISABLE_SSL |
Use http for the S3 endpoint | |||
AWS_FORCE_PATH_STYLE |
Path-style S3 addressing (MinIO) | |||
S3_STORAGE_CLASS |
S3 storage class | |||
S3_SSE |
Server-side encryption: AES256 or aws:kms (aes256, aws:kms) | |||
S3_SSE_KMS_KEY_ID |
KMS key id for aws:kms | |||
S3_PART_SIZE |
64MiB |
Multipart part size; max object size is 10000 x this | ||
S3_UPLOAD_CONCURRENCY |
2 |
Parallel part uploads (memory = part size x this) |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
SFTP_HOST |
SFTP host | |||
SFTP_PORT |
22 |
SFTP port | ||
SFTP_USER |
SFTP user | |||
SFTP_PASSWORD |
SFTP_PASSWORD_FILE |
SFTP password | ||
SFTP_IDENTITY_FILE |
SFTP private key file (the SSH agent is also used when SSH_AUTH_SOCK is set) | |||
SFTP_IDENTITY_PASSPHRASE |
SFTP_IDENTITY_PASSPHRASE_FILE |
Passphrase of the SFTP private key | ||
SFTP_KNOWN_HOSTS |
known_hosts file used to verify the SFTP host key (default ~/.ssh/known_hosts) | |||
SFTP_INSECURE_IGNORE_HOST_KEY |
Do not verify the SFTP host key (insecure) |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
FTP_HOST |
FTP_HOST_NAME (deprecated) |
FTP host | ||
FTP_PORT |
21 |
FTP port | ||
FTP_USER |
FTP user | |||
FTP_PASSWORD |
FTP_PASSWORD_FILE |
FTP password | ||
FTP_TLS |
Use explicit FTPS |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
AZURE_STORAGE_ACCOUNT_NAME |
Azure storage account | |||
AZURE_STORAGE_ACCOUNT_KEY |
AZURE_STORAGE_ACCOUNT_KEY_FILE |
Azure storage account key | ||
AZURE_STORAGE_CONTAINER_NAME |
Azure blob container | |||
AZURE_STORAGE_ENDPOINT |
Azure blob endpoint (Azurite, sovereign clouds) | |||
AZURE_STORAGE_SAS_TOKEN |
AZURE_STORAGE_SAS_TOKEN_FILE |
Azure SAS token (instead of the account key) |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
GCS_BUCKET |
GCS bucket | |||
GCS_CREDENTIALS_FILE |
GOOGLE_APPLICATION_CREDENTIALS |
GCS service account JSON file | ||
GCS_CREDENTIALS_JSON |
GCS_CREDENTIALS_JSON_FILE |
GCS service account JSON content | ||
GCS_ENDPOINT |
GCS endpoint (emulators) |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
ENCRYPTION |
--encryption |
auto |
auto (from the keys set), none, gpg or age (auto, none, gpg, age) | |
ENCRYPTION_ARMOR |
ASCII-armor encrypted output | |||
GPG_PASSPHRASE |
GPG_PASSPHRASE_FILE |
GPG symmetric passphrase | ||
GPG_PUBLIC_KEY |
GPG public key(s): file path or inline key (default /config/gnupg/public_key.{asc,gpg}) | |||
GPG_PRIVATE_KEY |
GPG_PRIVATE_KEY_FILE |
GPG private key for restore: file path or inline key (default /config/gnupg/private_key.{asc,gpg}) | ||
GPG_PRIVATE_KEY_PASSPHRASE |
GPG_PRIVATE_KEY_PASSPHRASE_FILE |
Passphrase of the GPG private key (default GPG_PASSPHRASE) | ||
AGE_RECIPIENTS |
age recipients (age1..., ssh-ed25519 ...), comma or newline separated | |||
AGE_RECIPIENTS_FILE |
File with age recipients | |||
AGE_PASSPHRASE |
AGE_PASSPHRASE_FILE |
age passphrase (scrypt) | ||
AGE_IDENTITY |
AGE_IDENTITY_FILE |
age identity (AGE-SECRET-KEY-...) for restore | ||
AGE_IDENTITY_FILE |
age identity file for restore (default /config/age/identity.txt) |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
MAIL_HOST |
SMTP host | |||
MAIL_PORT |
587 |
SMTP port | ||
MAIL_USERNAME |
SMTP user | |||
MAIL_PASSWORD |
MAIL_PASSWORD_FILE |
SMTP password | ||
MAIL_FROM |
Sender address | |||
MAIL_TO |
Recipients, comma separated | |||
MAIL_SKIP_TLS |
Deprecated: true skips certificate verification (use MAIL_INSECURE_SKIP_VERIFY) | |||
MAIL_INSECURE_SKIP_VERIFY |
Skip SMTP certificate verification | |||
MAIL_TLS |
starttls |
SMTP TLS mode (starttls, tls, none) | ||
TG_TOKEN |
TELEGRAM_BOT_TOKEN, TG_TOKEN_FILE |
Telegram bot token | ||
TG_CHAT_ID |
TELEGRAM_CHAT_ID |
Telegram chat id | ||
POSTA_URL |
Posta base URL (https://posta.example.com) for email notifications through Posta | |||
POSTA_API_KEY |
POSTA_API_KEY_FILE |
Posta API key with the send scope | ||
POSTA_WORKSPACE_ID |
Posta workspace id (only for account-wide API keys) | |||
POSTA_FROM |
Posta sender address (default MAIL_FROM) | |||
POSTA_TO |
Posta recipients, comma separated (default MAIL_TO) | |||
POSTA_TEMPLATE |
Posta template name for notifications; the event fields are passed as template data (default: built-in HTML) | |||
POSTA_TEMPLATE_ERROR |
Posta template name for failures (default POSTA_TEMPLATE) | |||
POSTA_LANGUAGE |
Posta template language | |||
WEBHOOK_URL |
Generic JSON webhook URL | |||
WEBHOOK_SECRET |
WEBHOOK_SECRET_FILE |
HMAC-SHA256 secret for the X-Bkup-Signature header | ||
SLACK_WEBHOOK_URL |
SLACK_WEBHOOK_URL_FILE |
Slack incoming webhook URL | ||
DISCORD_WEBHOOK_URL |
DISCORD_WEBHOOK_URL_FILE |
Discord webhook URL | ||
NTFY_URL |
ntfy topic URL | |||
NTFY_TOKEN |
NTFY_TOKEN_FILE |
ntfy access token | ||
NOTIFY_ON |
always |
When to notify (always, failure, success, never) | ||
HEALTHCHECK_PING_URL |
healthchecks.io-style URL pinged on start (/start), success and failure (/fail) | |||
BACKUP_REFERENCE |
Free text included in notifications | |||
TEMPLATES_DIR |
/config/templates |
Directory with custom notification templates |
| Variable | Flag | Default | Fallbacks | Description |
|---|---|---|---|---|
DB_URL |
DB_URL_FILE |
Connection URL: postgres://user:pass@host:5432/db?sslmode=require or jdbc:postgresql://host:5432/db?user=u&password=p (overrides host, port, user, password; its database is used when DB_NAME is not set) | ||
DB_HOST |
localhost |
Database host | ||
DB_PORT |
5432 |
Database port | ||
DB_NAME |
--dbname -d |
Database name | ||
DB_USER |
DB_USERNAME |
Database user | ||
DB_PASSWORD |
DB_PASSWORD_FILE |
Database password | ||
DB_SSL_MODE |
libpq sslmode, passed to pg_dump, psql and pg_restore as PGSSLMODE (empty = libpq default, prefer) (disable, allow, prefer, require, verify-ca, verify-full) | |||
DB_SSL_CA |
CA certificate file (PGSSLROOTCERT) | |||
DB_SSL_CERT |
Client certificate file (PGSSLCERT) | |||
DB_SSL_KEY |
Client key file (PGSSLKEY) | |||
BACKUP_ALL_DATABASES |
--all-databases -a |
backup: every database (templates and 'postgres' excluded), one file each; migrate: every database into the same name on the target | ||
BACKUP_ALL_IN_ONE |
--all-in-one -A |
Back up the whole instance (roles, tablespaces, all databases) into one file with pg_dumpall | ||
BACKUP_EXCLUDE_DATABASES |
--exclude-db |
Databases to skip with --all-databases / --all-in-one, comma separated (repeatable flag) | ||
TARGET_DB_URL |
TARGET_DB_URL_FILE |
migrate: target connection URL (postgres:// or jdbc:postgresql://) | ||
TARGET_DB_HOST |
migrate: target host | |||
TARGET_DB_PORT |
5432 |
migrate: target port | ||
TARGET_DB_NAME |
migrate: target database | |||
TARGET_DB_USER |
TARGET_DB_USERNAME |
migrate: target user | ||
TARGET_DB_PASSWORD |
TARGET_DB_PASSWORD_FILE |
migrate: target password | ||
TARGET_DB_SSL_MODE |
migrate: target libpq sslmode (disable, allow, prefer, require, verify-ca, verify-full) | |||
TARGET_DB_SSL_CA |
migrate: target CA certificate file | |||
DB_AUTH_DATABASE |
postgres |
Maintenance database used to list databases, create databases and run pg_dumpall | ||
TARGET_DB_AUTH_DATABASE |
postgres |
migrate: target maintenance database | ||
TARGET_DB_SSL_CERT |
migrate: target client certificate file | |||
TARGET_DB_SSL_KEY |
migrate: target client key file | |||
PG_DUMP_FORMAT |
--dump-format |
plain |
Dump format: plain (.sql, psql) or custom (.dump, pg_dump -Fc -Z0, pg_restore); COMPRESSION applies to both (plain, custom) | |
PG_CLIENT_VERSION |
Force a PostgreSQL client major (16, 17, 18); default: the lowest bundled client >= the server version | |||
BACKUP_SCHEMA_ONLY |
--schema-only |
Dump the schema only (file name infix schema) | ||
BACKUP_DATA_ONLY |
--data-only |
Dump the data only (file name infix data) | ||
BACKUP_TABLES |
--tables -t |
Only these tables (pg_dump -t patterns), comma separated or repeated (file name infix tables_N) | ||
BACKUP_EXCLUDE_TABLES |
--exclude-table |
Skip these tables (pg_dump --exclude-table patterns), comma separated or repeated | ||
BACKUP_NO_ROLE_PASSWORDS |
--no-role-passwords |
--all-in-one / migrate --entire-instance: do not dump role passwords (managed services such as Aiven, OVH) | ||
MIGRATE_ENTIRE_INSTANCE |
--entire-instance -I |
migrate: copy the whole instance (roles, tablespaces, all databases) with pg_dumpall | ||
RESTORE_SINGLE_TRANSACTION |
true |
Restore a database dump in one transaction (all or nothing); not used for --all-in-one dumps | ||
RESTORE_ON_ERROR_STOP |
auto |
Stop a psql restore at the first error; auto = on for database dumps, off for --all-in-one (pg_dumpall) dumps, which always contain 'role already exists' errors (auto, true, false) | ||
PG_CLEAN |
true |
Drop objects before recreating them (pg_dump/pg_restore --clean --if-exists), so a restore replaces an existing database inside its transaction | ||
RESTORE_NO_OWNER |
true |
Do not restore object ownership: skip ALTER ... OWNER TO (pg_restore --no-owner for custom dumps), so the restoring user owns the objects; grants to roles missing on the server are skipped with a warning either way |
docker pull jkaninda/pg-bkup
docker pull ghcr.io/jkaninda/pg-bkup
This project is licensed under the MIT License. See the LICENSE file for details.
Jonas Kaninda - https://github.com/jkaninda
Copyright (c) [2024] [Jonas Kaninda]