This project provides a local development and testing environment for a PostgreSQL setup featuring High Availability (HA) components, using only free and open-source software orchestrated with Docker Compose.
It demonstrates a configuration including:
- PostgreSQL Primary Server: Handles writes and acts as the replication source.
- PostgreSQL Streaming Replica: Provides read scaling and a warm standby for failover scenarios.
- PgBouncer: Lightweight connection pooling to optimize database connections from applications.
- pgBackRest: Robust backup and restore solution tailored for PostgreSQL.
- pgAdmin4: Web-based administration GUI for managing the databases.
- Host Volume Persistence: Ensures data, configurations, and backups persist across container restarts.
Goal: To offer a convenient local setup that mimics essential aspects of a production-ready, scalable PostgreSQL deployment, facilitating development and testing of applications requiring a resilient database backend.
- Features
- Directory Structure
- Prerequisites
- Quick Start
- Configuration
- Usage
- Detailed Documentation
- Administration
- Scaling
- Security Considerations
- Limitations
- Contributing
- License
- PostgreSQL 15 (or specify version used) Primary-Replica setup.
- Asynchronous Streaming Replication for HA and read scaling.
- Connection Pooling with PgBouncer.
- Browser-based Administration via pgAdmin4.
- Integrated Backup & Restore using pgBackRest.
- Persistent data storage using host-mounted volumes.
- Configuration managed via external files and
.envfor secrets. - Designed with scalability concepts in mind (though Docker Compose is single-host).
.
├── docker-compose.yaml # Main Docker Compose definition
├── .env.example # Example environment variables (Copy to .env)
├── .env # Environment variables (Secrets - DO NOT COMMIT)
├── data/ # Persisted data (mounted from host)
│ ├── primary/ # Primary DB data
│ └── replica/ # Replica DB data
├── config/ # Configuration files
│ ├── primary/
│ │ ├── postgresql.conf # Primary DB configuration
│ │ └── pg_hba.conf # Primary DB access rules
│ └── replica/
│ ├── postgresql.conf # Replica DB configuration
│ ├── pg_hba.conf # Replica DB access rules
│ └── entrypoint-replica.sh # Replica initialization script
├── pgbouncer/ # PgBouncer configuration
│ ├── pgbouncer.ini # Main PgBouncer config
│ └── userlist.txt # PgBouncer user authentication (SCRAM hashes)
├── pgbackrest/ # pgBackRest configuration and data
│ ├── conf/
│ │ └── pgbackrest.conf # pgBackRest configuration
│ ├── log/ # pgBackRest logs (mounted)
│ └── repo/ # pgBackRest backup repository (mounted)
├── pgadmin-data/ # Persisted pgAdmin data (servers, settings)
├── INSTALL.md # Detailed installation and setup guide
├── ADMIN.md # System administration and monitoring guide
└── README.md # This file
- Docker: Latest version installed (Get Docker).
- Docker Compose: V2 recommended (Install Docker Compose).
- Git (optional, for cloning).
- Operating System: Linux recommended. macOS/Windows may require adjustments (especially paths and permissions).
- Basic familiarity with the command line/terminal.
- Clone the Repository:
git clone <your-repo-url> cd postgres-ha-setup
- Create
.envFile: Copy the example and customize it with strong passwords.cp .env.example .env nano .env # Or use your preferred editor- CRITICAL: Secure the
POSTGRES_PASSWORD,REPLICATION_PASSWORD, andPGADMIN_DEFAULT_PASSWORD. - Optionally configure
PGBACKREST_REPO1_CIPHER_PASSfor encrypted backups.
- CRITICAL: Secure the
- Adjust Permissions (Linux Host): Ensure host directories are writable by the container user (often UID
999or70). Use with caution.Alternatively, switch to named volumes in# Check postgres image documentation for the correct UID if unsure # sudo chown -R 999:999 data/ pgbackrest/ pgadmin-data/ # Or more permissively (less secure): # sudo chmod -R 777 data/ pgbackrest/ pgadmin-data/
docker-compose.yamlto avoid host permission issues. - Build and Start Containers:
docker-compose up -d
- Perform Post-Start Initialization: (Run these commands after containers are up)
- Create Replication User:
docker-compose exec -T db-primary psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" <<< "CREATE USER ${REPLICATION_USER} WITH REPLICATION LOGIN PASSWORD '${REPLICATION_PASSWORD}';"
- Create PgBouncer Auth User (Use a secure internal password):
PGBOUNCER_INTERNAL_PASS='a_secure_internal_password' # Choose a strong password docker-compose exec -T db-primary psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" <<< "CREATE USER pgbouncer_auth WITH PASSWORD '${PGBOUNCER_INTERNAL_PASS}'; GRANT CONNECT ON DATABASE ${POSTGRES_DB} TO pgbouncer_auth; GRANT pg_read_all_settings TO pgbouncer_auth;"
- Generate SCRAM Hash for
userlist.txt:HASH=$(docker-compose exec -T db-primary psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -t -c "SELECT rolpassword FROM pg_shadow WHERE usename = '${POSTGRES_USER}';") echo "\"${POSTGRES_USER}\" \"${HASH}\"" > pgbouncer/userlist.txt docker-compose restart pgbouncer
- Initialize pgBackRest Stanza:
docker-compose exec db-primary pgbackrest --stanza=main --log-level-console=info stanza-create docker-compose exec pgbackrest pgbackrest --stanza=main --log-level-console=info check
- Create Replication User:
- Run Initial Backup:
docker-compose exec pgbackrest pgbackrest --stanza=main --type=full backup
For detailed setup steps, please refer to the Installation Guide (INSTALL.md).
- Environment Variables: Core credentials and settings are managed in the
.envfile. Never commit.envto version control. See.env.example. - PostgreSQL: Configuration files are located in
config/primary/andconfig/replica/. - PgBouncer: Configuration in
pgbouncer/.pgbouncer/pgbouncer.inipgbouncer/userlist.txt(Contains SCRAM hashes for users)
- pgBackRest: Configuration in
pgbackrest/conf/.
Changes to most configuration files require a reload or restart of the respective service. See the Administration Guide (ADMIN.md) for details.
- Applications: Connect via PgBouncer.
- Host:
localhost(orpgbouncerif connecting from another container on the same Docker network) - Port:
6432 - User/Password/Database: As defined in your
.envfile (POSTGRES_USER,POSTGRES_PASSWORD,POSTGRES_DB).
- Host:
- Direct Admin Access (Primary):
- Host:
localhost(ordb-primary) - Port:
5432(or usedocker-compose exec db-primary psql ...)
- Host:
- Direct Read Access (Replica):
- Host:
localhost(ordb-replica) - Port:
5432(or usedocker-compose exec db-replica psql ...)
- Host:
- Navigate to
http://localhost:8080in your web browser. - Log in using the credentials from your
.envfile (PGADMIN_DEFAULT_EMAIL,PGADMIN_DEFAULT_PASSWORD). - Add servers using the connection details above (use service names like
pgbouncer,db-primary,db-replicaas the host when configuring servers within pgAdmin).
Use docker-compose exec to run pgBackRest commands:
# Full Backup
docker-compose exec pgbackrest pgbackrest --stanza=main --type=full backup
# Incremental Backup
docker-compose exec pgbackrest pgbackrest --stanza=main --type=incr backup
# Check Backup Info
docker-compose exec pgbackrest pgbackrest --stanza=main infoBackups are stored in ./pgbackrest/repo/ on the host.
- Installation Guide (INSTALL.md): Step-by-step instructions for setting up the environment locally.
- Administration Guide (ADMIN.md): Covers monitoring, routine tasks, configuration management, user management, backup/restore, and troubleshooting.
For day-to-day monitoring, maintenance, user management, and troubleshooting, please consult the Administration Guide (ADMIN.md).
This Docker Compose setup provides the building blocks but is limited to a single host. For scaling to multiple servers, orchestration tools like Kubernetes are required, typically using components like Patroni for automated failover. See the Scaling Considerations Chapter in the Installation Guide for more details.
- Protect the
.envfile. - Use strong, unique passwords.
- Review and restrict access in
pg_hba.conffiles. - Limit exposed ports in
docker-compose.yaml. - Consider running pgAdmin behind a reverse proxy with HTTPS for production-like scenarios.
- Enable pgBackRest repository encryption for backups at rest.
See the Security section in the Administration Guide for more details.
- This setup uses Docker Compose, which is intended for single-host environments. It does not provide automatic cross-host orchestration or failover.
- Failover is manual: While a replica exists, promoting it requires manual steps described in the administration guide or external tooling (like Patroni in a Kubernetes setup).
- Host Volume Permissions: Can be tricky depending on the host OS and Docker configuration.
Contributions, issues, and feature requests are welcome. Please open an issue or submit a pull request.