Last active
December 6, 2025 16:27
-
-
Save zuedev/bdcda6ef2472acd96bb09ac544122ab6 to your computer and use it in GitHub Desktop.
Automated Restic Backup to Backblaze B2 via Docker: A single Bash script to initialize a Restic repository (if needed) and run a full, excluded, read-only backup of a Linux host's root filesystem (`/`) to Backblaze B2 using the official Docker image and S3-compatible API.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # --- 1. CONFIGURATION --- | |
| # Replace these placeholders with your actual values. | |
| # Backblaze B2 S3 Credentials | |
| export AWS_ACCESS_KEY_ID="YOUR_B2_KEY_ID" | |
| export AWS_SECRET_ACCESS_KEY="YOUR_B2_APPLICATION_KEY" | |
| # Restic Repository Details | |
| export RESTIC_REPOSITORY="s3:s3.eu-central-003.backblazeb2.com/sovereign-restic-backup" | |
| export RESTIC_PASSWORD="YOUR_REPOSITORY_PASSWORD" | |
| # Backup Parameters | |
| HOST_TAG="YOUR_HOST_TAG" | |
| BACKUP_SOURCE="/sovereign" | |
| # Host Path to the Exclude File (This path is on the HOST machine) | |
| HOST_EXCLUDE_FILE="/etc/restic-exclude" | |
| # Docker Parameters | |
| IMAGE_NAME="restic/restic:latest" | |
| VOLUME_MOUNT="/:/sovereign:ro" | |
| # --- 2. DYNAMIC COMMAND CONSTRUCTION (THE FIX) --- | |
| # Check if the exclude file exists on the HOST. | |
| # If it exists, set the flag to include it in the Restic command. | |
| # The path used here (inside the quotes) is the path *inside the container*. | |
| EXCLUDE_FLAG="" | |
| if [ -f "$HOST_EXCLUDE_FILE" ]; then | |
| echo "Exclusion file found on host at $HOST_EXCLUDE_FILE. Including in backup." | |
| EXCLUDE_FLAG="--exclude-file ${BACKUP_SOURCE}/etc/restic-exclude" | |
| else | |
| echo "WARNING: Exclusion file not found at $HOST_EXCLUDE_FILE. Skipping --exclude-file flag." | |
| fi | |
| # --- 3. RESTIC INITIALIZATION CHECK --- | |
| echo "Checking Restic repository status..." | |
| # Attempt to check the repository. Redirect output to /dev/null to keep things clean. | |
| docker run --rm \ | |
| -e AWS_ACCESS_KEY_ID \ | |
| -e AWS_SECRET_ACCESS_KEY \ | |
| -e RESTIC_REPOSITORY \ | |
| -e RESTIC_PASSWORD \ | |
| "${IMAGE_NAME}" snapshots &> /dev/null | |
| INIT_STATUS=$? | |
| # If the status is not 0 (success), attempt to initialize the repository. | |
| if [ "$INIT_STATUS" -ne 0 ]; then | |
| echo "Repository check failed (Exit Code: $INIT_STATUS). Attempting initialization (init)..." | |
| # Run the initialization command | |
| docker run --rm \ | |
| -e AWS_ACCESS_KEY_ID \ | |
| -e AWS_SECRET_ACCESS_KEY \ | |
| -e RESTIC_REPOSITORY \ | |
| -e RESTIC_PASSWORD \ | |
| "${IMAGE_NAME}" init | |
| # Check the result of the 'init' command | |
| if [ $? -ne 0 ]; then | |
| echo "======================================================================" | |
| echo "FATAL ERROR: Restic repository initialization failed." | |
| echo "Please verify your B2 credentials and RESTIC_REPOSITORY path." | |
| echo "======================================================================" | |
| exit 1 | |
| fi | |
| echo "Initialization successful. Proceeding to backup." | |
| fi | |
| # --- 4. RESTIC BACKUP --- | |
| echo "Starting backup of ${BACKUP_SOURCE}..." | |
| # Full backup command. Note the dynamic use of $EXCLUDE_FLAG. | |
| docker run --rm \ | |
| -e AWS_ACCESS_KEY_ID \ | |
| -e AWS_SECRET_ACCESS_KEY \ | |
| -e RESTIC_REPOSITORY \ | |
| -e RESTIC_PASSWORD \ | |
| --volume "${VOLUME_MOUNT}" \ | |
| "${IMAGE_NAME}" backup "${BACKUP_SOURCE}" \ | |
| --tag "${HOST_TAG}" \ | |
| ${EXCLUDE_FLAG} \ | |
| --exclude "${BACKUP_SOURCE}/proc" \ | |
| --exclude "${BACKUP_SOURCE}/sys" \ | |
| --exclude "${BACKUP_SOURCE}/dev" \ | |
| --exclude "${BACKUP_SOURCE}/run" \ | |
| --exclude "${BACKUP_SOURCE}/tmp" | |
| if [ $? -eq 0 ]; then | |
| echo "Backup completed successfully. 🎉" | |
| else | |
| echo "ERROR: Restic backup failed. ❌" | |
| fi | |
| # --- 5. PRUNE (Optional) --- | |
| : ' | |
| # Prune logic remains the same (uncomment to enable) | |
| echo "Starting prune operation..." | |
| docker run --rm \ | |
| -e AWS_ACCESS_KEY_ID \ | |
| -e AWS_SECRET_ACCESS_KEY \ | |
| -e RESTIC_REPOSITORY \ | |
| -e RESTIC_PASSWORD \ | |
| "${IMAGE_NAME}" forget \ | |
| --tag "${HOST_TAG}" \ | |
| --prune \ | |
| --keep-hourly 24 \ | |
| --keep-daily 7 \ | |
| --keep-monthly 12 | |
| if [ $? -eq 0 ]; then | |
| echo "Pruning completed successfully." | |
| else | |
| echo "WARNING: Restic prune failed." | |
| fi | |
| ' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment