Backup & Restore SOP - Scola ERP System¶
Version: 1.0
Date: March 1, 2026
Scope: Production database and file storage backup/restore procedures
RTO (Recovery Time Objective): < 1 hour
RPO (Recovery Point Objective): < 15 minutes
1. Overview¶
This document outlines the Standard Operating Procedures (SOP) for backing up and restoring the Scola ERP system, including: - PostgreSQL database backups - File storage backups (attachments, uploads) - Automated backup schedules - Disaster recovery procedures
2. Backup Strategy¶
2.1 Backup Types¶
| Type | Frequency | Retention | Storage Location |
|---|---|---|---|
| Full Database | Daily (2 AM) | 30 days | /backups/database/ + S3 |
| Incremental DB | Every 6 hours | 7 days | /backups/database/incremental/ |
| File Storage | Daily (3 AM) | 30 days | /backups/filestore/ + S3 |
| Transaction Logs | Continuous | 7 days | /backups/wal/ |
2.2 Backup Components¶
Database: - PostgreSQL database dump (pg_dump) - All Odoo databases (scola_production, scola_test) - Database roles and permissions
File Storage:
- Odoo filestore (/opt/odoo/.local/share/Odoo/filestore/)
- Uploaded attachments
- Generated reports
- Session files
Configuration:
- Odoo configuration files (odoo.conf)
- Nginx configuration
- SSL certificates
- Environment variables
3. Database Backup Procedures¶
3.1 Manual Full Backup¶
#!/bin/bash
# Manual database backup script
# Configuration
DB_NAME="scola_production"
BACKUP_DIR="/backups/database"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.dump"
# Create backup directory if not exists
mkdir -p ${BACKUP_DIR}
# Perform backup
echo "Starting backup of ${DB_NAME}..."
pg_dump -U odoo -F c -b -v -f ${BACKUP_FILE} ${DB_NAME}
# Verify backup
if [ $? -eq 0 ]; then
echo "Backup successful: ${BACKUP_FILE}"
# Compress backup
gzip ${BACKUP_FILE}
echo "Compressed: ${BACKUP_FILE}.gz"
# Calculate checksum
md5sum ${BACKUP_FILE}.gz > ${BACKUP_FILE}.gz.md5
echo "Checksum created: ${BACKUP_FILE}.gz.md5"
# Upload to S3 (optional)
# aws s3 cp ${BACKUP_FILE}.gz s3://scola-backups/database/
else
echo "Backup failed!"
exit 1
fi
# Clean up old backups (keep last 30 days)
find ${BACKUP_DIR} -name "*.dump.gz" -mtime +30 -delete
echo "Old backups cleaned up"
Usage:
sudo -u odoo /opt/odoo/scripts/backup_database.sh
3.2 Automated Daily Backup (Cron)¶
# Add to crontab: sudo crontab -e -u odoo
0 2 * * * /opt/odoo/scripts/backup_database.sh >> /var/log/odoo/backup.log 2>&1
3.3 Incremental Backup (WAL Archiving)¶
Enable WAL archiving in PostgreSQL:
# Edit postgresql.conf
sudo nano /etc/postgresql/14/main/postgresql.conf
# Add/modify:
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /backups/wal/%f && cp %p /backups/wal/%f'
archive_timeout = 300 # 5 minutes
Restart PostgreSQL:
sudo systemctl restart postgresql
4. File Storage Backup Procedures¶
4.1 Manual Filestore Backup¶
#!/bin/bash
# Manual filestore backup script
# Configuration
FILESTORE_PATH="/opt/odoo/.local/share/Odoo/filestore/scola_production"
BACKUP_DIR="/backups/filestore"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/filestore_${TIMESTAMP}.tar.gz"
# Create backup directory
mkdir -p ${BACKUP_DIR}
# Perform backup
echo "Starting filestore backup..."
tar -czf ${BACKUP_FILE} -C /opt/odoo/.local/share/Odoo/filestore scola_production
# Verify backup
if [ $? -eq 0 ]; then
echo "Filestore backup successful: ${BACKUP_FILE}"
# Calculate checksum
md5sum ${BACKUP_FILE} > ${BACKUP_FILE}.md5
# Upload to S3 (optional)
# aws s3 cp ${BACKUP_FILE} s3://scola-backups/filestore/
else
echo "Filestore backup failed!"
exit 1
fi
# Clean up old backups (keep last 30 days)
find ${BACKUP_DIR} -name "filestore_*.tar.gz" -mtime +30 -delete
Usage:
sudo /opt/odoo/scripts/backup_filestore.sh
4.2 Automated Daily Backup (Cron)¶
# Add to crontab: sudo crontab -e
0 3 * * * /opt/odoo/scripts/backup_filestore.sh >> /var/log/odoo/backup.log 2>&1
5. Restore Procedures¶
5.1 Database Restore¶
Prerequisites: - Stop Odoo service - Ensure sufficient disk space - Verify backup integrity (checksum)
Restore Steps:
#!/bin/bash
# Database restore script
# Configuration
DB_NAME="scola_production"
BACKUP_FILE="/backups/database/scola_production_20260301_020000.dump.gz"
# 1. Stop Odoo service
echo "Stopping Odoo service..."
sudo systemctl stop odoo
# 2. Verify backup checksum
echo "Verifying backup integrity..."
md5sum -c ${BACKUP_FILE}.md5
if [ $? -ne 0 ]; then
echo "Backup checksum verification failed!"
exit 1
fi
# 3. Decompress backup
echo "Decompressing backup..."
gunzip -c ${BACKUP_FILE} > /tmp/restore.dump
# 4. Drop existing database (CAUTION!)
echo "Dropping existing database..."
sudo -u postgres psql -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${DB_NAME}';"
sudo -u postgres dropdb ${DB_NAME}
# 5. Create new database
echo "Creating new database..."
sudo -u postgres createdb -O odoo ${DB_NAME}
# 6. Restore backup
echo "Restoring database..."
pg_restore -U odoo -d ${DB_NAME} -v /tmp/restore.dump
# 7. Verify restore
if [ $? -eq 0 ]; then
echo "Database restore successful!"
# Clean up temp file
rm /tmp/restore.dump
# Start Odoo service
echo "Starting Odoo service..."
sudo systemctl start odoo
# Wait for service to start
sleep 10
# Check service status
sudo systemctl status odoo
else
echo "Database restore failed!"
exit 1
fi
Usage:
sudo /opt/odoo/scripts/restore_database.sh
5.2 Filestore Restore¶
#!/bin/bash
# Filestore restore script
# Configuration
FILESTORE_PATH="/opt/odoo/.local/share/Odoo/filestore/scola_production"
BACKUP_FILE="/backups/filestore/filestore_20260301_030000.tar.gz"
# 1. Stop Odoo service
echo "Stopping Odoo service..."
sudo systemctl stop odoo
# 2. Verify backup checksum
echo "Verifying backup integrity..."
md5sum -c ${BACKUP_FILE}.md5
if [ $? -ne 0 ]; then
echo "Backup checksum verification failed!"
exit 1
fi
# 3. Backup current filestore (just in case)
echo "Backing up current filestore..."
mv ${FILESTORE_PATH} ${FILESTORE_PATH}.old.$(date +%Y%m%d_%H%M%S)
# 4. Restore filestore
echo "Restoring filestore..."
mkdir -p /opt/odoo/.local/share/Odoo/filestore
tar -xzf ${BACKUP_FILE} -C /opt/odoo/.local/share/Odoo/filestore
# 5. Set correct permissions
echo "Setting permissions..."
chown -R odoo:odoo ${FILESTORE_PATH}
chmod -R 750 ${FILESTORE_PATH}
# 6. Start Odoo service
echo "Starting Odoo service..."
sudo systemctl start odoo
# 7. Verify
if [ $? -eq 0 ]; then
echo "Filestore restore successful!"
sudo systemctl status odoo
else
echo "Filestore restore failed!"
exit 1
fi
6. Disaster Recovery Scenarios¶
6.1 Complete System Failure¶
Recovery Steps:
- Provision new server (same specs as production)
-
Install base system:
# Install PostgreSQL sudo apt install postgresql-14 # Install Odoo dependencies sudo apt install python3-pip python3-dev libxml2-dev libxslt1-dev \ libldap2-dev libsasl2-dev libjpeg-dev zlib1g-dev -
Restore database:
# Copy backup from S3 aws s3 cp s3://scola-backups/database/latest.dump.gz /tmp/ # Restore /opt/odoo/scripts/restore_database.sh -
Restore filestore:
# Copy backup from S3 aws s3 cp s3://scola-backups/filestore/latest.tar.gz /tmp/ # Restore /opt/odoo/scripts/restore_filestore.sh -
Restore configuration:
# Copy odoo.conf sudo cp /backups/config/odoo.conf /etc/odoo/ # Copy SSL certificates sudo cp -r /backups/ssl/* /etc/ssl/ -
Start services:
sudo systemctl start postgresql sudo systemctl start odoo sudo systemctl start nginx -
Verify system:
# Check services sudo systemctl status postgresql odoo nginx # Test web access curl -I https://scola.example.com # Check logs tail -f /var/log/odoo/odoo-server.log
Expected RTO: 45-60 minutes
6.2 Database Corruption¶
Recovery Steps:
- Stop Odoo service
- Identify corruption (check PostgreSQL logs)
- Attempt database repair:
sudo -u postgres reindexdb -d scola_production sudo -u postgres vacuumdb --full --analyze scola_production - If repair fails, restore from latest backup
- Verify data integrity
- Resume operations
Expected RTO: 15-30 minutes
6.3 Accidental Data Deletion¶
Recovery Steps:
- Identify deletion timestamp
- Find nearest backup before deletion
- Restore to temporary database:
pg_restore -U odoo -d scola_temp /backups/database/backup.dump - Extract deleted data:
-- Example: Restore deleted student records INSERT INTO scola_production.op_student SELECT * FROM scola_temp.op_student WHERE id IN (123, 456, 789); - Verify restored data
- Drop temporary database
Expected RTO: 10-20 minutes
7. Backup Verification¶
7.1 Monthly Restore Test¶
Schedule: First Sunday of each month
Procedure: 1. Select random backup from previous month 2. Restore to test environment 3. Verify data integrity: - Check record counts - Verify file attachments - Test critical workflows 4. Document results 5. Update procedures if issues found
7.2 Backup Integrity Checks¶
Daily automated checks:
#!/bin/bash
# Verify backup integrity
BACKUP_DIR="/backups/database"
LATEST_BACKUP=$(ls -t ${BACKUP_DIR}/*.dump.gz | head -1)
# Check file exists
if [ ! -f "${LATEST_BACKUP}" ]; then
echo "ERROR: Latest backup not found!"
# Send alert
exit 1
fi
# Verify checksum
md5sum -c ${LATEST_BACKUP}.md5
if [ $? -ne 0 ]; then
echo "ERROR: Backup checksum verification failed!"
# Send alert
exit 1
fi
# Check file size (should be > 100MB for production)
FILE_SIZE=$(stat -f%z "${LATEST_BACKUP}" 2>/dev/null || stat -c%s "${LATEST_BACKUP}")
if [ ${FILE_SIZE} -lt 104857600 ]; then
echo "WARNING: Backup file size suspiciously small!"
# Send alert
fi
echo "Backup integrity check passed"
8. Monitoring & Alerts¶
8.1 Backup Monitoring¶
Metrics to monitor: - Backup completion status - Backup file size - Backup duration - Storage space usage - Checksum verification status
Alert triggers: - Backup failed - Backup file size < expected - Backup duration > 2x normal - Storage space < 20% free - Checksum verification failed
8.2 Alert Channels¶
- Email: [email protected]
- Slack: #ops-alerts
- SMS: Critical failures only
9. Backup Storage Management¶
9.1 Local Storage¶
Location: /backups/
Retention: - Database: 30 days - Filestore: 30 days - WAL logs: 7 days
Cleanup script:
#!/bin/bash
# Clean up old backups
find /backups/database -name "*.dump.gz" -mtime +30 -delete
find /backups/filestore -name "*.tar.gz" -mtime +30 -delete
find /backups/wal -name "*.wal" -mtime +7 -delete
9.2 Off-site Storage (S3)¶
Bucket: s3://scola-backups/
Retention: - Daily backups: 90 days - Monthly backups: 1 year - Yearly backups: 7 years
Lifecycle policy:
{
"Rules": [
{
"Id": "DeleteOldDailyBackups",
"Status": "Enabled",
"Prefix": "database/daily/",
"Expiration": {
"Days": 90
}
},
{
"Id": "TransitionMonthlyToGlacier",
"Status": "Enabled",
"Prefix": "database/monthly/",
"Transitions": [
{
"Days": 30,
"StorageClass": "GLACIER"
}
],
"Expiration": {
"Days": 365
}
}
]
}
10. Checklist¶
Pre-Backup Checklist¶
- [ ] Verify sufficient disk space (>50GB free)
- [ ] Check PostgreSQL service status
- [ ] Verify backup scripts are executable
- [ ] Confirm S3 credentials are valid
Post-Backup Checklist¶
- [ ] Verify backup file created
- [ ] Check backup file size (>100MB)
- [ ] Verify checksum file created
- [ ] Confirm S3 upload successful (if enabled)
- [ ] Review backup logs for errors
Pre-Restore Checklist¶
- [ ] Verify backup integrity (checksum)
- [ ] Confirm sufficient disk space
- [ ] Notify users of maintenance window
- [ ] Stop Odoo service
- [ ] Backup current state (just in case)
Post-Restore Checklist¶
- [ ] Verify database connectivity
- [ ] Check critical tables (students, courses, exams)
- [ ] Test file attachments
- [ ] Verify user logins
- [ ] Check system logs for errors
- [ ] Notify users of completion
11. Contact Information¶
Primary Contact: - Name: System Administrator - Email: [email protected] - Phone: +62-xxx-xxxx-xxxx
Backup Contact: - Name: DevOps Engineer - Email: [email protected] - Phone: +62-xxx-xxxx-xxxx
Escalation: - CTO: [email protected]
Document Version: 1.0
Last Updated: March 1, 2026
Next Review: June 1, 2026