2625cf36d2
- Complete backup script for native Nextcloud (MySQL + files) - Systemd service and timer for daily automated backups at 2 AM - Backblaze B2 integration with secure credential storage - Incremental backup support with 30-day retention - zstd compression for 40-70% storage reduction - Comprehensive documentation and deployment guides - Successfully tested with first backup: 203MB DB + 1.3GB files - Cost-optimized: ~/bin/bash.01-0.02/month for 1.5GB data Deployment Details: - Installed B2 CLI via pipx - Created backup directories at /opt/nextcloud-backup/ - Configured systemd timer for daily execution at 2 AM - First backup verified in B2 bucket: jg-nextcloud - Automated scheduling enabled and tested Documentation includes: - Deployment report with complete setup details - Quick start guide for future deployments - Comprehensive technical reference - Troubleshooting procedures - File manifest and index
446 lines
11 KiB
Markdown
446 lines
11 KiB
Markdown
# Nextcloud to Backblaze B2 Automated Backups
|
|
|
|
Complete guide for setting up automated periodic backups of your Nextcloud instance to Backblaze B2.
|
|
|
|
## Overview
|
|
|
|
This solution provides:
|
|
- **Incremental & full backups** - Smart backup strategy to minimize data transfer
|
|
- **Database + files** - Complete Nextcloud backup including database and data
|
|
- **Automated scheduling** - systemd timer runs daily at 2 AM
|
|
- **Retention management** - Automatic cleanup of backups older than 30 days
|
|
- **Compression** - zstd compression to reduce storage costs
|
|
- **Monitoring** - Status checks and error reporting
|
|
|
|
## Prerequisites
|
|
|
|
### System Requirements
|
|
- Linux host with systemd
|
|
- Docker & Docker Compose (for Nextcloud)
|
|
- B2 CLI tool
|
|
- 10+ GB free disk space for temporary backups
|
|
|
|
### Backblaze B2 Setup
|
|
|
|
1. **Create a Backblaze B2 Account** (if not already done)
|
|
- Sign up at https://www.backblaze.com/b2/cloud-storage/
|
|
|
|
2. **Create a Bucket**
|
|
- In B2 console: Create private bucket named `nextcloud-backups` (or your preference)
|
|
- Note the bucket name
|
|
|
|
3. **Generate API Credentials**
|
|
- Go to Account → App Keys → Create Application Key
|
|
- Recommended settings:
|
|
- **File names** with prefix: `nextcloud-backups/`
|
|
- **Access**: Read & Write
|
|
- **Valid for**: No expiration (or your preference)
|
|
- Save the `Account ID` and `Application Key`
|
|
|
|
### Nextcloud Setup
|
|
|
|
You need to identify:
|
|
- **Nextcloud data path** (usually `/srv/docker/nextcloud/data` or similar)
|
|
- **Database details**:
|
|
- Type (MariaDB or PostgreSQL)
|
|
- Database name (usually `nextcloud`)
|
|
- Database user (usually `nextcloud`)
|
|
- Database password
|
|
|
|
## Installation
|
|
|
|
### Step 1: Install B2 CLI
|
|
|
|
```bash
|
|
# Install B2 command-line tool
|
|
pip3 install b2
|
|
|
|
# Verify installation
|
|
b2 version
|
|
```
|
|
|
|
### Step 2: Create Backup Directory
|
|
|
|
```bash
|
|
sudo mkdir -p /opt/nextcloud-backup
|
|
sudo mkdir -p /etc/nextcloud-backup
|
|
sudo chmod 700 /opt/nextcloud-backup
|
|
sudo chmod 700 /etc/nextcloud-backup
|
|
```
|
|
|
|
### Step 3: Deploy Backup Scripts
|
|
|
|
```bash
|
|
# Copy main backup script
|
|
sudo cp nextcloud-backup-to-backblaze.sh /opt/nextcloud-backup/
|
|
sudo chmod +x /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh
|
|
|
|
# Copy systemd files
|
|
sudo cp nextcloud-backup.service /etc/systemd/system/
|
|
sudo cp nextcloud-backup.timer /etc/systemd/system/
|
|
sudo chmod 644 /etc/systemd/system/nextcloud-backup.*
|
|
|
|
# Reload systemd
|
|
sudo systemctl daemon-reload
|
|
```
|
|
|
|
### Step 4: Configure Environment
|
|
|
|
Create the configuration files:
|
|
|
|
**File: `/opt/nextcloud-backup/.env`**
|
|
```bash
|
|
# Nextcloud configuration
|
|
NEXTCLOUD_COMPOSE_DIR=/path/to/nextcloud/docker-compose
|
|
NEXTCLOUD_DATA_PATH=/srv/docker/nextcloud/data
|
|
NEXTCLOUD_DB_NAME=nextcloud
|
|
NEXTCLOUD_DB_USER=nextcloud
|
|
NEXTCLOUD_DB_PASSWORD=your_db_password_here
|
|
NEXTCLOUD_CONTAINER=nextcloud
|
|
|
|
# Backup configuration
|
|
BACKUP_RETENTION_DAYS=30
|
|
COMPRESSION=zstd
|
|
BACKUP_DIR=/opt/nextcloud-backup/.backups
|
|
```
|
|
|
|
**File: `/etc/nextcloud-backup/b2-credentials.env`** (root-only, no world-readable)
|
|
```bash
|
|
# Backblaze B2 credentials
|
|
B2_ACCOUNT_ID=your_account_id_here
|
|
B2_APPLICATION_KEY=your_application_key_here
|
|
B2_BUCKET_NAME=nextcloud-backups
|
|
B2_REGION=us-west-002
|
|
```
|
|
|
|
Set secure permissions:
|
|
```bash
|
|
sudo chmod 600 /etc/nextcloud-backup/b2-credentials.env
|
|
sudo chown root:root /etc/nextcloud-backup/b2-credentials.env
|
|
```
|
|
|
|
### Step 5: Test the Backup
|
|
|
|
Run a test backup manually:
|
|
|
|
```bash
|
|
# Test with dry-run first
|
|
sudo DRY_RUN=true /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh
|
|
|
|
# Run actual incremental backup
|
|
sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh incremental
|
|
|
|
# Or full backup
|
|
sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh full
|
|
|
|
# Check backup status
|
|
sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh status
|
|
```
|
|
|
|
### Step 6: Enable Automated Backups
|
|
|
|
```bash
|
|
# Enable and start the timer
|
|
sudo systemctl enable nextcloud-backup.timer
|
|
sudo systemctl start nextcloud-backup.timer
|
|
|
|
# Verify it's active
|
|
sudo systemctl status nextcloud-backup.timer
|
|
|
|
# See next scheduled run
|
|
sudo systemctl list-timers nextcloud-backup.timer
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Manual Backup Commands
|
|
|
|
```bash
|
|
# Dry-run (shows what would happen, no actual upload)
|
|
DRY_RUN=true sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh
|
|
|
|
# Incremental backup (only changed files)
|
|
sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh incremental
|
|
|
|
# Full backup (all files)
|
|
sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh full
|
|
|
|
# Check status
|
|
sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh status
|
|
```
|
|
|
|
### View Backup Logs
|
|
|
|
```bash
|
|
# Recent backups
|
|
sudo tail -f /opt/nextcloud-backup/.backups/logs/backup_*.log
|
|
|
|
# Latest backup status
|
|
sudo ls -lh /opt/nextcloud-backup/.backups/logs/ | tail -5
|
|
```
|
|
|
|
### View Systemd Timer Status
|
|
|
|
```bash
|
|
# Timer status
|
|
sudo systemctl status nextcloud-backup.timer
|
|
|
|
# Last run results
|
|
sudo journalctl -u nextcloud-backup.service -n 50
|
|
|
|
# Live monitoring
|
|
sudo journalctl -u nextcloud-backup.service -f
|
|
```
|
|
|
|
## Backup Strategy
|
|
|
|
### Incremental vs Full
|
|
|
|
- **Incremental** (default, runs daily):
|
|
- Only backs up files changed since last backup
|
|
- Faster, saves bandwidth and storage
|
|
- Requires full backup to restore
|
|
|
|
- **Full** (recommended weekly):
|
|
- Backs up all files regardless of changes
|
|
- Slower but complete snapshot
|
|
- Standalone restore capability
|
|
|
|
### Recommended Schedule
|
|
|
|
```
|
|
Monday-Saturday: Incremental (02:00 AM)
|
|
Sunday: Full backup (02:00 AM)
|
|
```
|
|
|
|
To implement this, modify the `.timer` file's `OnCalendar` line:
|
|
```ini
|
|
OnCalendar=Mon-Sat *-*-* 02:00:00
|
|
OnCalendar=Sun *-*-* 02:00:00
|
|
```
|
|
|
|
## Monitoring and Alerts
|
|
|
|
### Check Backup Status
|
|
|
|
```bash
|
|
# List recent backups
|
|
sudo b2 list-file-names nextcloud-backups nextcloud-backups/
|
|
|
|
# Get total backup size
|
|
sudo b2 list-file-names nextcloud-backups nextcloud-backups/ | \
|
|
jq '[.[] | .contentLength] | add | . / 1024 / 1024 / 1024' \
|
|
echo "Total: $size GB"
|
|
```
|
|
|
|
### Monitor via Systemd
|
|
|
|
```bash
|
|
# Check last 10 backup runs
|
|
sudo journalctl -u nextcloud-backup.service --reverse | head -50
|
|
|
|
# Count successful vs failed backups
|
|
sudo journalctl -u nextcloud-backup.service | grep "SUCCESS\|ERROR" | wc -l
|
|
```
|
|
|
|
### Set up Email Alerts (Optional)
|
|
|
|
Install and configure `postfix` or `ssmtp`, then add to the backup script:
|
|
|
|
```bash
|
|
# On backup failure, send email
|
|
if ! run_backup; then
|
|
echo "Nextcloud backup failed at $(date)" | \
|
|
mail -s "Nextcloud Backup Failed" admin@example.com
|
|
fi
|
|
```
|
|
|
|
## Restoring from Backup
|
|
|
|
### List Available Backups
|
|
|
|
```bash
|
|
b2 list-file-names nextcloud-backups nextcloud-backups/ | \
|
|
jq -r '.fileName + " (" + (.contentLength | . / 1024 / 1024 | floor | tostring) + " MB)"'
|
|
```
|
|
|
|
### Restore Database
|
|
|
|
```bash
|
|
# Download database backup
|
|
b2 download-file-by-id nextcloud-backups \
|
|
<file-id> ./nextcloud-db-backup.sql.zst
|
|
|
|
# Restore to database
|
|
zstd -d nextcloud-db-backup.sql.zst -c | \
|
|
mysql -u root -p nextcloud
|
|
|
|
# Or for PostgreSQL:
|
|
zstd -d nextcloud-db-backup.sql.zst -c | \
|
|
psql -U postgres nextcloud
|
|
```
|
|
|
|
### Restore Files
|
|
|
|
```bash
|
|
# Download file archive
|
|
b2 download-file-by-id nextcloud-backups \
|
|
<file-id> ./nextcloud-files-backup.tar.zst
|
|
|
|
# Extract to temporary location
|
|
mkdir -p /tmp/nextcloud-restore
|
|
tar --zstd -xf nextcloud-files-backup.tar.zst -C /tmp/nextcloud-restore
|
|
|
|
# Review and copy back
|
|
cp -r /tmp/nextcloud-restore/srv/docker/nextcloud/data/* \
|
|
/srv/docker/nextcloud/data/
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### B2 Authentication Errors
|
|
|
|
```bash
|
|
# Clear cached auth
|
|
rm ~/.b2_account_info
|
|
|
|
# Re-authenticate
|
|
b2 authorize-account YOUR_ACCOUNT_ID YOUR_APP_KEY
|
|
|
|
# Test connection
|
|
b2 account-info
|
|
```
|
|
|
|
### Backup Size Issues
|
|
|
|
If backups are too large:
|
|
1. Check for duplicate/cache files in Nextcloud data
|
|
2. Enable deduplication in B2 console
|
|
3. Increase `BACKUP_RETENTION_DAYS` to allow fewer concurrent backups
|
|
|
|
### Permission Denied Errors
|
|
|
|
Ensure the backup script runs as root and has access to:
|
|
- Docker socket (for database dumps)
|
|
- Nextcloud data directory
|
|
- Temporary directory
|
|
|
|
### Database Connection Issues
|
|
|
|
Verify database credentials and that the container is running:
|
|
|
|
```bash
|
|
# Check if database container is running
|
|
docker-compose -f /path/to/nextcloud/docker-compose.yml ps
|
|
|
|
# Test database connection
|
|
docker-compose -f /path/to/nextcloud/docker-compose.yml exec -T mariadb \
|
|
mysql -u nextcloud -p${NEXTCLOUD_DB_PASSWORD} -e "SELECT 1"
|
|
```
|
|
|
|
## Cost Optimization
|
|
|
|
### Backblaze B2 Pricing
|
|
|
|
As of 2024:
|
|
- Storage: $0.006/GB/month
|
|
- Downloads: $0.003/GB (first 1GB free daily)
|
|
- API calls: $0.0004 per 1000 calls
|
|
|
|
### Optimize Costs
|
|
|
|
1. **Compression**: zstd reduces size by 40-70%
|
|
2. **Retention**: Keep only 30 days of backups
|
|
3. **Incremental**: Daily incremental + weekly full = smaller total size
|
|
4. **Deduplication**: Enable in B2 for identical blocks
|
|
|
|
Example: 100GB Nextcloud → ~30-40GB compressed → $0.18-0.24/month storage
|
|
|
|
## Maintenance
|
|
|
|
### Monthly Checks
|
|
|
|
```bash
|
|
# Verify backup integrity
|
|
sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh status
|
|
|
|
# Check logs for errors
|
|
sudo grep "ERROR" /opt/nextcloud-backup/.backups/logs/*.log
|
|
|
|
# Verify B2 credentials still valid
|
|
sudo b2 account-info
|
|
```
|
|
|
|
### Update Schedule
|
|
|
|
- Check for B2 CLI updates monthly
|
|
- Review Backblaze pricing changes quarterly
|
|
- Test restore procedure every 6 months
|
|
|
|
## Advanced Configuration
|
|
|
|
### Custom Backup Schedule
|
|
|
|
Edit `/etc/systemd/system/nextcloud-backup.timer`:
|
|
|
|
```ini
|
|
# Run at 2 AM and 2 PM daily
|
|
OnCalendar=*-*-* 02:00:00
|
|
OnCalendar=*-*-* 14:00:00
|
|
|
|
# Or more complex: Mon-Fri 2 AM, weekends 4 AM
|
|
OnCalendar=Mon-Fri *-*-* 02:00:00
|
|
OnCalendar=Sat,Sun *-*-* 04:00:00
|
|
```
|
|
|
|
Then reload:
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl restart nextcloud-backup.timer
|
|
```
|
|
|
|
### Exclude Directories
|
|
|
|
Modify the `get_changed_files()` function in the script:
|
|
|
|
```bash
|
|
find "${NEXTCLOUD_DATA_PATH}" -type f \
|
|
! -path '*/.*' \
|
|
! -path '*/cache/*' \
|
|
! -path '*/preview/*' \
|
|
> "$manifest_file"
|
|
```
|
|
|
|
### Pre/Post Backup Hooks
|
|
|
|
Add to the script before/after backup:
|
|
|
|
```bash
|
|
# Before backup
|
|
if [ -x /opt/nextcloud-backup/pre-backup-hook.sh ]; then
|
|
/opt/nextcloud-backup/pre-backup-hook.sh
|
|
fi
|
|
|
|
# ... backup logic ...
|
|
|
|
# After backup
|
|
if [ -x /opt/nextcloud-backup/post-backup-hook.sh ]; then
|
|
/opt/nextcloud-backup/post-backup-hook.sh
|
|
fi
|
|
```
|
|
|
|
## References
|
|
|
|
- [Backblaze B2 Documentation](https://www.backblaze.com/b2/docs/)
|
|
- [B2 CLI Reference](https://github.com/Backblaze/B2_Command_Line_Tool)
|
|
- [Nextcloud Backup Guide](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ/maintenance.html)
|
|
- [systemd Timer Documentation](https://www.freedesktop.org/software/systemd/man/systemd.timer.html)
|
|
|
|
## Support
|
|
|
|
For issues:
|
|
1. Check logs: `journalctl -u nextcloud-backup.service -n 100`
|
|
2. Verify configuration: `cat /opt/nextcloud-backup/.env`
|
|
3. Test manually: `sudo /opt/nextcloud-backup/nextcloud-backup-to-backblaze.sh status`
|
|
4. Check B2 credentials: `b2 account-info`
|