===============================
Backup & Restore Procedures
===============================
.. danger::
**CRITICAL**: Regularly backup your data! Hardware failures and data corruption can happen without warning.
This guide provides comprehensive backup and restore procedures for LUStores, including automated and manual methods.
Overview
========
LUStores stores critical data in several locations that must be backed up regularly to ensure business continuity.
Critical Data Locations
=======================
.. list-table:: Backup Priority Matrix
:header-rows: 1
:widths: 25 20 20 35
* - Component
- Priority
- Backup Frequency
- Location
* - PostgreSQL Database
- **CRITICAL**
- Daily (automated)
- ``/db`` on host
* - Environment Config (.env.prod)
- **CRITICAL**
- After any change
- Project root
* - SSL Certificates
- HIGH
- Weekly
- ``./certbot/conf``
* - Nginx Configuration
- MEDIUM
- After changes
- ``./nginx/``
* - Redis Data
- LOW
- Optional (transient)
- ``redis_data`` volume
* - Application Logs
- LOW
- Optional (archival)
- ``./logs/``
Backup Architecture
===================
.. mermaid::
graph TB
subgraph "Source Data (VM Host)"
DB[("/db
PostgreSQL Data
CRITICAL")]
ENV[(".env.prod
Secrets & Config
CRITICAL")]
SSL[("./certbot/conf
SSL Certificates
HIGH")]
NGINX[("./nginx/
Web Config
MEDIUM")]
REDIS[("redis_data
Cache/Sessions
LOW")]
end
subgraph "Backup Methods"
AUTO["Automated Daily Backup
(via Interface)"]
MANUAL["Manual Backup
(Command Line)"]
DOCKER["Docker Volume Backup
(Full System)"]
end
subgraph "Backup Storage"
LOCAL["Local Backup Dir
./backups/"]
REMOTE["Remote Storage
(Recommended)"]
CLOUD["Cloud Storage
(S3, Azure, etc.)"]
end
DB --> AUTO
DB --> MANUAL
DB --> DOCKER
ENV --> MANUAL
SSL --> MANUAL
NGINX --> MANUAL
REDIS --> DOCKER
AUTO --> LOCAL
MANUAL --> LOCAL
DOCKER --> LOCAL
LOCAL -.->|Copy| REMOTE
LOCAL -.->|Upload| CLOUD
style DB fill:#ff6b6b
style ENV fill:#ff6b6b
style SSL fill:#ffd93d
style AUTO fill:#6bcf7f
style REMOTE fill:#4d96ff
style CLOUD fill:#4d96ff
Backup Methods
==============
Method 1: Automated Backup via Interface (Recommended)
-------------------------------------------------------
The LUStores interface provides an automated backup feature for non-technical users.
**Steps:**
1. Log in as an admin user
2. Navigate to **Admin** → **System Management**
3. Click **"Create Backup"** button
4. Wait for confirmation (typically 30-60 seconds)
5. Download the backup file when prompted
**What's Included:**
- ✅ Complete PostgreSQL database dump
- ✅ Timestamp and metadata
- ✅ Compressed format (.sql.gz)
**What's NOT Included:**
- ❌ Environment configuration (.env.prod)
- ❌ SSL certificates
- ❌ Nginx configuration
.. note::
Automated backups are stored in ``./backups/`` directory on the host and are retained for 30 days.
Method 2: Manual Database Backup (Command Line)
------------------------------------------------
For administrators with SSH access to the VM.
Quick Backup
~~~~~~~~~~~~
::
# Navigate to project directory
cd /data/LUStores
# Create backup with timestamp
docker compose -f docker-compose.prod.yml exec -T db \
pg_dump -U postgres university_inventory \
| gzip > "backups/backup_$(date +%Y%m%d_%H%M%S).sql.gz"
# Verify backup was created
ls -lh backups/
Comprehensive Backup (Database + Config)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
# Create backup directory with timestamp
BACKUP_DIR="backups/full_backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# 1. Backup PostgreSQL database
echo "Backing up database..."
docker compose -f docker-compose.prod.yml exec -T db \
pg_dump -U postgres -F c university_inventory \
> "$BACKUP_DIR/database.dump"
# 2. Backup environment configuration
echo "Backing up configuration..."
cp .env.prod "$BACKUP_DIR/env.prod.backup"
# 3. Backup SSL certificates
echo "Backing up SSL certificates..."
tar -czf "$BACKUP_DIR/ssl_certificates.tar.gz" certbot/conf/
# 4. Backup nginx configuration
echo "Backing up nginx config..."
tar -czf "$BACKUP_DIR/nginx_config.tar.gz" nginx/
# 5. Create backup manifest
cat > "$BACKUP_DIR/MANIFEST.txt" << EOF
LUStores Backup Manifest
========================
Backup Date: $(date)
Hostname: $(hostname)
Database Size: $(du -sh $BACKUP_DIR/database.dump | cut -f1)
Contents:
- database.dump (PostgreSQL custom format)
- env.prod.backup (environment configuration)
- ssl_certificates.tar.gz (Let's Encrypt certs)
- nginx_config.tar.gz (web server config)
EOF
# 6. Compress entire backup
echo "Compressing backup..."
tar -czf "${BACKUP_DIR}.tar.gz" -C backups "$(basename $BACKUP_DIR)"
# 7. Clean up uncompressed directory
rm -rf "$BACKUP_DIR"
echo "✅ Backup completed: ${BACKUP_DIR}.tar.gz"
ls -lh "${BACKUP_DIR}.tar.gz"
Method 3: Docker Volume Backup (Full System)
---------------------------------------------
Backs up all Docker volumes including Redis data.
::
# Stop services (downtime required)
docker compose -f docker-compose.prod.yml stop
# Backup all volumes
docker run --rm \
-v /db:/source/db:ro \
-v lustores_redis_data:/source/redis:ro \
-v $(pwd)/backups:/backup \
alpine tar czf /backup/volumes_$(date +%Y%m%d_%H%M%S).tar.gz \
-C /source .
# Restart services
docker compose -f docker-compose.prod.yml start
echo "✅ Volume backup completed"
.. warning::
This method requires stopping services and causes downtime. Use Method 2 for zero-downtime backups.
Automated Backup Script
========================
Create a daily automated backup script.
Create Backup Script
--------------------
::
# Create script
cat > /usr/local/bin/lustores-backup.sh << 'EOF'
#!/bin/bash
set -e
# Configuration
PROJECT_DIR="/data/LUStores"
BACKUP_DIR="$PROJECT_DIR/backups"
RETENTION_DAYS=30
LOG_FILE="$PROJECT_DIR/logs/backup.log"
# Ensure backup directory exists
mkdir -p "$BACKUP_DIR"
mkdir -p "$(dirname $LOG_FILE)"
# Log function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
log "Starting automated backup..."
# Create timestamped backup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/auto_backup_$TIMESTAMP.sql.gz"
# Perform backup
cd "$PROJECT_DIR"
docker compose -f docker-compose.prod.yml exec -T db \
pg_dump -U postgres university_inventory \
| gzip > "$BACKUP_FILE"
# Verify backup
if [ -f "$BACKUP_FILE" ]; then
SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
log "✅ Backup successful: $BACKUP_FILE ($SIZE)"
else
log "❌ Backup failed!"
exit 1
fi
# Clean up old backups (keep last 30 days)
log "Cleaning up backups older than $RETENTION_DAYS days..."
find "$BACKUP_DIR" -name "auto_backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete
log "Backup process completed successfully"
EOF
# Make executable
chmod +x /usr/local/bin/lustores-backup.sh
Setup Automated Daily Backup (Cron)
------------------------------------
::
# Add to crontab (runs daily at 2 AM)
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/lustores-backup.sh") | crontab -
# Verify cron job
crontab -l
Off-Site Backup (Recommended)
==============================
Always store backups in a separate location from the production server.
Option 1: Remote Server via SCP
--------------------------------
::
# Copy backup to remote server
BACKUP_FILE="backups/backup_$(date +%Y%m%d_%H%M%S).sql.gz"
REMOTE_SERVER="backup.university.edu"
REMOTE_PATH="/backups/lustores/"
scp "$BACKUP_FILE" "admin@$REMOTE_SERVER:$REMOTE_PATH"
Option 2: Cloud Storage (AWS S3 Example)
-----------------------------------------
::
# Install AWS CLI (if not already installed)
sudo apt-get install awscli
# Configure AWS credentials
aws configure
# Upload to S3
BACKUP_FILE="backups/backup_$(date +%Y%m%d_%H%M%S).sql.gz"
S3_BUCKET="s3://university-lustores-backups"
aws s3 cp "$BACKUP_FILE" "$S3_BUCKET/$(basename $BACKUP_FILE)"
Option 3: Network Attached Storage (NAS)
-----------------------------------------
::
# Mount NAS (one-time setup)
sudo apt-get install cifs-utils
sudo mkdir -p /mnt/nas-backup
# Add to /etc/fstab
# //nas.university.edu/backups /mnt/nas-backup cifs credentials=/root/.nascreds 0 0
# Mount
sudo mount /mnt/nas-backup
# Copy backups
cp backups/*.sql.gz /mnt/nas-backup/lustores/
Restore Procedures
==================
Restore Scenario 1: Database Only
----------------------------------
**Use Case**: Data corruption, accidental deletion, need to roll back to previous state.
**Downtime**: Minimal (2-5 minutes)
Steps::
cd /data/LUStores
# 1. Stop the application (keeps database running)
docker compose -f docker-compose.prod.yml stop app
# 2. Restore from compressed backup
gunzip -c backups/backup_20250122_020000.sql.gz | \
docker compose -f docker-compose.prod.yml exec -T db \
psql -U postgres -d university_inventory
# OR restore from custom format backup
docker compose -f docker-compose.prod.yml exec -T db \
pg_restore -U postgres -d university_inventory -c < backups/database.dump
# 3. Restart application
docker compose -f docker-compose.prod.yml start app
# 4. Verify
docker compose -f docker-compose.prod.yml logs -f app
Restore Scenario 2: Complete System Failure
--------------------------------------------
**Use Case**: VM crash, disk failure, complete data loss.
**Downtime**: 15-30 minutes
.. mermaid::
graph TB
START([System Failure])
PREP[1. Prepare New VM
Install Docker & Docker Compose]
CLONE[2. Clone Repository
git clone repo]
RESTORE_CONFIG[3. Restore .env.prod
from backup]
RESTORE_DB[4. Restore Database
Extract to /db]
RESTORE_SSL[5. Restore SSL Certs
Extract to ./certbot/conf]
RESTORE_NGINX[6. Restore nginx Config
Extract to ./nginx]
START_SERVICES[7. Start Services
docker compose up -d]
VERIFY[8. Verify System
Check logs & health]
DONE([System Restored])
START --> PREP
PREP --> CLONE
CLONE --> RESTORE_CONFIG
RESTORE_CONFIG --> RESTORE_DB
RESTORE_DB --> RESTORE_SSL
RESTORE_SSL --> RESTORE_NGINX
RESTORE_NGINX --> START_SERVICES
START_SERVICES --> VERIFY
VERIFY --> DONE
style START fill:#ff6b6b
style RESTORE_CONFIG fill:#ffd93d
style RESTORE_DB fill:#ffd93d
style VERIFY fill:#6bcf7f
style DONE fill:#6bcf7f
Complete Restore Steps::
# 1. Install prerequisites on new VM
sudo apt-get update
sudo apt-get install -y docker.io docker-compose git
# 2. Clone repository
cd /data
git clone https://github.com/st7ma784/LUStores.git
cd LUStores
# 3. Extract full backup
BACKUP_FILE="full_backup_20250122_020000.tar.gz"
tar -xzf "$BACKUP_FILE" -C .
# 4. Restore environment configuration
cp full_backup_20250122_020000/env.prod.backup .env.prod
chmod 600 .env.prod
# 5. Restore SSL certificates
tar -xzf full_backup_20250122_020000/ssl_certificates.tar.gz
# 6. Restore nginx configuration
tar -xzf full_backup_20250122_020000/nginx_config.tar.gz
# 7. Create database volume directory
sudo mkdir -p /db
sudo chown -R 999:999 /db
# 8. Start database only
docker compose -f docker-compose.prod.yml up -d db
# Wait for database to initialize
sleep 10
# 9. Restore database
docker compose -f docker-compose.prod.yml exec -T db \
pg_restore -U postgres -d university_inventory -c \
< full_backup_20250122_020000/database.dump
# 10. Start all services
docker compose -f docker-compose.prod.yml up -d
# 11. Verify system
docker compose -f docker-compose.prod.yml ps
docker compose -f docker-compose.prod.yml logs -f app
Restore Scenario 3: Specific Point in Time
-------------------------------------------
**Use Case**: Need to restore to a specific date/time.
1. Identify the correct backup file::
ls -lh backups/ | grep "20250122"
2. Follow Restore Scenario 1 steps with the specific backup file
Verification After Restore
===========================
Critical Checks
---------------
1. **Database Connection**::
docker compose -f docker-compose.prod.yml exec db \
psql -U postgres -d university_inventory -c "SELECT COUNT(*) FROM users;"
2. **Application Health**::
curl https://your-domain.com/health
3. **Login Test**: Try logging in with known credentials
4. **Data Integrity**: Check recent records exist
5. **Services Running**::
docker compose -f docker-compose.prod.yml ps
Backup Testing
==============
.. important::
**Test your backups regularly!** A backup is only useful if it can be restored.
Monthly Backup Test Procedure
------------------------------
1. Create a test environment (separate VM or local Docker)
2. Restore latest backup following Scenario 2
3. Verify all data is accessible
4. Document any issues
5. Update procedures if needed
Test Restore Script::
#!/bin/bash
# Test backup restore in isolated environment
BACKUP_FILE="$1"
TEST_DIR="/tmp/lustores-restore-test"
# Create test environment
mkdir -p "$TEST_DIR"
cd "$TEST_DIR"
# Extract and test restore
tar -xzf "$BACKUP_FILE"
# ... perform restore steps ...
# Verify
docker compose exec -T db psql -U postgres -d university_inventory -c "SELECT version();"
# Cleanup
docker compose down -v
rm -rf "$TEST_DIR"
Disaster Recovery Checklist
============================
.. list-table:: Disaster Recovery Steps
:header-rows: 1
:widths: 10 60 15 15
* - Step
- Action
- Responsible
- Est. Time
* - 1
- Assess damage and determine recovery scope
- IT Manager
- 5 min
* - 2
- Provision new VM (if needed)
- System Admin
- 10 min
* - 3
- Retrieve latest backup from off-site storage
- System Admin
- 5 min
* - 4
- Install Docker and dependencies
- System Admin
- 5 min
* - 5
- Restore configuration files
- System Admin
- 2 min
* - 6
- Restore database
- System Admin
- 5 min
* - 7
- Restore SSL certificates and nginx config
- System Admin
- 2 min
* - 8
- Start services and verify
- System Admin
- 5 min
* - 9
- Test application functionality
- QA Team
- 10 min
* - 10
- Notify users of service restoration
- IT Manager
- 2 min
**Total Recovery Time Objective (RTO)**: 51 minutes
**Recovery Point Objective (RPO)**: 24 hours (with daily backups)
Backup Best Practices
======================
Daily Operations
----------------
- ✅ **Automated daily backups** at 2 AM (low traffic)
- ✅ **Monitor backup logs** daily for failures
- ✅ **Verify backup file sizes** are reasonable
- ✅ **Copy to off-site storage** within 24 hours
Weekly Tasks
------------
- ✅ **Manual full backup** (database + config + SSL)
- ✅ **Verify off-site backups** are accessible
- ✅ **Check disk space** in backup directory
Monthly Tasks
-------------
- ✅ **Test restore procedure** in isolated environment
- ✅ **Review backup retention policy**
- ✅ **Update documentation** if procedures change
Troubleshooting
===============
Backup Fails with "Permission Denied"
--------------------------------------
::
# Fix permissions on backup directory
sudo chown -R $(whoami):$(whoami) backups/
chmod 755 backups/
Backup File is Empty or Too Small
----------------------------------
::
# Check if database container is running
docker compose -f docker-compose.prod.yml ps db
# Check database size
docker compose -f docker-compose.prod.yml exec db \
psql -U postgres -d university_inventory \
-c "SELECT pg_size_pretty(pg_database_size('university_inventory'));"
Restore Fails with "Database Already Exists"
---------------------------------------------
::
# Drop and recreate database
docker compose -f docker-compose.prod.yml exec db \
psql -U postgres -c "DROP DATABASE university_inventory;"
docker compose -f docker-compose.prod.yml exec db \
psql -U postgres -c "CREATE DATABASE university_inventory;"
# Then retry restore
Cannot Connect After Restore
-----------------------------
1. Check .env.prod has correct credentials
2. Verify all services are running
3. Check application logs for errors
4. Ensure database initialized correctly
Related Documentation
=====================
- :doc:`docker-architecture` - Understanding the system architecture
- :doc:`qrh` - Quick troubleshooting reference
- :doc:`/deployment/production` - Production deployment guide
- :doc:`/admin/system-management` - Admin interface backup feature