Sign inSign up

alexbidenko/postgres-backuper

By alexbidenko

•Updated 4 months ago

Docker Postgres Backup Manager

Image
0

3.5K

alexbidenko/postgres-backuper repository overview

⁠Docker Postgres Backup Manager

Docker Postgres Backup Manager is a lightweight controller container that orchestrates regular backups for one or many PostgreSQL instances. It exposes a small CLI that can be used both for scheduled operations (inside the container) and for manual backup or restore tasks.

⁠Key Features

  • Multi-database support. One controller container can maintain backups for several PostgreSQL services defined in DATABASE_LIST.
  • Configurable credentials per service. Override host, database, user and password for each database through environment variables.
  • Retention policy. Old archives are cleaned up automatically (daily backups are kept for 7 days, weekly for 30 days and monthly/manual for 365 days).
  • Operational tooling. Includes commands to list available backups, create dumps and restore them on demand.

⁠Container Layout

The container expects the following mount points:

MountPurpose
/var/lib/postgresql/backup/data/<database>Primary backup storage for each database.

When MODE=production, the controller writes directly to the /var/lib/postgresql/backup/* paths above. Otherwise backups are stored inside the working directory (./backup-data).

⁠PostgreSQL 18 Support

The controller's backup and restore flow remains the same on PostgreSQL 18 because it uses logical dumps via pg_dump and pg_restore, not PostgreSQL's on-disk cluster format.

  • Existing backup files do not need migration for PostgreSQL 18.
  • Upgrading a live PostgreSQL cluster still requires the usual PostgreSQL major-upgrade path: logical dump/restore, pg_upgrade, or logical replication.
  • If you run the official postgres:18 Docker image, mount the database service volume at /var/lib/postgresql rather than /var/lib/postgresql/data.

⁠Adding a New Database Service

  1. Define a new named volume for the database data in your docker-compose.yml.
  2. Create a new database service that uses that volume.
  3. Append the service name to the DATABASE_LIST environment variable of the controller (comma-separated).
  4. Mount a dedicated backup volume into the controller.
  5. (Optional) Provide custom credentials via environment variables (see below).

A complete example is available in compose.example.yaml⁠.

⁠Environment Variables

⁠General settings
VariableDescription
BACKUP_TARGETStorage provider used for backups. Set to local (default) or s3.
DATABASE_LISTComma-separated list of database service identifiers that the controller manages.
MODESet to production to use the predefined /var/lib/postgresql/backup/* locations and enable scheduled dumps.
TZOptional timezone used by cron-like scheduling inside the container.
⁠Backup content config

The controller optionally reads /etc/postgres-backuper/config.yaml. When the file is missing, backups remain full logical dumps exactly as before. When the file exists, profiles.default.exclude_table_data can list schema-qualified tables whose data should be omitted while keeping their table structure, constraints, triggers and index definitions in the dump. In automated start mode, the file is read during controller startup; restart the container after changing the config.

profiles:
  default:
    exclude_table_data:
      - public.resource_document_ai_semantic_chunks
      - public.resource_document_ai_representative_vectors
      - public.resource_document_ai_index_states

Each entry is passed to pg_dump as --exclude-table-data=<schema.table>. The controller validates that every configured relation exists before running pg_dump. Entries must be exact lowercase schema.table names; wildcard patterns, quoted identifiers and mixed-case table names are intentionally not supported. Missing tables or unknown YAML fields are treated as configuration errors. This setting applies to every current backup type: manual, daily, weekly and monthly.

Use this only for rebuildable or disposable data. After restore, excluded tables will exist but will be empty, so the application must be able to rebuild or tolerate that state. description and notes fields are accepted inside a profile for human documentation, but they do not affect backup behavior. See config.example.yaml for a complete example.

⁠Database connection overrides
VariableDescription
<SERVICE>_POSTGRES_HOSTHostname of the database service (defaults to the service name).
<SERVICE>_POSTGRES_USERUsername for the target database (defaults to postgres).
<SERVICE>_POSTGRES_PASSWORDPassword for the target database (defaults to postgres).
<SERVICE>_POSTGRES_PASSWORD_FILEPath to a file containing the target database password. If both password variables are set, the file value wins.
<SERVICE>_POSTGRES_DBDatabase name used for restores (defaults to postgres).

Note: Environment variable prefixes are derived from the service identifier in DATABASE_LIST. For example, a service named users uses USERS_POSTGRES_USER, USERS_POSTGRES_PASSWORD, etc. Hyphens (-) in service names are converted to underscores.

⁠S3 storage options
VariableDescription
S3_BUCKETBucket name used when BACKUP_TARGET=s3.
S3_PREFIXOptional prefix inside the S3 bucket where backups are stored.
S3_REGIONAWS region of the S3 endpoint.
S3_ENDPOINTEndpoint URL of the S3-compatible service.
S3_ACCESS_KEY_IDAccess key for the S3 service.
S3_ACCESS_KEY_ID_FILEPath to a file containing the S3 access key ID. If both access key variables are set, the file value wins.
S3_SECRET_ACCESS_KEYSecret key for the S3 service.
S3_SECRET_ACCESS_KEY_FILEPath to a file containing the S3 secret access key. If both secret key variables are set, the file value wins.
S3_USE_TLSSet to true to use HTTPS (recommended).
S3_FORCE_PATH_STYLESet to true for S3-compatible services that require path-style addressing.

⁠S3-compatible storage

Set BACKUP_TARGET=s3 to store backups in an S3-compatible bucket. The controller will upload each dump using the credentials and endpoint supplied via the S3_* variables listed above. Backups remain fully compatible with all other commands (listing and restoring downloads the dump to a temporary location inside the container).

⁠Integration tests

The integration test suite uses Docker to spin up PostgreSQL and controller containers. Tests that exercise S3 storage require credentials supplied through the TEST_S3_* environment variables. You can create a local .env file (ignored by Git) by copying .env.example and filling in the required values. The test harness automatically loads the file when present.

⁠Controller CLI

The controller binary is available inside the container as /controller. All commands must be executed as the postgres user.

⁠Automated mode
./controller start

Runs an infinite loop (designed for container start-up) that performs a dump every 6 hours at HH:03, HH:09, HH:15 and HH:21 when MODE=production. The backup type is selected automatically:

  • Monthly on the first day of the month.
  • Weekly on Saturdays.
  • Daily for all other runs.

Retention is enforced after each run according to the policy described above.

⁠Manual operations
./controller dump <database-name|--all>

Creates a dump for a single database, or for every database listed in DATABASE_LIST when --all is provided.

./controller restore <database-name> <backup-file>

Restores a dump located in the database backup directory. Use the filename listed by ./controller list (for example file_daily_2025-07-04T09:00:00Z.dump).

./controller list <database-name>

Lists available backup files for the given database.

⁠Permissions

The image runs the controller as the postgres user, matching the default user in the upstream PostgreSQL image. Mounted backup volumes must already be writable by that user—use user: postgres in your Compose configuration (or adjust ownership on the host) so the controller can create and restore dump files. If you mount /etc/postgres-backuper/config.yaml, the file only needs to be readable by postgres; Docker configs and bind-mounted files with 0444 or 0644 permissions work.

⁠License

This project is distributed under the terms of the MIT License⁠.

⁠Testing

Integration tests cover the full backup and restore flow by orchestrating PostgreSQL and the controller inside Docker containers. To run them locally:

go clean -testcache ; go test ./test/... -v

Tip: run with -v to see a step-by-step log of every Docker command that the suite executes.

Note: Docker must be available in the environment. When it is missing the integration suite is skipped.

Tag summary

Content type

Image

Digest

sha256:80187ea03…

Size

114.2 MB

Last updated

4 months ago

docker pull alexbidenko/postgres-backuper