DEV Community

Brad
Brad

Posted on

Python Backup Automation: Never Lose Data Again (Free Alternative to BackBlaze)

BackBlaze costs $99/year. Building your own backup system with Python takes about 100 lines and costs almost nothing.

Incremental Backup Engine

Only back up files that have changed:

import hashlib
import shutil
import json
from pathlib import Path
from datetime import datetime

MANIFEST = Path.home() / '.backups' / 'manifest.json'

def file_hash(path: Path) -> str:
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            h.update(chunk)
    return h.hexdigest()

def load_manifest() -> dict:
    if MANIFEST.exists():
        with open(MANIFEST) as f:
            return json.load(f)
    return {}

def backup_directory(source: Path, dest: Path) -> dict:
    manifest = load_manifest()
    source_key = str(source)
    if source_key not in manifest:
        manifest[source_key] = {}

    stats = {"new": 0, "updated": 0, "unchanged": 0}
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_dest = dest / timestamp

    for file in source.rglob('*'):
        if not file.is_file():
            continue
        rel_path = file.relative_to(source)
        current_hash = file_hash(file)
        cached_hash = manifest[source_key].get(str(rel_path))

        if cached_hash == current_hash:
            stats["unchanged"] += 1
            continue

        stats["updated" if cached_hash else "new"] += 1
        target = backup_dest / rel_path
        target.parent.mkdir(parents=True, exist_ok=True)
        shutil.copy2(file, target)
        manifest[source_key][str(rel_path)] = current_hash

    json.dump(manifest, open(MANIFEST, 'w'), indent=2)
    return stats
Enter fullscreen mode Exit fullscreen mode

Upload to S3 (Optional)

import boto3

def upload_to_s3(local_dir: Path, bucket: str, prefix: str):
    s3 = boto3.client('s3')
    uploaded = 0
    for file in local_dir.rglob('*'):
        if file.is_file():
            key = f'{prefix}/{file.relative_to(local_dir)}'
            s3.upload_file(str(file), bucket, key)
            uploaded += 1
    print(f"Uploaded {uploaded} files to s3://{bucket}/{prefix}")
Enter fullscreen mode Exit fullscreen mode

Email Alerts on Failure

import smtplib
from email.mime.text import MIMEText

def send_backup_alert(success: bool, stats: dict, email: str):
    status = "SUCCESS" if success else "FAILED"
    body = f"""Backup Report:\nNew: {stats["new"]}\nUpdated: {stats["updated"]}\nUnchanged: {stats["unchanged"]}"""
    msg = MIMEText(body)
    msg['Subject'] = f'Backup {status}'
    msg['From'] = email
    msg['To'] = email
    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
        server.login(email, "your_app_password")
        server.send_message(msg)
Enter fullscreen mode Exit fullscreen mode

Schedule with Cron

# Back up Documents daily at 2am
0 2 * * * /usr/bin/python3 /home/user/backup.py
Enter fullscreen mode Exit fullscreen mode

Full Python Business Automation

This backup script is part of the Python Business Automation Toolkit - 50+ scripts covering backup, invoicing, CRM, email automation, and more. One-time $29.

How do you handle backups? Manual, cloud service, or DIY? Share in the comments.

Top comments (0)