Skip to content

Instantly share code, notes, and snippets.

@cs224
Last active March 10, 2025 05:50
Show Gist options
  • Save cs224/34eebc2f9389404d7c0192d45cae7259 to your computer and use it in GitHub Desktop.
Save cs224/34eebc2f9389404d7c0192d45cae7259 to your computer and use it in GitHub Desktop.
Home Server Blueprint: Rock-Solid Home Server with Unattended Reboots, Secure Disk Encryption, and Cost-Effective Offsite Backups
# .env file
# Secret (avoid storing real secrets in version control!)
KOPIA_REPOSITORY_SECRET=mysupersecret
LUKS_PASSPHRASE=abc123
# Toggle alerting
ALERT_ENABLED=false
# Pushover credentials
PUSHOVER_TOKEN=your_pushover_token
PUSHOVER_USER=your_pushover_user_key
# Daily backup time e.g. 04:00:00 for 4 AM
DAILY_BACKUP_TIME=*-*-* 04:00:00
# Etc.
[Unit]
Description=BTRFS to Kopia Backup (Offsite)
Requires=network-online.target
After=network-online.target
[Service]
Type=oneshot
Environment=HOME="/root"
ExecStart=/usr/local/bin/btrfs-kopia-backup.sh
#!/usr/bin/env bash
# ---------------------------------------------------------
# btrfs-kopia-backup.sh
#
# 1) Create a read-only BTRFS snapshot
# 2) Run a Kopia snapshot
# 3) Rename the snapshot with a date/time suffix
# 4) (Optional) Send a Pushover alert if something fails
# ---------------------------------------------------------
set -e
###############################################################################
# CONFIG SECTION
#
# Toggle this to "true" to enable Pushover alerts on error, or to "false" (or
# comment out) if you do not want alerts.
###############################################################################
ALERT_ENABLED=true
###############################################################################
# "I am alive" message configuration
# Possible values: "daily", "weekly", "monthly", or anything else means "false"
###############################################################################
ALIVE_MESSAGE_ENABLED="false"
# Pushover credentials (DO NOT store secrets in version control!)
PUSHOVER_TOKEN="...sometoken..."
PUSHOVER_USER="...someuser..."
###############################################################################
# Pushover function
# You can comment out the entire function if you never want to use it,
# or just set ALERT_ENABLED=false above.
###############################################################################
function pushover_alert() {
local message="$1"
local title="$2"
# If your Pushover config includes more data (HTML, link, etc.), adapt as needed
curl -s --fail \
-F "token=${PUSHOVER_TOKEN}" \
-F "user=${PUSHOVER_USER}" \
-F "sound=none" \
-F "title=${title}" \
-F "message=${message}" \
-F "html=1" \
https://api.pushover.net/1/messages.json \
|| echo "Warning: Failed to send Pushover alert (curl error)."
}
###############################################################################
# Error Handler
# This function is called automatically on any command error
# (because of 'set -e' plus the 'trap' directive).
###############################################################################
function error_handler() {
local exit_code=$?
local line_no=$1
echo "ERROR: Backup script failed at line ${line_no}. Exit code: ${exit_code}"
if [ "$ALERT_ENABLED" = "true" ]; then
# Build an alert message. Adjust to taste:
pushover_alert \
"Backup on host $(hostname) failed at line ${line_no} (exit code ${exit_code})" \
"BTRFS-Kopia Backup Failed"
fi
# Exit with the same code to signal failure
exit "$exit_code"
}
# If alerts are enabled, set a trap to catch errors and call 'error_handler'
if [ "$ALERT_ENABLED" = "true" ]; then
trap 'error_handler $LINENO' ERR
fi
###############################################################################
# Main Backup Logic
###############################################################################
SRC_SUBVOL="/mnt/luks_btrfs_volume/@offsite_backup_storage"
SNAP_DEST="/mnt/luks_btrfs_volume/@offsite_backup_storage_backup-snap"
echo "Creating read-only BTRFS snapshot...: btrfs subvolume snapshot -r ${SRC_SUBVOL} ${SNAP_DEST}"
btrfs subvolume snapshot -r "$SRC_SUBVOL" "$SNAP_DEST"
echo "Running Kopia snapshot...: /usr/bin/kopia snapshot create --parallel=1 ${SNAP_DEST} "
/usr/bin/kopia snapshot create --parallel=1 "$SNAP_DEST"
TIMESTAMP="$(date +%Y-%m-%d-%H%M)"
NEW_NAME="/mnt/luks_btrfs_volume/@offsite_backup_storage_snapshot-${TIMESTAMP}"
echo "Renaming snapshot to $NEW_NAME"
mv "$SNAP_DEST" "$NEW_NAME"
echo "Backup completed successfully!"
# Optionally send an "I am alive" message if enabled and successful
if [ "$ALERT_ENABLED" = "true" ]; then
day_of_week="$(date +%u)" # Monday=1 ... Sunday=7
day_of_month="$(date +%d)" # 01..31
case "$ALIVE_MESSAGE_ENABLED" in
daily)
pushover_alert \
"Backup on host $(hostname) completed successfully." \
"BTRFS-Kopia Backup Succeeded"
;;
weekly)
if [ "$day_of_week" = "1" ]; then
pushover_alert \
"Backup on host $(hostname) completed successfully (weekly check)." \
"BTRFS-Kopia Backup Succeeded"
fi
;;
monthly)
if [ "$day_of_month" = "01" ]; then
pushover_alert \
"Backup on host $(hostname) completed successfully (monthly check)." \
"BTRFS-Kopia Backup Succeeded"
fi
;;
*)
# No "alive" messages if set to anything else
;;
esac
fi
[Unit]
Description=Daily BTRFS to Kopia Backup at 4:00 AM
[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true
[Install]
WantedBy=timers.target
# <mapped_name> <source> <keyfile> <options>
luks_btrfs_volume /opt/luks-btrfs-volume.img none luks,noauto,loop,timeout=120
[Unit]
RequiresMountsFor=/opt/docker_services
After=opt-docker_services.mount
# <file system> <mount point> <type> <options> <dump> <pass>
/dev/mapper/luks_btrfs_volume /mnt/luks_btrfs_volume btrfs noauto,x-systemd.automount,relatime,compress=zstd:3,defaults 0 0
/mnt/luks_btrfs_volume/@offsite_backup_storage/storage /opt/offsite_backup_storage none bind,noauto,x-systemd.automount,x-systemd.requires=/mnt/luks_btrfs_volume,x-systemd.after=/mnt/luks_btrfs_volume 0 0
/mnt/luks_btrfs_volume/@offsite_backup_storage/docker_services /opt/docker_services none bind,noauto,x-systemd.automount,x-systemd.requires=/opt/offsite_backup_storage,x-systemd.after=/opt/offsite_backup_storage 0 0
###############################################################################
# Makefile for setting up a LUKS-encrypted BTRFS volume, Docker systemd override,
# and Kopia/Rclone backup infrastructure on a Debian/Ubuntu-based system.
#
# USAGE:
# 1) Set any desired environment variables in ".env".
# 2) Run "make all" to perform the entire setup.
# 3) If a step fails, fix the issue and re-run "make all"; it will continue
# from where it left off.
#
# OPTIONAL TARGETS (not part of "make all"):
# make kopia-repository-create
# make kopia-repository-connect
#
# NOTES / RECOMMENDATIONS FOR CUSTOMIZATION:
# - Adjust volume size (IMG_SIZE) below.
# - If you want to store your LUKS file in a different location, change
# LUKS_BTRFS_IMG and LUKS_BTRFS_NAME accordingly.
# - If you need to pass other arguments to cryptsetup, adjust LUKS_FORMAT_OPTS.
# - Tweak subvolume paths, Docker override paths, or systemd unit install paths
# as you see fit.
# - The .env file is used for "offline templating" of some files (like
# btrfs-kopia-backup.timer and btrfs-kopia-backup.sh). Once the Makefile
# finishes, you can remove .env (unless you need to re-run the Makefile and
# want the same settings).
###############################################################################
SHELL := /bin/bash
#
# 1) Load environment variables from .env (if present).
# We assume simple KEY=VALUE lines with no spaces.
#
ifneq ("$(wildcard .env)","")
include .env
# export $(shell sed 's/=.*//' .env)
# This way, lines that start with # or don’t have an = sign are safely ignored.
export $(shell grep -E '^[[:alnum:]_]+=' .env | cut -d= -f1)
endif
###############################################################################
# CONFIGURABLE VARIABLES (can be overridden in .env or via environment)
###############################################################################
HOSTNAME ?= $(shell hostname)
# you can set in .env or pass from CLI: LUKS_PASSPHRASE=abc123
LUKS_PASSPHRASE ?= abc123
# The size of the LUKS volume image:
IMG_SIZE ?= 100G
# Path and name of the LUKS volume image:
LUKS_BTRFS_IMG ?= /opt/luks-btrfs-volume.img
# Mapped name inside /dev/mapper:
LUKS_BTRFS_NAME ?= luks_btrfs_volume
# Subvolume directory name inside /mnt/luks_btrfs_volume:
BTRFS_SUBVOLUME ?= @offsite_backup_storage
# Additional sub-dirs that will hold persistent data:
DOCKER_SERVICES ?= docker_services
OFFSITE_STORAGE ?= storage
# Where it will be mounted (on-demand, after LUKS password is given):
LUKS_MOUNTPOINT ?= /mnt/luks_btrfs_volume
# Docker data mount point:
DOCKER_DIR ?= /opt/docker_services
# Offsite data mount point:
OFFSITE_DIR ?= /opt/offsite_backup_storage
# Default cryptsetup format options (adjust if needed):
LUKS_FORMAT_OPTS ?= --type luks2 -y -v
# Global policy for Kopia (some recommended settings):
KOPIA_POLICY_PARALLELISM ?= --max-parallel-snapshots=1 --max-parallel-file-reads=1
KOPIA_POLICY_RETENTION ?= --keep-latest=7 --keep-hourly=0 --keep-daily=14 --keep-weekly=4 --keep-monthly=12 --keep-annual=3
KOPIA_POLICY_COMPRESSION ?= --compression=pgzip
# A directory for stamp files to track progress:
STAMP_DIR ?= .stamp
# The time for the daily backup from the .env or fallback:
# e.g., "*-*-* 04:00:00" for daily at 4 AM
DAILY_BACKUP_TIME ?= *-*-* 04:00:00
# The Kopia repository password from .env
# e.g.: KOPIA_REPOSITORY_SECRET=...mysecret...
KOPIA_REPOSITORY_SECRET ?= CHANGEME
###############################################################################
# HELPER CONFIG / DO NOT CHANGE UNLESS YOU KNOW WHAT YOU'RE DOING
###############################################################################
APT_UPDATED_STAMP := $(STAMP_DIR)/apt-updated
CRYPTSETUP_INSTALLED := $(STAMP_DIR)/cryptsetup-installed
RCLONE_INSTALLED := $(STAMP_DIR)/rclone-installed
KOPIA_INSTALLED := $(STAMP_DIR)/kopia-installed
LUKS_VOLUME_IMG_CREATED := $(STAMP_DIR)/luks-volume-img-created
LUKS_FORMATTED_STAMP := $(STAMP_DIR)/luks-formatted
LUKS_OPENED_STAMP := $(STAMP_DIR)/luks-opened
BTRFS_FORMATTED_STAMP := $(STAMP_DIR)/btrfs-formatted
BTRFS_SUBVOL_CREATED := $(STAMP_DIR)/btrfs-subvol-created
SYSTEMD_CONFIG_INSTALLED := $(STAMP_DIR)/systemd-config-installed
KOPIA_POLICY_STAMP := $(STAMP_DIR)/kopia-policy
MKDIR_OPT_DOCKER := $(STAMP_DIR)/mkdir-opt-docker
MKDIR_OPT_OFFSITE := $(STAMP_DIR)/mkdir-opt-offsite
# For convenience, define directories we want:
DIRS_TO_CREATE = $(DOCKER_DIR) $(OFFSITE_DIR) $(STAMP_DIR)
.PHONY: all
all: \
apt-update \
install-cryptsetup \
install-rclone \
install-kopia \
$(LUKS_BTRFS_IMG) \
luks-format \
luks-open \
btrfs-format \
btrfs-subvolume \
mkdirs \
install-systemd-configs
# kopia-global-policy
@echo "Setup complete!"
@echo "You may now check your systemd configurations, crypttab, and fstab."
@echo "Remember that after a reboot, the encrypted volume remains locked until you provide the password."
@echo "Once the system is up, run: systemctl start docker.service"
@echo "That will trigger the full chain of systemd dependencies requiring the LUKS passphrase."
###############################################################################
# STEP: apt update
###############################################################################
.PHONY: apt-update
apt-update: $(APT_UPDATED_STAMP)
$(APT_UPDATED_STAMP):
@echo "=== [APT UPDATE] Updating package lists..."
apt-get update
@mkdir -p $(STAMP_DIR)
@touch $@
###############################################################################
# STEP: install-cryptsetup
###############################################################################
.PHONY: install-cryptsetup
install-cryptsetup: $(CRYPTSETUP_INSTALLED)
$(CRYPTSETUP_INSTALLED): $(APT_UPDATED_STAMP)
@echo "=== [INSTALL] Installing cryptsetup..."
apt-get install -y cryptsetup unzip p7zip-full btrfs-progs file
@touch $@
###############################################################################
# STEP: install-rclone
###############################################################################
.PHONY: install-rclone
install-rclone: $(RCLONE_INSTALLED)
$(RCLONE_INSTALLED): $(APT_UPDATED_STAMP)
@echo "=== [INSTALL] Installing rclone via official script..."
@curl -fsSL https://rclone.org/install.sh | sudo bash; \
status=$$?; \
if [ $$status -eq 3 ]; then \
echo "rclone already up to date, continuing..."; \
elif [ $$status -ne 0 ]; then \
exit $$status; \
fi
@touch $@
###############################################################################
# STEP: install-kopia
###############################################################################
.PHONY: install-kopia
install-kopia: $(KOPIA_INSTALLED)
$(KOPIA_INSTALLED): $(APT_UPDATED_STAMP)
@echo "=== [INSTALL] Installing Kopia from official repository..."
@echo "=== [INSTALL] Adding Kopia signing key..."
curl -s https://kopia.io/signing-key | gpg --dearmor --batch --yes -o /etc/apt/keyrings/kopia-keyring.gpg
@echo "=== [INSTALL] Adding Kopia repo to /etc/apt/sources.list.d/kopia.list..."
echo "deb [signed-by=/etc/apt/keyrings/kopia-keyring.gpg] http://packages.kopia.io/apt/ stable main" | tee /etc/apt/sources.list.d/kopia.list
apt-get update
apt-get install -y kopia
@touch $@
###############################################################################
# STEP: Create LUKS volume image file
###############################################################################
$(LUKS_BTRFS_IMG): $(LUKS_VOLUME_IMG_CREATED)
$(LUKS_VOLUME_IMG_CREATED):
@echo "=== [CREATE] LUKS volume image at $(LUKS_BTRFS_IMG) with size $(IMG_SIZE)"
@if [ ! -f "$(LUKS_BTRFS_IMG)" ]; then \
echo "File $(LUKS_BTRFS_IMG) not found. Creating it now..."; \
truncate -s $(IMG_SIZE) $(LUKS_BTRFS_IMG); \
else \
echo "File $(LUKS_BTRFS_IMG) already exists."; \
echo "To change the current file, remove it (and the stamp file) manually. For example:"; \
echo " rm $(LUKS_BTRFS_IMG) && rm -f $(STAMP_DIR)/$(LUKS_VOLUME_IMG_CREATED)"; \
fi
@mkdir -p $(STAMP_DIR)
@touch $@
###############################################################################
# STEP: LUKS-format the image
###############################################################################
.PHONY: luks-format
luks-format: $(LUKS_FORMATTED_STAMP)
$(LUKS_FORMATTED_STAMP): $(LUKS_VOLUME_IMG_CREATED)
@if cryptsetup isLuks $(LUKS_BTRFS_IMG) >/dev/null 2>&1; then \
echo "File $(LUKS_BTRFS_IMG) is already LUKS formatted."; \
echo "If you want to re-format (this may cause data loss), please remove the LUKS header and stamp file manually."; \
echo "For example:"; \
echo " cryptsetup luksErase $(LUKS_BTRFS_IMG) && rm -f $(LUKS_FORMATTED_STAMP)"; \
else \
echo "=== [LUKS FORMAT] luksFormat for $(LUKS_BTRFS_IMG) non-interactively..."; \
echo -n "$(LUKS_PASSPHRASE)" | cryptsetup $(LUKS_FORMAT_OPTS) --batch-mode luksFormat $(LUKS_BTRFS_IMG) --key-file=-; \
fi
@touch $@
###############################################################################
# STEP: Open the LUKS volume
# NOTE: This requires user to type the LUKS passphrase.
###############################################################################
.PHONY: luks-open
# luks-open: $(LUKS_OPENED_STAMP)
# $(LUKS_OPENED_STAMP): $(LUKS_FORMATTED_STAMP)
# @echo "=== [LUKS OPEN] Opening the LUKS volume: $(LUKS_BTRFS_IMG)"
# cryptsetup open $(LUKS_BTRFS_IMG) $(LUKS_BTRFS_NAME)
# @touch $@
luks-open: $(LUKS_OPENED_STAMP)
$(LUKS_OPENED_STAMP): $(LUKS_FORMATTED_STAMP)
@echo "=== [LUKS OPEN] Opening the LUKS volume non-interactively..."
echo -n "$(LUKS_PASSPHRASE)" | cryptsetup open $(LUKS_BTRFS_IMG) $(LUKS_BTRFS_NAME) --key-file=-
@touch $@
###############################################################################
# STEP: Format the opened device as BTRFS
###############################################################################
.PHONY: btrfs-format
btrfs-format: $(BTRFS_FORMATTED_STAMP)
$(BTRFS_FORMATTED_STAMP): $(LUKS_OPENED_STAMP)
@target=$$(readlink -f /dev/mapper/$(LUKS_BTRFS_NAME)); \
if file -s $$target | grep -q "BTRFS"; then \
echo "BTRFS filesystem already exists on /dev/mapper/$(LUKS_BTRFS_NAME)."; \
echo "If you wish to reformat (WARNING: this will destroy your data), remove the filesystem signature and the stamp file manually."; \
echo "For example:"; \
echo " wipefs -a /dev/mapper/$(LUKS_BTRFS_NAME) && rm -f $(BTRFS_FORMATTED_STAMP)"; \
else \
echo "=== [BTRFS FORMAT] Creating BTRFS on /dev/mapper/$(LUKS_BTRFS_NAME)"; \
mkfs.btrfs /dev/mapper/$(LUKS_BTRFS_NAME); \
fi
@touch $@
###############################################################################
# STEP: Create BTRFS subvolume
# We must mount the device temporarily, create subvolume(s), then unmount.
###############################################################################
.PHONY: btrfs-subvolume
btrfs-subvolume: $(BTRFS_SUBVOL_CREATED)
$(BTRFS_SUBVOL_CREATED): $(BTRFS_FORMATTED_STAMP)
@echo "=== [BTRFS] Mounting device to create subvolume: $(BTRFS_SUBVOLUME)"
mkdir -p $(LUKS_MOUNTPOINT)
mount -t btrfs -o noatime,compress=zstd /dev/mapper/$(LUKS_BTRFS_NAME) $(LUKS_MOUNTPOINT)
# create the subvolume
btrfs subvolume create "$(LUKS_MOUNTPOINT)/$(BTRFS_SUBVOLUME)"
mkdir -p "$(LUKS_MOUNTPOINT)/$(BTRFS_SUBVOLUME)/$(DOCKER_SERVICES)"
mkdir -p "$(LUKS_MOUNTPOINT)/$(BTRFS_SUBVOLUME)/$(OFFSITE_STORAGE)"
# @echo "=== [BTRFS] Unmounting after subvolume creation..."
# umount $(LUKS_MOUNTPOINT)
@touch $@
###############################################################################
# STEP: Create mountpoint directories on the host
###############################################################################
.PHONY: mkdirs
mkdirs: $(MKDIR_OPT_DOCKER) $(MKDIR_OPT_OFFSITE)
$(MKDIR_OPT_DOCKER):
@echo "=== [MOUNTPOINT] Creating $(DOCKER_DIR) if it does not exist..."
mkdir -p $(DOCKER_DIR)
@touch $@
$(MKDIR_OPT_OFFSITE):
@echo "=== [MOUNTPOINT] Creating $(OFFSITE_DIR) if it does not exist..."
mkdir -p $(OFFSITE_DIR)
@touch $@
###############################################################################
# STEP: Install systemd config fragments (crypttab, fstab) and Docker override
###############################################################################
.PHONY: install-systemd-configs
install-systemd-configs: $(SYSTEMD_CONFIG_INSTALLED)
$(SYSTEMD_CONFIG_INSTALLED): crypttab.fragment fstab.fragment docker.service.override.conf btrfs-kopia-backup.timer btrfs-kopia-backup.service btrfs-kopia-backup.sh
@echo "=== [SYSTEMD CONFIG] Appending crypttab.fragment to /etc/crypttab (if not already present)..."
@if ! grep -q '$(LUKS_BTRFS_NAME)' /etc/crypttab 2>/dev/null; then \
cat crypttab.fragment >> /etc/crypttab; \
else \
echo " -> /etc/crypttab already has an entry for '$(LUKS_BTRFS_NAME)'"; \
fi
@echo "=== [SYSTEMD CONFIG] Appending fstab.fragment to /etc/fstab (if not already present)..."
@if ! grep -q '$(LUKS_MOUNTPOINT)' /etc/fstab 2>/dev/null; then \
cat fstab.fragment >> /etc/fstab; \
else \
echo " -> /etc/fstab already has an entry for '$(LUKS_MOUNTPOINT)'"; \
fi
@echo "=== [SYSTEMD CONFIG] Installing Docker override in /etc/systemd/system/docker.service.d/override.conf ..."
mkdir -p /etc/systemd/system/docker.service.d
cp docker.service.override.conf /etc/systemd/system/docker.service.d/override.conf
@echo "=== [SYSTEMD CONFIG] Templating btrfs-kopia-backup.timer -> /etc/systemd/system/btrfs-kopia-backup.timer ..."
@# We'll replace OnCalendar= with the value from $(DAILY_BACKUP_TIME)
sed "s|OnCalendar=.*|OnCalendar=$(DAILY_BACKUP_TIME)|g" btrfs-kopia-backup.timer > /etc/systemd/system/btrfs-kopia-backup.timer
@echo "=== [SYSTEMD CONFIG] Installing btrfs-kopia-backup.service -> /etc/systemd/system/"
cp btrfs-kopia-backup.service /etc/systemd/system/btrfs-kopia-backup.service
@echo "=== [SYSTEMD CONFIG] Installing btrfs-kopia-backup.sh -> /usr/local/bin (with envsubst for ALERT settings)"
cp btrfs-kopia-backup.sh btrfs-kopia-backup.sh.tmp
# We'll envsubst just the lines that mention ALERT, PUSHOVER_TOKEN, and PUSHOVER_USER if present:
@# If your script has placeholders, adapt accordingly. Here, we assume the user put placeholders or checks.
sed -i "s|^ALERT_ENABLED=.*|ALERT_ENABLED=${ALERT_ENABLED}|" btrfs-kopia-backup.sh.tmp
sed -i "s|^PUSHOVER_TOKEN=.*|PUSHOVER_TOKEN=\"${PUSHOVER_TOKEN}\"|" btrfs-kopia-backup.sh.tmp
sed -i "s|^PUSHOVER_USER=.*|PUSHOVER_USER=\"${PUSHOVER_USER}\"|" btrfs-kopia-backup.sh.tmp
install -m 0755 btrfs-kopia-backup.sh.tmp /usr/local/bin/btrfs-kopia-backup.sh
rm -f btrfs-kopia-backup.sh.tmp
@echo "=== [SYSTEMD] Reloading daemon to register new/modified units..."
systemctl daemon-reload
@echo "=== [SYSTEMD] Making sure that `opt-offsite_backup_storage.mount` and `opt-docker_services.mount` are started ..."
systemctl start opt-docker_services.mount
mount | grep '/opt/'
findmnt -T /opt/docker_services
findmnt -T /opt/offsite_backup_storage
@echo "=== [SYSTEMD] Enabling the btrfs-kopia-backup.timer so it starts on boot... XXX DO THIS YOURSELF XXX ..."
echo systemctl enable btrfs-kopia-backup.timer
@mkdir -p $(STAMP_DIR)
@touch $@
###############################################################################
# STEP: Set Kopia Global Policies
###############################################################################
.PHONY: kopia-global-policy
kopia-global-policy: $(KOPIA_POLICY_STAMP)
$(KOPIA_POLICY_STAMP): $(KOPIA_INSTALLED)
@echo "=== [KOPIA] Setting global Kopia policies..."
kopia policy set --global $(KOPIA_POLICY_PARALLELISM)
kopia policy set --global $(KOPIA_POLICY_RETENTION)
kopia policy set --global $(KOPIA_POLICY_COMPRESSION)
@touch $@
###############################################################################
# Optional: Create a new Kopia repository (NOT part of all)
###############################################################################
.PHONY: kopia-repository-create
kopia-repository-create: $(KOPIA_INSTALLED)
@echo "=== [KOPIA] Creating new Kopia repository with Rclone remote..."
@echo "Replace 'rclone-backup-sharepoint-site:\"${HOSTNAME}\"' with your actual remote path."
kopia repository create rclone --password "${KOPIA_REPOSITORY_SECRET}" --remote-path=rclone-backup-sharepoint-site:"${HOSTNAME}" --description="My Offsite BTRFS Snapshots for ${HOSTNAME}" --content-cache-size-mb=512 --metadata-cache-size-mb=512
@echo "=== [INFO] Kopia repository created. Adjust your remote path/password if needed."
###############################################################################
# Optional: Connect to an existing Kopia repository (NOT part of all)
###############################################################################
.PHONY: kopia-repository-connect
kopia-repository-connect:
@echo "=== [KOPIA] Connecting to existing Kopia repository with Rclone remote..."
@echo "Replace 'rclone-backup-sharepoint-site:\"${HOSTNAME}\"' with your actual remote path."
kopia repository connect rclone --remote-path=rclone-backup-sharepoint-site:"${HOSTNAME}"
@echo "=== [INFO] Kopia repository connected."
###############################################################################
# Housekeeping: a phony target to nudge systemd to reload (if you tweak configs)
###############################################################################
.PHONY: systemd-reload
systemd-reload:
@echo "=== [SYSTEMD] Reloading daemon..."
systemctl daemon-reload
###############################################################################
# Deinstall: a phony target to deinstall the systemd timers, services and overrides
###############################################################################
.PHONY: deinstall
deinstall:
@echo "=== [DEINSTALL] Disabling and stopping the btrfs-kopia-backup.timer (if active)..."
-systemctl disable --now btrfs-kopia-backup.timer 2>/dev/null || true
# @echo "=== [DEINSTALL] Removing systemd unit files for the backup..."
# rm -f /etc/systemd/system/btrfs-kopia-backup.timer
# rm -f /etc/systemd/system/btrfs-kopia-backup.service
# @echo "=== [DEINSTALL] Removing the backup script from /usr/local/bin..."
# rm -f /usr/local/bin/btrfs-kopia-backup.sh
@echo "=== [DEINSTALL] Removing Docker override (if present)..."
rm -f /etc/systemd/system/docker.service.d/override.conf
@echo "=== [DEINSTALL] Reloading systemd to reflect changes..."
systemctl daemon-reload
@echo "=== [DEINSTALL] Done. The rest of your system remains intact."
###############################################################################
# Housekeeping: Clean stamp files (won't delete your system changes!)
###############################################################################
.PHONY: clean
clean:
@echo "=== Removing local stamp files (this does NOT revert system changes!)"
rm -rf $(STAMP_DIR)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment