Skip to content

Instantly share code, notes, and snippets.

@jivanpal
Created August 30, 2025 14:43
Show Gist options
  • Select an option

  • Save jivanpal/2485c780df4a3d7229a7b98fbc70e35e to your computer and use it in GitHub Desktop.

Select an option

Save jivanpal/2485c780df4a3d7229a7b98fbc70e35e to your computer and use it in GitHub Desktop.
Backup script (using Restic) and SystemD units.
#!/bin/bash
# Lives at /usr/local/bin/backup
if [ $EUID -ne 0 ]; then
>&2 echo "ERROR: This script must be run as root."
exit 1
fi
if [ $# -eq 0 ]; then
>&2 echo "ERROR: Missing required args: $0 <backup-set name> [restic args]"
exit 1
fi
backup_set="$1"
shift
## Set envvars
export HOME=/root # For Restic cache
export RESTIC_PASSWORD_FILE=/etc/restic/password
case "$backup_set" in
media-data)
export RESTIC_REPOSITORY=sftp:jivan@restic.jivan.dev:/mnt/restic/repos/media-data
;;
*)
export RESTIC_REPOSITORY=sftp:jivan@restic.jivan.dev:/mnt/restic/repos/default
;;
esac
## Define backup sets
docker_service=false
case "$backup_set" in
dawarich)
docker_service=true
data_dir='/var/www/email.pal.maps'
backup_dirs="$data_dir"
;;
immich)
docker_service=true
data_dir='/var/www/email.pal.photos'
backup_dirs="$data_dir"
;;
jellyfin-config)
backup_dirs="/var/www/com.jivanpal.media /var/lib/jellyfin"
;;
media-data)
backup_dirs="/mnt/media-data --exclude /mnt/media-data/lost+found"
;;
palworld)
backup_dirs="/var/www/email.pal.world --exclude-file /etc/restic/exclude-palworld"
;;
transmission-config)
backup_dirs="/etc/transmission-daemon /var/lib/transmission-daemon"
;;
vaultwarden)
docker_service=true
data_dir='/var/www/email.pal.vault'
backup_dirs="$data_dir /var/lib/vaultwarden"
;;
*)
>&2 echo "ERROR: Unknown backup-set \"$backup_set\""
exit 1
esac
## Perform backup
if $docker_service; then (
set -x
docker compose --project-directory "$data_dir" pull
docker compose --project-directory "$data_dir" down
); fi
hostname="$(hostname -f)"
echo "+ RESTIC_REPOSITORY=$RESTIC_REPOSITORY"
(
set -x
restic -vv \
backup $backup_dirs \
-H "$hostname" \
--tag "$backup_set" \
"$@" |
grep --line-buffered -Ev '^unchanged '
)
if $docker_service; then (
set -x
docker compose --project-directory "$data_dir" up -d
); fi
# Lives at /etc/systemd/system/backup@.service
[Unit]
Description=Backup data to Restic repository
[Service]
Type=exec
ExecStart=/usr/local/bin/backup %i
# Lives at /etc/systemd/system/backup@.timer
[Unit]
Description=Backup data to Restic repository
[Timer]
Unit=backup@%i.service
OnCalendar=03:00
[Install]
WantedBy=timers.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment