From 6290136327caaf703556b68d2f0a3081e4a642e1 Mon Sep 17 00:00:00 2001 From: xmrcheckout Date: Fri, 9 Jan 2026 14:40:31 +0000 Subject: [PATCH] Add optional Postgres backup service --- .env.example | 3 +++ .gitignore | 2 ++ README.md | 13 +++++++++++++ docker-compose.yml | 16 ++++++++++++++++ docker/pg_backup/Dockerfile | 12 ++++++++++++ docker/pg_backup/backup.sh | 21 +++++++++++++++++++++ docker/pg_backup/pg_backup.cron | 1 + 7 files changed, 68 insertions(+) create mode 100644 docker/pg_backup/Dockerfile create mode 100644 docker/pg_backup/backup.sh create mode 100644 docker/pg_backup/pg_backup.cron diff --git a/.env.example b/.env.example index 877899b..f8f0120 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,9 @@ POSTGRES_PASSWORD=xmrcheckout POSTGRES_DB=xmrcheckout DATABASE_URL=postgresql://xmrcheckout:xmrcheckout@db:5432/xmrcheckout +# Optional: Postgres backups (used by the `db-backup` Compose profile) +BACKUP_RETENTION_DAYS=7 + # API authentication API_KEYS=dev-key-1 API_KEY_ENCRYPTION_KEY=replace-with-fernet-key diff --git a/.gitignore b/.gitignore index 652deab..c742db9 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ ui/node_modules/ *.py[cod] nginx/certs/ + +backups/ diff --git a/README.md b/README.md index 5861319..f359e06 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,19 @@ If you’re running the bundled `monerod` service: docker compose --profile local-daemon up --build -d ``` +### Optional: Postgres backups (disabled by default) + +This repository includes an optional `db-backup` service that runs `pg_dump` hourly and writes backups to `./backups/postgres` on the host. + +Enable it by starting Compose with the `db-backup` profile: + +``` +docker compose --profile db-backup up --build -d +``` + +Retention defaults to 7 days. To override: +- Set `BACKUP_RETENTION_DAYS` in `.env` + ### Optional: donations (disabled by default) Donation endpoints and UI are off by default for self-hosted deployments. diff --git a/docker-compose.yml b/docker-compose.yml index 0bcc452..ec07497 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -216,6 +216,22 @@ services: interval: 5s timeout: 3s retries: 10 + db-backup: + build: + context: ./docker/pg_backup + environment: + POSTGRES_HOST: db + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7} + volumes: + - ./backups/postgres:/backups + depends_on: + db: + condition: service_healthy + restart: on-failure + profiles: ["db-backup"] volumes: postgres_data: monerod_data: diff --git a/docker/pg_backup/Dockerfile b/docker/pg_backup/Dockerfile new file mode 100644 index 0000000..b011fb1 --- /dev/null +++ b/docker/pg_backup/Dockerfile @@ -0,0 +1,12 @@ +FROM postgres:16-alpine + +RUN apk add --no-cache bash + +COPY backup.sh /usr/local/bin/backup.sh +COPY pg_backup.cron /etc/cron.d/pg_backup + +RUN chmod +x /usr/local/bin/backup.sh \ + && chmod 0644 /etc/cron.d/pg_backup \ + && crontab /etc/cron.d/pg_backup + +CMD ["crond", "-f", "-l", "8"] diff --git a/docker/pg_backup/backup.sh b/docker/pg_backup/backup.sh new file mode 100644 index 0000000..84222e9 --- /dev/null +++ b/docker/pg_backup/backup.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${POSTGRES_HOST:?}" +: "${POSTGRES_USER:?}" +: "${POSTGRES_PASSWORD:?}" +: "${POSTGRES_DB:?}" + +backup_retention_days="${BACKUP_RETENTION_DAYS:-7}" + +export PGPASSWORD="$POSTGRES_PASSWORD" + +backup_dir="/backups" +timestamp="$(date +%Y%m%d_%H%M%S)" +backup_path="${backup_dir}/${POSTGRES_DB}_${timestamp}.dump" + +mkdir -p "$backup_dir" + +pg_dump -h "$POSTGRES_HOST" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -F c -f "$backup_path" + +find "$backup_dir" -type f -name "*.dump" -mtime "+${backup_retention_days}" -delete diff --git a/docker/pg_backup/pg_backup.cron b/docker/pg_backup/pg_backup.cron new file mode 100644 index 0000000..2e88156 --- /dev/null +++ b/docker/pg_backup/pg_backup.cron @@ -0,0 +1 @@ +0 * * * * /usr/local/bin/backup.sh >> /var/log/pg_backup.log 2>&1