diff --git a/backend/RECOVERY.md b/backend/RECOVERY.md new file mode 100644 index 00000000..f60684ea --- /dev/null +++ b/backend/RECOVERY.md @@ -0,0 +1,62 @@ +# PetChain Database Recovery Procedures + +This document outlines the steps for full restore and Point-In-Time Recovery (PITR) for the PetChain PostgreSQL database. + +## 1. Prerequisites +- Access to the backup storage (Base backups and WAL archives). +- Docker environment with `petchain_postgres` container. + +## 2. Full Restore (Latest Backup) + +Use these steps to restore the database to the state of the most recent base backup. + +1. **Stop the Application**: + ```bash + docker-compose stop + ``` + +2. **Clear Existing Data**: + ```bash + docker volume rm backend_postgres_data + ``` + +3. **Restore Base Backup**: + - Start the postgres container (it will recreate the volume). + - Extract the latest base backup into `/var/lib/postgresql/data`. + ```bash + tar -xzf /var/lib/postgresql/data/backups/base_backup_YYYYMMDD_HHMMSS.tar.gz -C /var/lib/postgresql/data + ``` + +4. **Restart Container**: + ```bash + docker-compose up -d postgres + ``` + +## 3. Point-In-Time Recovery (PITR) + +Use these steps to restore the database to a specific point in time. + +1. **Stop the Application and Clear Data** (as above). + +2. **Restore Latest Base Backup** (as above). + +3. **Create Recovery Configuration**: + - Create a `recovery.signal` file in the data directory. + - Update `postgresql.conf` or add `restore_command`: + ```ini + restore_command = 'cp /var/lib/postgresql/data/archive/%f %p' + recovery_target_time = 'YYYY-MM-DD HH:MM:SS' + ``` + +4. **Start PostgreSQL**: + PostgreSQL will read the WAL files from the archive and apply them until it reaches the target time. + +5. **Verify Data**: + Once recovery is complete, PostgreSQL will rename `recovery.signal` to `recovery.done` (or just start accepting connections). Verify the data integrity. + +## 4. Verification + +After any restore operation, run the following: +- Check PostgreSQL logs: `docker logs petchain_postgres`. +- Run application health checks. +- Verify data consistency via the Admin portal. diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index dc7eb090..bee9132e 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -13,6 +13,9 @@ services: - '5432:5432' volumes: - postgres_data:/var/lib/postgresql/data + - ./postgresql.conf:/etc/postgresql/postgresql.conf + - postgres_archive:/var/lib/postgresql/data/archive + command: postgres -c 'config_file=/etc/postgresql/postgresql.conf' networks: - petchain_network @@ -65,6 +68,7 @@ services: volumes: postgres_data: + postgres_archive: redis_data: clamav_data: diff --git a/backend/postgresql.conf b/backend/postgresql.conf new file mode 100644 index 00000000..cf774cee --- /dev/null +++ b/backend/postgresql.conf @@ -0,0 +1,6 @@ +# Enable WAL archiving for PITR +wal_level = replica +archive_mode = on +archive_command = 'test ! -f /var/lib/postgresql/data/archive/%f && cp %p /var/lib/postgresql/data/archive/%f' +max_wal_senders = 10 +archive_timeout = 60 diff --git a/backend/scripts/backup.sh b/backend/scripts/backup.sh new file mode 100644 index 00000000..9c541312 --- /dev/null +++ b/backend/scripts/backup.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Database Backup Script for PetChain + +# Configuration +BACKUP_DIR="/var/lib/postgresql/data/backups" +ARCHIVE_DIR="/var/lib/postgresql/data/archive" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_NAME="base_backup_${TIMESTAMP}" +RETENTION_DAYS=7 + +# Ensure backup directory exists +mkdir -p ${BACKUP_DIR} + +echo "Starting base backup: ${BACKUP_NAME}..." + +# Perform base backup +pg_basebackup -D ${BACKUP_DIR}/${BACKUP_NAME} -Ft -z -X fetch -P + +if [ $? -eq 0 ]; then + echo "Base backup successful: ${BACKUP_NAME}" + + # Calculate checksum for integrity verification + sha256sum ${BACKUP_DIR}/${BACKUP_NAME}.tar.gz > ${BACKUP_DIR}/${BACKUP_NAME}.sha256 + + # Cleanup old backups + find ${BACKUP_DIR} -name "base_backup_*" -mtime +${RETENTION_DAYS} -delete + + # In production, sync to S3: + # aws s3 sync ${BACKUP_DIR} s3://petchain-backups/ + # aws s3 sync ${ARCHIVE_DIR} s3://petchain-wal-archive/ +else + echo "Base backup failed!" + exit 1 +fi + +echo "Backup process complete." diff --git a/backend/scripts/verify-backup.sh b/backend/scripts/verify-backup.sh new file mode 100644 index 00000000..ce0624d3 --- /dev/null +++ b/backend/scripts/verify-backup.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Backup Integrity Verification Script + +BACKUP_DIR="/var/lib/postgresql/data/backups" + +echo "Verifying latest backups..." + +# Find the most recent backup +LATEST_BACKUP=$(ls -t ${BACKUP_DIR}/base_backup_*.tar.gz | head -n 1) + +if [ -z "$LATEST_BACKUP" ]; then + echo "No backups found to verify." + exit 1 +fi + +CHECKsum_FILE="${LATEST_BACKUP%.tar.gz}.sha256" + +if [ ! -f "$CHECKsum_FILE" ]; then + echo "Checksum file missing for ${LATEST_BACKUP}" + exit 1 +fi + +# Verify checksum +sha256sum -c "$CHECKsum_FILE" + +if [ $? -eq 0 ]; then + echo "Integrity verification successful for ${LATEST_BACKUP}" +else + echo "Integrity verification FAILED for ${LATEST_BACKUP}!" + exit 1 +fi