Files
homelab-configs/NEXTCLOUD_BACKBLAZE_SETUP.md
T
jgitta 2625cf36d2 Add: Nextcloud Backblaze B2 backup solution - automated daily backups
- 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
2026-04-25 18:00:07 -05:00

11 KiB

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)

  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

# Install B2 command-line tool
pip3 install b2

# Verify installation
b2 version

Step 2: Create Backup Directory

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

# 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

# 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)

# 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:

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:

# 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

# 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

# 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

# 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

# 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
Monday-Saturday: Incremental (02:00 AM)
Sunday: Full backup (02:00 AM)

To implement this, modify the .timer file's OnCalendar line:

OnCalendar=Mon-Sat *-*-* 02:00:00
OnCalendar=Sun *-*-* 02:00:00

Monitoring and Alerts

Check Backup Status

# 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

# 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:

# 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

b2 list-file-names nextcloud-backups nextcloud-backups/ | \
  jq -r '.fileName + " (" + (.contentLength | . / 1024 / 1024 | floor | tostring) + " MB)"'

Restore Database

# 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

# 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

# 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:

# 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

# 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:

# 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:

sudo systemctl daemon-reload
sudo systemctl restart nextcloud-backup.timer

Exclude Directories

Modify the get_changed_files() function in the script:

find "${NEXTCLOUD_DATA_PATH}" -type f \
  ! -path '*/.*' \
  ! -path '*/cache/*' \
  ! -path '*/preview/*' \
  > "$manifest_file"

Pre/Post Backup Hooks

Add to the script before/after backup:

# 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

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