Skip to content

Production ready postgres with backups to s3, restore, backup now, and daily backups.

Notifications You must be signed in to change notification settings

neiltalap/TheGreatPostgres

Repository files navigation

The Great Postgres — Secure Postgres + Backups

Secure, containerized Postgres 17 with S3 backups and mutual TLS (mTLS) access.

Highlights

  • Postgres 17 (alpine), public TLS on 5432
  • Certificate-only authentication (mTLS) — no passwords
  • S3-compatible backups + restore tooling

Quickstart

  1. Copy env template and fill values
    • cp .env.example .env (set S3 credentials and DB names/users)
  2. Generate TLS certs (CA, server with SAN, client per user)
    • ./generate-certs.sh --cn db.ozinozi.com --client admin --client appuser
    • The script automatically adds DNS:postgres to the server certificate SANs so internal services (backup/restore/exporter) can connect using host postgres with PGSSLMODE=verify-full. Add extra SANs with repeated --san flags.
    • Places server/CA under certs/ and client identities under structured folders client-certs/<user>/client.crt|client.key (and flat copies at client-certs/<user>.crt|.key). It also copies certs/ca.crt to client-certs/ca.crt for convenience.
    • Script auto-sets permissions; it also attempts chown 999:999 on server certs (optional)
    • If you see Permission denied for server.key in logs, run: ./fix-certs-perms.sh --restart
  3. Start Postgres
    • docker compose up -d postgres
    • Note: We use a PGDATA subdirectory so first initialization works even if the host mount (e.g., /mnt/.../pgdata) contains lost+found. The image initializes the cluster on first start. Application databases can be created later.
  4. Create extra DB users (if you generated additional client certs)
    • docker exec -it postgres-prod psql -U postgres -c "CREATE ROLE appuser LOGIN;"
    • The client cert CN must equal the Postgres role name
  5. Open firewall to 5432 for your allowed networks (mTLS required regardless)
  6. Test client connection (psql example)
    • psql "host=db.ozinozi.com port=5432 dbname=postgres user=dbuser sslmode=verify-full sslrootcert=ca.crt sslcert=client.crt sslkey=client.key"
  7. Configure and test backups
    • Generate an admin client cert (SUPERUSER) for full-cluster backups: ./generate-certs.sh --cn db.ozinozi.com --client admin
    • Backup/restore default to the admin identity and structured paths: client-certs/admin/client.{crt,key} and client-certs/ca.crt
    • ./backup-manager.sh setup (validates S3, builds images, runs a test backup)
    • ./backup-manager.sh list (verify uploaded backup)
    • If the backup service reports it cannot connect and your server cert was generated without DNS:postgres, re-run cert generation with --force or set PGSSLMODE=verify-ca for backup/restore in docker-compose.yaml.
    • To back up ALL databases and roles, set BACKUP_SCOPE=cluster in your .env (requires the backup user to be a superuser). Database-only backups remain the default.
  8. Optional: run exporter (Prometheus metrics on 9187)
    • docker compose up -d postgres-exporter

More

  • docs/overview.md — high-level summary
  • docs/tls-mtls.md — TLS and client cert setup
  • docs/clients.md — how to connect from clients
  • docs/backup-restore.md — backups and restores with mTLS
  • docs/commands.md — script usage (generate certs + backup manager)
  • docs/roles.md — creating app and datagrip roles + psql access
  • docs/cloudflare-tunnel.md — add an optional Cloudflare Tunnel

About

Production ready postgres with backups to s3, restore, backup now, and daily backups.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages