What to back up
A complete Halo backup includes:
Database : All content, settings, and user data
Work directory : Uploaded files, plugins, themes, and logs
Configuration files : Custom application.yaml and environment settings
Regular backups are critical for disaster recovery. Test your restore procedure periodically to ensure backups are working correctly.
Backup strategies
Complete backup of all data, suitable for disaster recovery. Takes longer but provides complete restoration capability.
Only backs up changed files since last backup. Faster but requires all previous backups for restoration.
Backs up only the database. Quick and essential for content recovery.
Backs up the work directory only. Important for uploaded media and customizations.
Docker deployment backups
Manual backup
Create a one-time backup of your Docker deployment:
Stop Halo container
Stopping the container ensures data consistency in the backup.
Create backup archive
# Create backup directory
mkdir -p ~/halo-backups
# Backup all data
tar -czf ~/halo-backups/halo-backup- $( date +%Y%m%d-%H%M%S ) .tar.gz \
./halo \
./postgres \
docker-compose.yml
Verify backup
ls -lh ~/halo-backups/
tar -tzf ~/halo-backups/halo-backup- * .tar.gz | head -20
Automated backup script
Create a backup script at /usr/local/bin/halo-backup.sh:
/usr/local/bin/halo-backup.sh
#!/bin/bash
# Configuration
BACKUP_DIR = "/backup/halo"
HALO_DIR = "/path/to/your/halo"
RETENTION_DAYS = 30
TIMESTAMP = $( date +%Y%m%d-%H%M%S )
BACKUP_FILE = " $BACKUP_DIR /halo-backup- $TIMESTAMP .tar.gz"
# Create backup directory
mkdir -p " $BACKUP_DIR "
echo "Starting Halo backup at $( date )"
# Stop Halo for consistent backup
cd " $HALO_DIR "
docker-compose down
# Create backup
tar -czf " $BACKUP_FILE " \
./halo \
./postgres \
docker-compose.yml
if [ $? -eq 0 ]; then
echo "Backup created successfully: $BACKUP_FILE "
echo "Backup size: $( du -h $BACKUP_FILE | cut -f1 )"
else
echo "Backup failed!"
docker-compose up -d
exit 1
fi
# Restart Halo
docker-compose up -d
# Remove old backups
find " $BACKUP_DIR " -name "halo-backup-*.tar.gz" -mtime + $RETENTION_DAYS -delete
echo "Removed backups older than $RETENTION_DAYS days"
echo "Backup completed at $( date )"
Make the script executable:
sudo chmod +x /usr/local/bin/halo-backup.sh
Schedule automated backups
Use cron to run backups daily at 2 AM:
# Edit crontab
crontab -e
# Add this line
0 2 * * * /usr/local/bin/halo-backup.sh >> /var/log/halo-backup.log 2>&1
Database-only backups
For faster, more frequent backups, back up only the database:
#!/bin/bash
BACKUP_DIR = "/backup/halo/db"
TIMESTAMP = $( date +%Y%m%d-%H%M%S )
mkdir -p " $BACKUP_DIR "
# Backup PostgreSQL database
docker exec halo-postgres pg_dump -U halo halo | \
gzip > " $BACKUP_DIR /halo-db- $TIMESTAMP .sql.gz"
echo "Database backup created: halo-db- $TIMESTAMP .sql.gz"
# Keep only last 14 days
find " $BACKUP_DIR " -name "halo-db-*.sql.gz" -mtime +14 -delete
Schedule hourly database backups:
0 * * * * /usr/local/bin/halo-db-backup.sh >> /var/log/halo-db-backup.log 2>&1
Kubernetes deployment backups
Using Velero
Velero is a popular backup solution for Kubernetes:
Install Velero
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.8.0 \
--bucket halo-backups \
--secret-file ./credentials-velero \
--backup-location-config region=us-west-2
Create backup schedule
velero schedule create halo-daily \
--schedule= "0 2 * * *" \
--include-namespaces halo \
--ttl 720h0m0s
Manual backup
velero backup create halo-manual- $( date +%Y%m%d ) \
--include-namespaces halo
Manual Kubernetes backup
#!/bin/bash
BACKUP_DIR = "/backup/halo/k8s"
TIMESTAMP = $( date +%Y%m%d-%H%M%S )
NAMESPACE = "halo"
mkdir -p " $BACKUP_DIR "
echo "Starting Kubernetes backup for namespace: $NAMESPACE "
# Export all resources
kubectl get all,pvc,configmap,secret -n $NAMESPACE -o yaml > \
" $BACKUP_DIR /halo-k8s- $TIMESTAMP .yaml"
# Backup persistent volumes
for pvc in $( kubectl get pvc -n $NAMESPACE -o jsonpath='{.items[*].metadata.name}' ); do
POD = $( kubectl get pods -n $NAMESPACE -o jsonpath="{.items[0].metadata.name}" )
kubectl exec -n $NAMESPACE $POD -- tar czf /tmp/pvc-backup.tar.gz /root/.halo2
kubectl cp $NAMESPACE / $POD :/tmp/pvc-backup.tar.gz \
" $BACKUP_DIR /halo-pvc- $pvc - $TIMESTAMP .tar.gz"
kubectl exec -n $NAMESPACE $POD -- rm /tmp/pvc-backup.tar.gz
done
# Backup database
POSTGRES_POD = $( kubectl get pod -n $NAMESPACE -l app=postgres -o jsonpath="{.items[0].metadata.name}" )
kubectl exec -n $NAMESPACE $POSTGRES_POD -- pg_dump -U halo halo | \
gzip > " $BACKUP_DIR /halo-db- $TIMESTAMP .sql.gz"
echo "Backup completed: $BACKUP_DIR "
# Cleanup old backups
find " $BACKUP_DIR " -name "halo-*" -mtime +30 -delete
Restore procedures
Restore Docker deployment
Remove existing data
This will delete all current data. Make sure you have a backup of current state if needed.
Extract backup
tar -xzf ~/halo-backups/halo-backup-YYYYMMDD-HHMMSS.tar.gz
Verify restoration
# Check containers are running
docker-compose ps
# Check Halo logs
docker-compose logs -f halo
# Access the site
curl http://localhost:8090
Restore database only
If you only need to restore the database:
# Stop Halo
docker-compose stop halo
# Drop and recreate database
docker exec -it halo-postgres psql -U halo -c "DROP DATABASE halo;"
docker exec -it halo-postgres psql -U halo -c "CREATE DATABASE halo;"
# Restore from backup
gunzip -c /backup/halo/db/halo-db-YYYYMMDD-HHMMSS.sql.gz | \
docker exec -i halo-postgres psql -U halo halo
# Restart Halo
docker-compose start halo
Restore Kubernetes deployment
Delete current deployment
kubectl delete namespace halo
Restore with Velero
# List available backups
velero backup get
# Restore from backup
velero restore create --from-backup halo-daily-YYYYMMDD
# Check restore status
velero restore describe halo-daily-YYYYMMDD
Verify restoration
kubectl get pods -n halo
kubectl logs -n halo -l app=halo -f
Remote backup storage
Store backups offsite for disaster recovery:
AWS S3
Backblaze B2
rsync to remote server
#!/bin/bash
# After creating backup, sync to S3
aws s3 sync /backup/halo/ s3://my-halo-backups/
# Or use AWS CLI in backup script
aws s3 cp " $BACKUP_FILE " s3://my-halo-backups/ $( basename $BACKUP_FILE )
Backup verification
Regularly test your backups to ensure they work:
#!/bin/bash
BACKUP_FILE = " $1 "
TEST_DIR = "/tmp/halo-backup-test"
if [ -z " $BACKUP_FILE " ]; then
echo "Usage: $0 <backup-file>"
exit 1
fi
echo "Testing backup: $BACKUP_FILE "
# Create test directory
mkdir -p " $TEST_DIR "
cd " $TEST_DIR "
# Extract backup
tar -xzf " $BACKUP_FILE "
if [ $? -eq 0 ]; then
echo "✓ Backup extraction successful"
# Verify files exist
if [ -d "halo" ] && [ -d "postgres" ] && [ -f "docker-compose.yml" ]; then
echo "✓ All required files present"
else
echo "✗ Missing required files"
exit 1
fi
else
echo "✗ Backup extraction failed"
exit 1
fi
# Cleanup
cd /
rm -rf " $TEST_DIR "
echo "✓ Backup verification completed successfully"
Best practices
3-2-1 rule Keep 3 copies of data, on 2 different media types, with 1 copy offsite
Regular testing Test restore procedures quarterly to ensure backups work
Monitor backups Set up alerts for backup failures
Document procedures Keep restore instructions accessible outside of the system being backed up
Next steps
Docker deployment Learn about Docker-based deployment options
Kubernetes deployment Deploy Halo on Kubernetes with persistent storage