# Backup and Restore Guide Complete guide for backing up and restoring your Nextcloud Stack. ## Automated Backups ### What Gets Backed Up - **Daily (3:00 AM)**: - PostgreSQL database dump - **Weekly (Sundays, 3:00 AM)**: - Nextcloud data volume - Configuration files - **Retention**: 30 days ### Backup Locations ``` /opt/nextcloud-stack/backups/ ├── database/ │ └── nextcloud_db_YYYYMMDD_HHMMSS.sql.gz ├── volumes/ │ ├── nextcloud_data_YYYYMMDD_HHMMSS.tar.gz │ └── configs_YYYYMMDD_HHMMSS.tar.gz └── backup.log ``` ### Manual Backup ```bash ssh user@server /opt/nextcloud-stack/backup.sh ``` ### Check Backup Status ```bash # View backup log tail -f /opt/nextcloud-stack/backups/backup.log # List backups ls -lh /opt/nextcloud-stack/backups/database/ ls -lh /opt/nextcloud-stack/backups/volumes/ # Check disk usage du -sh /opt/nextcloud-stack/backups/ ``` --- ## Restore Procedures ### 1. Restore Database Only **When to use:** - Database corruption - Accidental data deletion - Need to revert to earlier state **Steps:** ```bash # 1. Stop Nextcloud (keep database running) cd /opt/nextcloud-stack docker compose stop next # 2. List available backups ls -lh backups/database/ # 3. Choose backup to restore BACKUP_FILE="backups/database/nextcloud_db_20260216_030000.sql.gz" # 4. Drop existing database (CAUTION!) docker exec next-db psql -U nextcloud -c "DROP DATABASE nextcloud;" docker exec next-db psql -U nextcloud -c "CREATE DATABASE nextcloud;" # 5. Restore from backup gunzip < $BACKUP_FILE | docker exec -i next-db psql -U nextcloud -d nextcloud # 6. Restart Nextcloud docker compose start next # 7. Run Nextcloud upgrade (if needed) docker exec -u www-data next php occ upgrade # 8. Disable maintenance mode docker exec -u www-data next php occ maintenance:mode --off ``` ### 2. Restore Data Volumes **When to use:** - Lost files - Corrupted data directory - Complete system failure **Steps:** ```bash # 1. Stop all services cd /opt/nextcloud-stack docker compose down # 2. List available backups ls -lh backups/volumes/ # 3. Choose backup BACKUP_FILE="backups/volumes/nextcloud_data_20260216_030000.tar.gz" # 4. Restore volume # Note: This requires accessing the Docker volume directory sudo tar -xzf $BACKUP_FILE -C /var/lib/docker/volumes/nextcloud_nextcloud_data/_data/ # 5. Restore configs (optional) CONFIG_BACKUP="backups/volumes/configs_20260216_030000.tar.gz" sudo tar -xzf $CONFIG_BACKUP -C /opt/nextcloud-stack/configs/ # 6. Fix permissions sudo chown -R www-data:www-data /var/lib/docker/volumes/nextcloud_nextcloud_data/_data/ # 7. Start services docker compose up -d # 8. Run Nextcloud file scan docker exec -u www-data next php occ files:scan --all ``` ### 3. Complete System Restore **When to use:** - Disaster recovery - Migration to new server - Complete system failure **Steps:** ```bash # 1. On new server, install base system # Run Ansible playbooks 01-04 (up to Tailscale) ansible-playbook playbooks/01-preflight-checks.yml --ask-vault-pass ansible-playbook playbooks/02-system-setup.yml --ask-vault-pass ansible-playbook playbooks/03-docker-setup.yml --ask-vault-pass ansible-playbook playbooks/04-tailscale-setup.yml --ask-vault-pass # 2. Create deployment directory structure ssh user@new-server sudo mkdir -p /opt/nextcloud-stack/backups/{database,volumes} # 3. Copy backups from old server to new server # On your local machine: scp -r old-server:/opt/nextcloud-stack/backups/* user@new-server:/opt/nextcloud-stack/backups/ # 4. Deploy stack (creates volumes and containers) ansible-playbook playbooks/05-deploy-stack.yml --ask-vault-pass # 5. Stop services on new server ssh user@new-server cd /opt/nextcloud-stack docker compose down # 6. Restore database BACKUP_FILE="backups/database/nextcloud_db_20260216_030000.sql.gz" docker compose up -d next-db next-redis sleep 10 gunzip < $BACKUP_FILE | docker exec -i next-db psql -U nextcloud -d nextcloud # 7. Restore data volumes VOLUME_BACKUP="backups/volumes/nextcloud_data_20260216_030000.tar.gz" sudo tar -xzf $VOLUME_BACKUP -C /var/lib/docker/volumes/nextcloud_nextcloud_data/_data/ # 8. Restore configs CONFIG_BACKUP="backups/volumes/configs_20260216_030000.tar.gz" sudo tar -xzf $CONFIG_BACKUP -C /opt/nextcloud-stack/configs/ # 9. Fix permissions sudo chown -R www-data:www-data /var/lib/docker/volumes/nextcloud_nextcloud_data/_data/ # 10. Start all services docker compose up -d # 11. Run Nextcloud maintenance docker exec -u www-data next php occ maintenance:mode --off docker exec -u www-data next php occ files:scan --all docker exec -u www-data next php occ db:add-missing-indices # 12. Continue with remaining playbooks exit ansible-playbook playbooks/06-configure-caddy.yml --ask-vault-pass ansible-playbook playbooks/07-setup-backups.yml --ask-vault-pass ansible-playbook playbooks/08-post-deployment.yml --ask-vault-pass ``` --- ## Off-Site Backups with rclone ### Initial Setup ```bash ssh user@server # Configure rclone rclone config # Example: Setup Backblaze B2 # Follow prompts: # - Choose: New remote # - Name: b2backup # - Storage: Backblaze B2 # - Enter account ID and application key ``` ### Sync Backups to Remote ```bash # Test sync (dry run) rclone sync /opt/nextcloud-stack/backups/ b2backup:nextcloud-backups --dry-run # Actual sync rclone sync /opt/nextcloud-stack/backups/ b2backup:nextcloud-backups ``` ### Automated Off-Site Backups Add to `/opt/nextcloud-stack/backup.sh` (after the cleanup section): ```bash # Off-site backup (if rclone configured) if command -v rclone &> /dev/null && rclone listremotes | grep -q "b2backup"; then log "Syncing backups to off-site storage..." rclone sync $BACKUP_DIR b2backup:nextcloud-backups --log-file=$LOG_FILE log "Off-site sync completed" fi ``` ### Restore from Off-Site Backup ```bash # List remote backups rclone ls b2backup:nextcloud-backups/database/ # Download specific backup rclone copy b2backup:nextcloud-backups/database/nextcloud_db_20260216_030000.sql.gz /opt/nextcloud-stack/backups/database/ # Download all backups rclone sync b2backup:nextcloud-backups /opt/nextcloud-stack/backups/ ``` --- ## Backup Verification ### Test Database Backup Integrity ```bash # 1. Extract backup gunzip -c backups/database/nextcloud_db_20260216_030000.sql.gz > /tmp/test_restore.sql # 2. Check for errors grep -i "error" /tmp/test_restore.sql # 3. Verify size (should be reasonable) ls -lh /tmp/test_restore.sql # 4. Cleanup rm /tmp/test_restore.sql ``` ### Test Volume Backup Integrity ```bash # Test tar archive tar -tzf backups/volumes/nextcloud_data_20260216_030000.tar.gz | head -20 # Check for errors tar -tzf backups/volumes/nextcloud_data_20260216_030000.tar.gz > /dev/null && echo "Archive OK" ``` --- ## Migration to New Server **Complete migration guide:** 1. **Prepare new server:** - Same or newer Ubuntu version - Run Ansible setup playbooks (01-04) 2. **Backup old server:** ```bash /opt/nextcloud-stack/backup.sh ``` 3. **Copy backups to new server:** ```bash rsync -avz old-server:/opt/nextcloud-stack/backups/ new-server:/opt/nextcloud-stack/backups/ ``` 4. **Update DNS:** - Point all domains to new server IP - Wait for propagation 5. **Restore on new server:** - Follow "Complete System Restore" steps above 6. **Verify:** - Test all services - Check Nextcloud functionality - Verify SSL certificates 7. **Decommission old server:** - Only after confirming new server works - Keep final backup from old server --- ## Backup Best Practices ### DO: - ✅ Test restores regularly (monthly) - ✅ Keep backups off-site (rclone to cloud storage) - ✅ Verify backup integrity - ✅ Monitor backup log for errors - ✅ Document restore procedures - ✅ Keep multiple backup generations ### DON'T: - ❌ Store backups only on same server - ❌ Assume backups work without testing - ❌ Delete old backups without verification - ❌ Skip database backups - ❌ Ignore backup failure notifications --- ## Backup Schedule Customization Edit `/opt/nextcloud-stack/backup.sh` to change: - Backup frequency - Retention period - What gets backed up - Compression settings Edit cron job: ```bash sudo crontab -e # Change from 3:00 AM to 2:00 AM 0 2 * * * /opt/nextcloud-stack/backup.sh >> /opt/nextcloud-stack/backups/backup.log 2>&1 ``` --- ## Troubleshooting Backups ### Backup script fails **Check logs:** ```bash tail -100 /opt/nextcloud-stack/backups/backup.log ``` **Common issues:** - Disk space full - Docker container not running - Permission denied **Solutions:** ```bash # Check disk space df -h # Check containers docker ps # Fix permissions sudo chown -R root:root /opt/nextcloud-stack/backup.sh sudo chmod +x /opt/nextcloud-stack/backup.sh ``` ### Database backup empty **Verify database is running:** ```bash docker exec next-db pg_isready -U nextcloud ``` **Test manual backup:** ```bash docker exec next-db pg_dump -U nextcloud nextcloud > /tmp/test.sql ls -lh /tmp/test.sql ``` --- ## Emergency Recovery If all backups are lost and you need to start fresh: ```bash # 1. Remove everything ansible-playbook playbooks/99-rollback.yml --ask-vault-pass cd /opt/nextcloud-stack docker compose down -v # 2. Redeploy from scratch ansible-playbook playbooks/site.yml --ask-vault-pass # 3. Reconfigure Nextcloud manually # Login and set up users, apps, etc. ``` --- **Remember:** Backups are worthless unless you've tested restoring from them! **Last Updated:** 2026-02-16