diff --git a/minio_backup/README.md b/minio_backup/README.md deleted file mode 100644 index a5f2c91..0000000 --- a/minio_backup/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# MinIO Backup Add-on - -This add-on automatically creates Home Assistant backups, stores them on a MinIO -(S3-compatible) server, and manages retention for daily and monthly backups. - -### Features -- Automatic daily and monthly backups -- Retention control (default: 3 daily, 12 monthly) -- Optional AES-256 encryption -- Upload to MinIO / S3-compatible servers -- Uses Supervisor API for snapshot creation - -### Decryption (if encryption is enabled) -openssl enc -d -aes-256-cbc -pbkdf2 -in backup.tar.enc -out backup.tar -k "PASSWORD" - -### Configuration options -- `minio_endpoint` – MinIO server URL -- `minio_access_key` -- `minio_secret_key` -- `minio_bucket` -- `daily_to_keep` -- `monthly_to_keep` -- `encryption_enabled` – true/false -- `encryption_password` diff --git a/minio_backup/config.json b/minio_backup/config.json deleted file mode 100644 index 3314f05..0000000 --- a/minio_backup/config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "MinIO Backup", - "version": "1.0.0", - "slug": "minio_backup", - "startup": "application", - "description": "Automatic Home Assistant backups to a MinIO S3 server with retention and optional AES-256 encryption.", - "arch": ["aarch64", "amd64"], - "schema": { - "minio_endpoint": "str", - "minio_access_key": "str", - "minio_secret_key": "str", - "minio_bucket": "str", - "daily_to_keep": "int", - "monthly_to_keep": "int", - "daily_time": "str", - "encryption_enabled": "bool", - "encryption_password": "str" - }, - "options": { - "minio_endpoint": "https://your-minio-server.com", - "minio_access_key": "", - "minio_secret_key": "", - "minio_bucket": "ha-backup", - "daily_to_keep": 3, - "monthly_to_keep": 12, - "daily_time": "03:00", - "encryption_enabled": true, - "encryption_password": "" - } -} diff --git a/minio_backup/dockerfile b/minio_backup/dockerfile deleted file mode 100644 index ace8075..0000000 --- a/minio_backup/dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM python:3.11-slim - -RUN apt-get update && apt-get install -y openssl && apt-get clean - -WORKDIR /app -COPY run.py /app/run.py - -RUN pip install requests boto3 - -CMD ["python", "/app/run.py"] diff --git a/minio_backup/run.py b/minio_backup/run.py deleted file mode 100644 index aee5342..0000000 --- a/minio_backup/run.py +++ /dev/null @@ -1,96 +0,0 @@ -import os, time, json, requests, boto3, subprocess -from datetime import datetime - -SUPERVISOR_TOKEN = os.environ.get("SUPERVISOR_TOKEN") -HEADERS = {"Authorization": f"Bearer {SUPERVISOR_TOKEN}"} - -def load_cfg(): - with open("/data/options.json") as f: - return json.load(f) - -def create_backup(): - name = f"auto_backup_{datetime.now().strftime('%Y-%m-%d_%H-%M')}" - r = requests.post( - "http://supervisor/supervisor/backups", - headers=HEADERS, - json={"name": name} - ) - r.raise_for_status() - return r.json()["slug"] - -def download_backup(slug, path="/tmp/backup.tar"): - dl = requests.get( - f"http://supervisor/supervisor/backups/{slug}/download", - headers=HEADERS, - stream=True - ) - dl.raise_for_status() - with open(path, "wb") as f: - for chunk in dl.iter_content(1024 * 64): - f.write(chunk) - return path - -def encrypt_backup(input_path, password): - output_path = input_path + ".enc" - subprocess.run([ - "openssl", "enc", "-aes-256-cbc", - "-salt", "-pbkdf2", - "-k", password, - "-in", input_path, - "-out", output_path - ], check=True) - return output_path - -def upload_minio(path, cfg, backup_type): - s3 = boto3.client( - "s3", - aws_access_key_id=cfg["minio_access_key"], - aws_secret_access_key=cfg["minio_secret_key"], - endpoint_url=cfg["minio_endpoint"] - ) - key = f"{backup_type}/backup_{int(time.time())}{os.path.splitext(path)[1]}" - s3.upload_file(path, cfg["minio_bucket"], key) - print(f"[OK] Uploaded: {key}") - cleanup_retention(s3, cfg["minio_bucket"], backup_type, cfg) - -def cleanup_retention(s3, bucket, backup_type, cfg): - prefix = f"{backup_type}/" - keep = cfg["monthly_to_keep"] if backup_type == "monthly" else cfg["daily_to_keep"] - objs = s3.list_objects_v2(Bucket=bucket, Prefix=prefix).get("Contents", []) - if len(objs) <= keep: - return - objs.sort(key=lambda x: x["LastModified"]) - to_delete = objs[:-keep] - for o in to_delete: - s3.delete_object(Bucket=bucket, Key=o["Key"]) - print(f"[CLEAN] Deleted old backup: {o['Key']}") - -def main(): - cfg = load_cfg() - backup_type = "monthly" if datetime.now().day == 1 else "daily" - - print("[INFO] Creating backup…") - slug = create_backup() - - print("[INFO] Downloading backup…") - path = download_backup(slug) - - # optional encryption - if cfg.get("encryption_enabled") and cfg.get("encryption_password"): - print("[INFO] Encrypting with AES-256…") - path = encrypt_backup(path, cfg["encryption_password"]) - else: - print("[INFO] Encryption disabled.") - - print("[INFO] Uploading to MinIO…") - upload_minio(path, cfg, backup_type) - - try: - os.remove(path) - except: - pass - - print("[DONE] Backup process finished.") - -if __name__ == "__main__": - main()