Backup and Restore
This guide covers data backup and restoration procedures for the eTeamups Platform. The platform stores data in MongoDB (primary database), Redis (caching and session store), and the file system (media uploads). All backup and restore operations are handled through dedicated scripts.
Backup Overview
| Data Store | Backup Method | Script | Default Location |
|---|---|---|---|
| MongoDB | mongodump (gzip compressed) |
scripts/backup.sh |
backups/{date}/mongodb-{timestamp}/ |
| Redis | redis-cli SAVE + RDB copy |
scripts/backup.sh |
backups/{date}/redis-{timestamp}.rdb |
| Media files | tar archive from Docker volume |
scripts/backup.sh |
backups/{date}/media-{timestamp}.tar.gz |
| Configuration | File copy | scripts/backup.sh |
backups/{date}/docker-compose-{timestamp}.yml |
MongoDB Backup
Running a Backup
Execute the backup script from the project root:
./scripts/backup.sh
The script performs the following steps:
- Creates a date-stamped directory under
backups/(e.g.,backups/20241127/). - Runs
mongodumpinside theeteamups-mongodbcontainer with gzip compression. - Copies the backup from the container to the host filesystem.
- Removes the temporary backup directory from inside the container.
- Reports the backup size.
What Gets Backed Up
The mongodump command authenticates using the MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD from docker.env and backs up all databases, including:
- The primary application database (
eteamupsby default) - The
apilogscollection containing API request logs - Any other databases present in the MongoDB instance
Backup Output
A successful backup produces the following structure:
backups/
20241127/
mongodb-20241127_143000/
eteamups/
users.bson.gz
users.metadata.json.gz
apilogs.bson.gz
apilogs.metadata.json.gz
...
admin/
...
redis-20241127_143000.rdb
media-20241127_143000.tar.gz
docker-compose-20241127_143000.yml
manifest-20241127_143000.txt
Backup Manifest
Each backup includes a manifest-{timestamp}.txt file recording:
- Backup date and timestamp
- List of backed-up components
- Docker Compose version
- List of running services at the time of backup
Configuration
| Variable | Default | Description |
|---|---|---|
BACKUP_DIR |
./backups |
Root directory for all backups |
RETENTION_DAYS |
30 |
Number of days to keep old backups |
BACKUP_REMOTE_PATH |
(unset) | Remote rsync destination for off-site backup |
AWS_S3_BUCKET |
(unset) | S3 bucket for cloud backup |
Automatic Cleanup
The backup script automatically deletes backup directories older than RETENTION_DAYS (default: 30 days). This runs at the end of every backup operation.
MongoDB Restore
Running a Restore
Restore from a specific backup date:
./scripts/restore.sh 20241127
If no date is provided, the script lists available backups:
./scripts/restore.sh
# Output:
# Error: Please provide backup date
# Available backups:
# 20241125
# 20241126
# 20241127
Restore Process
The scripts/restore.sh script performs the following steps:
- Validates the backup – Checks that the backup directory exists and displays its contents.
- Prompts for confirmation – Requires typing
yesto proceed. This is a destructive operation. - Stops application services – Stops auth, profile, organisation, media, message-queue, admin-portal, and nginx containers. MongoDB and Redis remain running.
- Restores MongoDB – Copies the backup into the container, drops the existing database, and runs
mongorestorewith gzip decompression. - Restores Redis – Stops Redis, copies the RDB file into the container, and restarts Redis.
- Restores media files – Extracts the media archive into the
media_uploadsDocker volume, replacing existing files. - Starts all services – Brings all containers back up and waits for them to become healthy (up to 2.5 minutes).
Partial Restore
To restore only specific components, you can run the relevant Docker commands manually:
Restore Only MongoDB
# Copy backup to container
docker cp backups/20241127/mongodb-20241127_143000 eteamups-mongodb:/data/restore
# Restore (without dropping existing data -- merges)
docker exec eteamups-mongodb mongorestore \
--username="$MONGO_INITDB_ROOT_USERNAME" \
--password="$MONGO_INITDB_ROOT_PASSWORD" \
--authenticationDatabase=admin \
--gzip \
/data/restore
# Clean up
docker exec eteamups-mongodb rm -rf /data/restore
Restore Only a Specific Collection
docker exec eteamups-mongodb mongorestore \
--username="$MONGO_INITDB_ROOT_USERNAME" \
--password="$MONGO_INITDB_ROOT_PASSWORD" \
--authenticationDatabase=admin \
--gzip \
--nsInclude="eteamups.users" \
/data/restore
Restore Only Redis
docker compose stop redis
docker cp backups/20241127/redis-20241127_143000.rdb eteamups-redis:/data/dump.rdb
docker compose start redis
Redis Persistence
AOF (Append-Only File)
Redis is configured with AOF persistence in docker-compose.yml:
command: >
redis-server
--appendonly yes
--appendfsync everysec
--maxmemory 512mb
--maxmemory-policy allkeys-lru
--requirepass ${REDIS_PASSWORD:-changeme}
| Setting | Value | Description |
|---|---|---|
appendonly |
yes |
AOF persistence enabled |
appendfsync |
everysec |
Fsync every second (good balance of performance and durability) |
maxmemory |
512mb |
Maximum memory usage |
maxmemory-policy |
allkeys-lru |
Evict least-recently-used keys when memory limit is reached |
How AOF Works
- Every write command is appended to the AOF file (
appendonly.aof) inside the Redis data volume. - If Redis restarts, it replays the AOF file to reconstruct the dataset.
- With
appendfsync everysec, you could lose at most 1 second of writes in a crash scenario.
Redis Data Volume
Redis data is stored in the redis_data Docker volume, which persists across container restarts. The volume contains:
dump.rdb– Point-in-time RDB snapshot (created bySAVEcommands during backup)appendonly.aof– Append-only file for continuous persistence
Manual Redis Snapshot
To create an immediate RDB snapshot:
docker exec eteamups-redis redis-cli -a "$REDIS_PASSWORD" SAVE
To copy it to the host:
docker cp eteamups-redis:/data/dump.rdb ./redis-backup.rdb
Backup Scheduling
Setting Up Automated Backups with Cron
Add a daily backup cron job:
crontab -e
Add the following line for a daily backup at 2:00 AM:
0 2 * * * cd /path/to/eteamups-platform && ./scripts/backup.sh >> backups/backup.log 2>&1
Recommended Backup Schedule
| Frequency | Time | What |
|---|---|---|
| Daily | 2:00 AM | Full backup (MongoDB + Redis + Media) via scripts/backup.sh |
| Weekly | Sunday 3:00 AM | Verify latest backup integrity (see verification section) |
| Monthly | 1st of month | Copy latest backup to off-site storage |
Off-Site Backup
The backup script supports two off-site methods if the corresponding environment variables are set:
rsync
Set the BACKUP_REMOTE_PATH variable:
export BACKUP_REMOTE_PATH="user@backup-server:/backups/eteamups"
The script will automatically rsync the backup after local completion.
AWS S3
Set the AWS_S3_BUCKET variable (requires the AWS CLI to be installed):
export AWS_S3_BUCKET="my-backup-bucket"
The script will sync the backup to s3://{bucket}/backups/{date}/.
Backup Verification
Testing Backup Integrity
After each backup, verify its contents:
# List the backup contents
ls -lh backups/20241127/
# Check MongoDB backup completeness
ls backups/20241127/mongodb-*/eteamups/
# Verify gzip archive integrity for media
gzip -t backups/20241127/media-*.tar.gz && echo "Archive OK" || echo "Archive corrupted"
# Check manifest
cat backups/20241127/manifest-*.txt
Restore Test Procedure
Periodically test your backups by restoring to a separate environment:
Spin up a temporary MongoDB instance:
docker run -d --name mongo-test -p 27018:27017 mongo:7-jammyCopy and restore the backup:
docker cp backups/20241127/mongodb-20241127_143000 mongo-test:/data/restore docker exec mongo-test mongorestore --gzip /data/restoreVerify the data:
docker exec mongo-test mongosh --eval "db.getSiblingDB('eteamups').getCollectionNames()"Clean up:
docker stop mongo-test && docker rm mongo-test
Disaster Recovery Procedures
Scenario 1: Single Service Failure
If one application service fails but the database is intact:
- Check container status:
docker compose ps - View container logs:
docker compose logs auth-service - Restart the service:
docker compose restart auth-service - Verify health:
./scripts/health-check.sh
No data restore is needed since the service is stateless.
Scenario 2: Database Corruption
If MongoDB data becomes corrupted:
Stop all application services:
docker compose stop auth-service profile-service organisation-service media-service message-queue-service admin-portal zeswa-hub nginxIdentify the latest good backup:
ls -la backups/Run the restore script:
./scripts/restore.sh 20241127Verify the restoration:
./scripts/health-check.sh
Scenario 3: Complete Server Failure
If the entire server must be rebuilt:
Provision a new server with Docker and Docker Compose installed.
Clone the repository and copy your
docker.envconfiguration.Copy the latest backup from off-site storage:
mkdir -p backups/ rsync -az backup-server:/backups/eteamups/latest/ backups/Pull the Docker images:
docker compose pullStart the infrastructure services:
docker compose up -d mongodb redisWait for MongoDB and Redis to become healthy, then restore data:
./scripts/restore.sh {backup-date}Start all services:
docker compose up -dRun the health check:
./scripts/health-check.sh
Scenario 4: Redis Data Loss
Redis is used for caching and sessions. Data loss is generally recoverable:
- Restart Redis:
docker compose restart redis - If the AOF file is corrupted:
docker compose stop redis docker exec eteamups-redis redis-check-aof --fix /data/appendonly.aof docker compose start redis - If a full restore is needed, use the RDB file from the latest backup (see the partial restore section above).
- Active user sessions will be lost and users will need to re-authenticate.
Related Scripts
| Script | Description |
|---|---|
scripts/backup.sh |
Full platform backup (MongoDB, Redis, media, config) |
scripts/restore.sh [date] |
Restore from a backup by date |
scripts/health-check.sh |
Verify all services are healthy after restore |
scripts/seed.sh |
Seed initial data (for fresh deployments, not restores) |
scripts/seed-docker.sh |
Seed data inside Docker containers |