When running containerized services on a homelab server, many call for a Postgres database in the cluster. These are the defaults I’m using for configuring the database, health checks, backups to NAS, and a restore script.

Docker Compose Configuration

In docker-compose.yml:

services:
  db:
    image: postgres:17-alpine
    restart: unless-stopped
    shm_size: 256mb
    healthcheck:
      test: ['CMD', 'pg_isready', '-U', "${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - ${POSTGRES_DATA_DIR}:/var/lib/postgresql/data
      - ${BACKUP_PATH}:/backups
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

This defines a db service using the latest version of Postgres, including volume mounts for data persistence and backups.

Environment File

In .env:

# PostgreSQL Variables
POSTGRES_DB=mydatabase
POSTGRES_USER=myuser
POSTGRES_PASSWORD=mypassword

# SSD mount for working postgresql data
POSTGRES_DATA_DIR=/path/to/postgres/data/dir

# NAS mount for persisted backups
BACKUP_PATH=/mnt/nas/PostgreSQLBackups

The .env file is automatically loaded by docker-compose.

Backup Script

In backup.sh:

#!/bin/bash

# Load environment variables
source .env

# Format for the backup filename
BACKUP_DATE=$(date +%F)
BACKUP_FILENAME="/backups/${POSTGRES_DB}_${BACKUP_DATE}.dump"

# Perform the backup
docker-compose exec db pg_dump -U ${POSTGRES_USER} ${POSTGRES_DB} > ${BACKUP_FILENAME}

# Optional: Clean up old backups
# find /backups/* -mtime +30 -exec rm {} \;

Make the script executable: chmod +x backup.sh.

Cron Schedule for Backup

Add to crontab (crontab -e) to run the backup at 3 a.m. daily:

0 3 * * * /path/to/backup.sh

Restore Script

For restoring a database, use restore.sh:

#!/bin/bash

# Load environment variables
source .env

# Ensure there's a filename argument
if [ "$#" -ne 1 ]; then
  echo "Usage: $0 <backup_filename>"
  exit 1
fi

BACKUP_FILENAME=$1

# Check the backup file exists
if [ ! -f "$BACKUP_PATH/$BACKUP_FILENAME" ]; then
  echo "Backup file not found: $BACKUP_PATH/$BACKUP_FILENAME"
  exit 1
fi

# Restore the database
cat $BACKUP_PATH/$BACKUP_FILENAME | docker-compose exec db psql -U $POSTGRES_USER -d $POSTGRES_DB

echo "Database restored from $BACKUP_FILENAME"

Make the script executable: chmod +x restore.sh.

Run a restore like this:

./restore.sh mydatabase_YYYY-MM-DD.dump