PostgreSQL Agent
Standalone backup agent for PostgreSQL databases. Supports logical dumps, base backups, and continuous WAL archiving for point-in-time recovery.
Features
- PostgreSQL 12, 13, 14, 15, 16+ support
- Logical backups (pg_dump) and physical backups (pg_basebackup)
- Continuous WAL archiving for point-in-time recovery
- Custom and directory format support
- Parallel dump and restore
- Schema-only and data-only backup options
- Automatic source identifier for backup tracking
Quick Start
Docker Compose
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_USER: myapp
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: myapp
volumes:
- pg_data:/var/lib/postgresql/data
lox-pg-agent:
image: loxbackup/postgresql-agent:latest
environment:
LOX_API_KEY: ${LOX_API_KEY}
PGHOST: postgres
PGPORT: 5432
PGUSER: myapp
PGPASSWORD: ${POSTGRES_PASSWORD}
PGDATABASE: myapp
BACKUP_SCHEDULE: "0 3 * * *"
BACKUP_NAME: "myapp-postgres"
depends_on:
- postgres
volumes:
pg_data:Standalone Binary
# Download the agent curl -L https://releases.backlox.com/postgresql-agent/latest/linux-amd64 -o lox-pg-agent chmod +x lox-pg-agent # Configure export LOX_API_KEY="lox_xxxxxxxxxxxx" export PGHOST="localhost" export PGUSER="backup_user" export PGPASSWORD="secure_password" export PGDATABASE="myapp" # Run a backup ./lox-pg-agent backup # Or run as daemon with schedule ./lox-pg-agent daemon --schedule "0 3 * * *"
Environment Variables
Connection Settings
| Variable | Default | Description |
|---|---|---|
| PGHOST | localhost | PostgreSQL server hostname |
| PGPORT | 5432 | PostgreSQL server port |
| PGUSER | postgres | PostgreSQL username |
| PGPASSWORD | - | PostgreSQL password (required) |
| PGDATABASE | all | Specific database or "all" for all databases |
| PGSSLMODE | prefer | SSL mode: disable, allow, prefer, require, verify-ca, verify-full |
Backup Settings
| Variable | Default | Description |
|---|---|---|
| LOX_API_KEY | - | LOX API key (required) |
| BACKUP_NAME | postgres-backup | Backup name prefix |
| BACKUP_SCHEDULE | 0 3 * * * | Cron schedule expression |
| BACKUP_RETENTION | 30 | Days to retain backups |
| BACKUP_TYPE | logical | Backup type: logical or physical |
| BACKUP_FORMAT | custom | Format: custom, directory, plain, tar |
| SOURCE_IDENTIFIER | auto | Custom source ID (auto-generated if not set) |
Source Identifier
The agent automatically generates a unique source_identifier for each database instance (format: postgresql-hostname-database-hash). This enables tracking backups across multiple servers and identifying their origin in the dashboard.
Advanced Options
| Variable | Default | Description |
|---|---|---|
| COMPRESSION | gzip | Compression: gzip, zstd, lz4, or none |
| PARALLEL_JOBS | 4 | Number of parallel dump/restore jobs |
| SCHEMA_ONLY | false | Dump schema only (no data) |
| DATA_ONLY | false | Dump data only (no schema) |
| EXCLUDE_SCHEMAS | - | Comma-separated schemas to exclude |
| EXCLUDE_TABLES | - | Comma-separated tables to exclude |
| INCLUDE_BLOBS | true | Include large objects in dump |
| PG_DUMP_EXTRA_ARGS | - | Additional pg_dump arguments |
Database User Setup
Create a dedicated backup user with minimum required privileges:
-- For logical backups (pg_dump) CREATE ROLE lox_backup WITH LOGIN PASSWORD 'secure_password'; GRANT CONNECT ON DATABASE myapp TO lox_backup; GRANT USAGE ON SCHEMA public TO lox_backup; GRANT SELECT ON ALL TABLES IN SCHEMA public TO lox_backup; GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO lox_backup; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO lox_backup; -- For backing up all databases ALTER ROLE lox_backup WITH SUPERUSER; -- Or use pg_read_all_data role in PG14+ -- PostgreSQL 14+ alternative (more secure) GRANT pg_read_all_data TO lox_backup; -- For physical backups (pg_basebackup) ALTER ROLE lox_backup WITH REPLICATION;
pg_hba.conf Configuration
Ensure the backup user can connect from the agent container:
# TYPE DATABASE USER ADDRESS METHOD host all lox_backup 172.0.0.0/8 scram-sha-256 host replication lox_backup 172.0.0.0/8 scram-sha-256
Backup Types
Logical Backup (Default)
Uses pg_dump or pg_dumpall to create logical dumps.
| Format | Description | Use Case |
|---|---|---|
| custom | Compressed, flexible restore | Recommended for most cases |
| directory | Parallel dump, per-table files | Large databases, parallel restore |
| plain | Plain SQL text | Simple restore, readability |
| tar | Tar archive format | Compatibility with older tools |
Physical Backup
Uses pg_basebackup for hot physical backups. Best for large databases requiring fast recovery.
lox-pg-agent:
image: loxbackup/postgresql-agent:latest
environment:
LOX_API_KEY: ${LOX_API_KEY}
PGHOST: postgres
PGPASSWORD: ${POSTGRES_PASSWORD}
BACKUP_TYPE: physical
BACKUP_SCHEDULE: "0 2 * * *"Point-in-Time Recovery (PITR)
Enable WAL archiving for continuous backup and point-in-time recovery:
lox-pg-agent:
image: loxbackup/postgresql-agent:latest
environment:
LOX_API_KEY: ${LOX_API_KEY}
PGHOST: postgres
PGPASSWORD: ${POSTGRES_PASSWORD}
BACKUP_TYPE: physical
# Enable WAL archiving
WAL_ARCHIVING: "true"
WAL_ARCHIVE_SCHEDULE: "*/5 * * * *" # Every 5 minutes
# Full backup weekly
BACKUP_SCHEDULE: "0 3 * * 0"PostgreSQL Server Configuration
Enable WAL archiving in your postgresql.conf:
wal_level = replica archive_mode = on archive_command = 'test ! -f /archive/%f && cp %p /archive/%f' max_wal_senders = 3
Examples
Single Database with Parallel Dump
lox-pg-agent:
image: loxbackup/postgresql-agent:latest
environment:
LOX_API_KEY: ${LOX_API_KEY}
PGHOST: postgres
PGPASSWORD: ${POSTGRES_PASSWORD}
PGDATABASE: myapp
BACKUP_FORMAT: directory
PARALLEL_JOBS: 8 # Use 8 parallel workers
BACKUP_NAME: "myapp-parallel"
BACKUP_SCHEDULE: "0 */4 * * *"Exclude Large Tables
lox-pg-agent:
image: loxbackup/postgresql-agent:latest
environment:
LOX_API_KEY: ${LOX_API_KEY}
PGHOST: postgres
PGPASSWORD: ${POSTGRES_PASSWORD}
PGDATABASE: analytics
# Skip large audit/log tables
EXCLUDE_TABLES: "public.audit_log,public.events,public.metrics_raw"
BACKUP_NAME: "analytics-db"Schema-Only Backup
lox-pg-agent:
image: loxbackup/postgresql-agent:latest
environment:
LOX_API_KEY: ${LOX_API_KEY}
PGHOST: postgres
PGPASSWORD: ${POSTGRES_PASSWORD}
PGDATABASE: myapp
SCHEMA_ONLY: "true"
BACKUP_NAME: "myapp-schema"
BACKUP_SCHEDULE: "0 0 * * *" # Daily at midnightAmazon RDS / Aurora PostgreSQL
lox-pg-agent:
image: loxbackup/postgresql-agent:latest
environment:
LOX_API_KEY: ${LOX_API_KEY}
PGHOST: mydb.xxxx.us-east-1.rds.amazonaws.com
PGPORT: 5432
PGUSER: postgres
PGPASSWORD: ${RDS_PASSWORD}
PGDATABASE: myapp
PGSSLMODE: require
# RDS doesn't allow physical backups
BACKUP_TYPE: logical
BACKUP_FORMAT: custom
BACKUP_NAME: "rds-postgres-prod"All Databases Backup
lox-pg-agent:
image: loxbackup/postgresql-agent:latest
environment:
LOX_API_KEY: ${LOX_API_KEY}
PGHOST: postgres
PGUSER: postgres
PGPASSWORD: ${POSTGRES_PASSWORD}
PGDATABASE: all # Backup all databases
BACKUP_NAME: "postgres-cluster"
BACKUP_SCHEDULE: "0 3 * * *"Restoring Backups
Restore from Custom Format
# Download the backup lox backup download <backup-id> -o backup.dump # Restore to PostgreSQL pg_restore -h localhost -U postgres -d myapp backup.dump # Restore with parallel jobs pg_restore -h localhost -U postgres -d myapp -j 4 backup.dump # Restore specific tables only pg_restore -h localhost -U postgres -d myapp -t users -t orders backup.dump
Restore from Plain Format
# Download the backup lox backup download <backup-id> -o backup.sql.gz # Decompress and restore gunzip backup.sql.gz psql -h localhost -U postgres -d myapp < backup.sql
Point-in-Time Recovery
# 1. Stop PostgreSQL sudo systemctl stop postgresql # 2. Clear data directory rm -rf /var/lib/postgresql/16/main/* # 3. Download and extract base backup lox backup download <base-backup-id> -o base.tar.gz tar -xzf base.tar.gz -C /var/lib/postgresql/16/main/ # 4. Download WAL archives lox backup download <wal-backup-id> -o wal.tar.gz tar -xzf wal.tar.gz -C /var/lib/postgresql/16/main/pg_wal/ # 5. Create recovery signal with target time cat > /var/lib/postgresql/16/main/recovery.signal << EOF EOF # 6. Configure recovery target in postgresql.conf echo "recovery_target_time = '2024-01-15 14:30:00'" >> postgresql.conf echo "restore_command = 'cp /path/to/wal/%f %p'" >> postgresql.conf # 7. Start PostgreSQL sudo systemctl start postgresql
Monitoring
The agent exposes Prometheus metrics and health endpoints:
| Endpoint | Description |
|---|---|
| /health | Liveness check |
| /ready | Readiness check (DB connected) |
| /metrics | Prometheus metrics |
Key Metrics
# Backup metrics
lox_pg_backup_total{status="success"}
lox_pg_backup_total{status="failed"}
lox_pg_backup_duration_seconds
lox_pg_backup_size_bytes
lox_pg_last_backup_timestamp
# WAL metrics
lox_pg_wal_archived_total
lox_pg_wal_archive_lag_bytes
# Database metrics
lox_pg_database_size_bytes{database="myapp"}
lox_pg_tables_count{database="myapp"}Troubleshooting
FATAL: password authentication failed
Verify password is correct and pg_hba.conf allows the connection. Check PGSSLMODE matches server configuration.
pg_dump: permission denied
The backup user needs SELECT permission on all tables. Use pg_read_all_data role in PostgreSQL 14+ or grant SUPERUSER for earlier versions.
pg_basebackup: could not connect
Physical backups require REPLICATION privilege and a replication entry in pg_hba.conf. Ensure max_wal_senders is set high enough.
Debug mode
Set LOG_LEVEL: debug to see detailed pg_dump commands and output.