A containerized PostgreSQL backup service that automatically creates database backups with configurable retention policies and optional S3/R2 cloud storage sync.
- 🔄 Automated Backups: Configurable backup intervals (default: 24 hours)
- 🗂️ Retention Policies: Automatic cleanup of old backups (local and cloud)
- ☁️ Cloud Storage: Support for AWS S3 and Cloudflare R2
- 🐳 Container Ready: Works with Docker Compose and Kamal accessories
- 📊 Health Checks: Built-in health monitoring
- 🔒 Secure: Uses environment variables for credentials
- Create a
.env
file with your database credentials:
POSTGRES_USER=myuser
POSTGRES_PASSWORD=mypassword
POSTGRES_DB=mydatabase
# Optional: S3/R2 configuration
S3_BUCKET=my-backup-bucket
S3_PREFIX=db-backups
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_DEFAULT_REGION=us-east-1
# For Cloudflare R2, also set:
AWS_ENDPOINT_URL=https://your-account-id.r2.cloudflarestorage.com
- Use the provided
compose.yml
:
docker compose up -d
Add to your config/deploy.yml
:
accessories:
postgres-backup:
image: ghcr.io/servicestack/backup-postgres:latest
host: your-server
env:
clear:
POSTGRES_HOST: postgres
BACKUP_INTERVAL: "86400" # 24 hours
RETENTION_DAYS: "7"
S3_BUCKET: "your-backup-bucket"
S3_PREFIX: "db-backups"
S3_RETENTION_DAYS: "30"
secret:
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_DB
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_DEFAULT_REGION
- AWS_ENDPOINT_URL # For R2
volumes:
- "/opt/backups:/backups"
depends_on:
- postgres
Variable | Required | Default | Description |
---|---|---|---|
POSTGRES_HOST |
✅ | - | PostgreSQL server hostname |
POSTGRES_USER |
✅ | - | Database username |
POSTGRES_PASSWORD |
✅ | - | Database password |
POSTGRES_DB |
✅ | - | Database name |
BACKUP_INTERVAL |
❌ | 86400 |
Backup interval in seconds |
RETENTION_DAYS |
❌ | 7 |
Local backup retention in days |
S3_BUCKET |
❌ | - | S3/R2 bucket name |
S3_PREFIX |
❌ | db-backups |
S3/R2 prefix/folder |
S3_RETENTION_DAYS |
❌ | - | Cloud backup retention in days |
AWS_ACCESS_KEY_ID |
❌ | - | AWS/R2 access key |
AWS_SECRET_ACCESS_KEY |
❌ | - | AWS/R2 secret key |
AWS_DEFAULT_REGION |
❌ | - | AWS region |
AWS_ENDPOINT_URL |
❌ | - | Custom endpoint (for R2) |
- Default: Every 24 hours (
BACKUP_INTERVAL=86400
) - Custom: Set
BACKUP_INTERVAL
to any value in seconds - Examples:
- Every 6 hours:
BACKUP_INTERVAL=21600
- Every 12 hours:
BACKUP_INTERVAL=43200
- Every hour:
BACKUP_INTERVAL=3600
- Every 6 hours:
- Local: Controlled by
RETENTION_DAYS
(default: 7 days) - Cloud: Controlled by
S3_RETENTION_DAYS
(optional) - Cleanup runs after each backup
Set only the PostgreSQL connection variables. Backups will be stored locally with the configured retention policy.
S3_BUCKET=my-backup-bucket
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_DEFAULT_REGION=us-east-1
S3_BUCKET=my-backup-bucket
AWS_ACCESS_KEY_ID=your-r2-access-key
AWS_SECRET_ACCESS_KEY=your-r2-secret-key
AWS_ENDPOINT_URL=https://your-account-id.r2.cloudflarestorage.com
Use the development compose file:
docker compose -f compose.dev.yml up -d
This builds the image locally instead of pulling from the registry.
docker build -t backup-postgres .
The container includes health checks that verify the backup service is running:
docker ps # Check health status
docker logs postgres_backup # View logs
The service provides detailed logging with timestamps:
docker compose logs -f postgres_backup
- Connection Failed: Verify PostgreSQL credentials and network connectivity
- S3 Upload Failed: Check AWS credentials and bucket permissions
- Permission Denied: Ensure backup volume has proper write permissions
Add verbose logging by checking container logs:
docker compose logs postgres_backup
MIT License - see LICENSE file for details.