Use this pattern for local development, staging, or controlled lab environments. Updated for PostgreSQL 18 with current Docker best practices.
sudo mkdir -p /opt/postgres
cd /opt/postgres
Create a secure environment file instead of hardcoding passwords:
# Create .env file
cat > .env << EOF
POSTGRES_DB=appdb
POSTGRES_USER=appuser
POSTGRES_PASSWORD=your_secure_password_here
PGDATA=/var/lib/postgresql/data/pgdata
EOF
# Secure the .env file
chmod 600 .env
compose.yamlservices:
postgres:
image: postgres:18
restart: unless-stopped
container_name: postgres-db
ports:
- "5432:5432"
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- ./data:/var/lib/postgresql/data
- ./custom.conf:/etc/postgresql/postgresql.conf
command: postgres -c config_file=/etc/postgresql/postgresql.conf
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- postgres-network
networks:
postgres-network:
driver: bridge
volumes:
postgres-data:
Create a custom configuration file for production use:
mkdir -p /opt/postgres
cat > /opt/postgres/custom.conf << EOF
# Connection settings
listen_addresses = '*'
max_connections = 100
# Memory settings (adjust based on container resources)
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 4MB
maintenance_work_mem = 64MB
# Logging
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = 1d
log_rotation_size = 100MB
log_min_duration_statement = 1000
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
# Checkpoints
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
# Replication (if needed)
max_wal_senders = 3
max_replication_slots = 3
hot_standby = on
EOF
# Pull the latest image
docker compose pull
# Start the service
docker compose up -d
# Check service status
docker compose ps
# View logs
docker compose logs -f postgres
Monitor container health:
# Check container health status
docker ps
# Check PostgreSQL connectivity
docker exec postgres-db pg_isready
# View health check logs
docker inspect postgres-db | grep -A 10 Health
# For production, don't expose port 5432 publicly
# Use Docker networks for application connectivity
docker network create postgres-app-net
# Use Docker secrets for sensitive data (alternative to env file)
# Create a secret file
echo "your_secure_password" | docker secret create postgres_password -
# Backup database
docker exec postgres-db pg_dump -U appuser -d appdb > backup.sql
# Restore database
docker exec -i postgres-db psql -U appuser -d appdb < backup.sql
# Or use volume backup
docker run --rm -v /opt/postgres/data:/data -v $(pwd):/backup alpine tar czf /backup/data-backup.tar.gz -C /data .
# Stop current container
docker compose down
# Pull new image
docker compose pull
# Start with new image
docker compose up -d