{ config, lib, pkgs, ... }: let nasHost = "nas"; repoPath = "/backups/workstation"; resticRepository = "sftp:${nasHost}:${repoPath}"; backupPaths = [ "${config.home.homeDirectory}/Documents" "${config.home.homeDirectory}/Pictures" ]; excludeFile = "${config.home.homeDirectory}/.config/restic/exclude"; includeFile = "${config.home.homeDirectory}/.config/restic/includes"; in { home.packages = with pkgs; [ restic ]; age.secrets.restic-password = { file = ../../secrets/restic-pw.age; path = "${config.home.homeDirectory}/.config/restic/password"; mode = "400"; }; home.sessionVariables = { RESTIC_REPOSITORY = resticRepository; RESTIC_PASSWORD_FILE = config.age.secrets.restic-password.path; }; home.file.".config/restic/includes" = { text = lib.concatStringsSep "\n" backupPaths; onChange = '' echo "Restic backup paths updated" ''; }; home.file.".config/restic/exclude" = { text = '' # macOS specific .DS_Store .Trash .Spotlight-V100 .fseventsd .TemporaryItems .DocumentRevisions-V100 .VolumeIcon.icns .AppleDouble .LSOverride Library/Caches Library/Logs # Development artifacts **/node_modules **/.venv **/__pycache__ **/*.pyc **/venv **/target # Rust **/dist **/build **/.tox **/.pytest_cache **/.coverage **/.mypy_cache # Large files that might not need backup *.dmg *.iso *.pkg # Version control **/.git/objects **/.git/lfs # IDE **/.idea **/.vscode *.swp *~ ''; }; home.file.".local/bin/restic-now" = { executable = true; text = '' #!/usr/bin/env bash set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color echo -e "''${GREEN}Starting restic backup...''${NC}" # Check if repository exists, initialize if not echo -e "''${YELLOW}Checking repository...''${NC}" if ! ${pkgs.restic}/bin/restic cat config > /dev/null 2>&1; then echo -e "''${YELLOW}Repository not found. Initializing...''${NC}" ${pkgs.restic}/bin/restic init fi # Run backup echo -e "''${GREEN}Running backup...''${NC}" ${pkgs.restic}/bin/restic backup \ --compression max \ --files-from="${includeFile}" \ --exclude-file="${excludeFile}" \ --verbose=1 \ --host="$(hostname -s)" # Unlock in case of stale locks echo -e "''${YELLOW}Checking for stale locks...''${NC}" ${pkgs.restic}/bin/restic unlock || true # Prune old snapshots echo -e "''${GREEN}Pruning old snapshots...''${NC}" ${pkgs.restic}/bin/restic forget \ --prune \ --keep-daily=7 \ --keep-weekly=4 \ --keep-monthly=12 \ --compression max \ --verbose=1 # Check repository integrity (optional, can be slow) echo -e "''${GREEN}Checking repository integrity...''${NC}" ${pkgs.restic}/bin/restic check --read-data-subset=5% echo -e "''${GREEN}Backup completed successfully!''${NC}" ''; }; home.file.".local/bin/restic-status" = { executable = true; text = '' #!/usr/bin/env bash set -euo pipefail echo "Repository: $RESTIC_REPOSITORY" echo "" echo "=== Latest snapshots ===" ${pkgs.restic}/bin/restic snapshots --latest 5 --compact echo "" echo "=== Repository stats ===" ${pkgs.restic}/bin/restic stats ''; }; home.file.".local/bin/restic-mount" = { executable = true; text = '' #!/usr/bin/env bash set -euo pipefail MOUNT_POINT="''${1:-$HOME/mnt/restic}" if [ ! -d "$MOUNT_POINT" ]; then echo "Creating mount point: $MOUNT_POINT" mkdir -p "$MOUNT_POINT" fi echo "Mounting restic repository at $MOUNT_POINT" echo "Press Ctrl+C to unmount" ${pkgs.restic}/bin/restic mount "$MOUNT_POINT" ''; }; home.file.".local/bin/restic-restore" = { executable = true; text = '' #!/usr/bin/env bash set -euo pipefail if [ $# -lt 1 ]; then echo "Usage: $0 [target-directory]" echo "" echo "Available snapshots:" ${pkgs.restic}/bin/restic snapshots --compact exit 1 fi SNAPSHOT="$1" TARGET="''${2:-$HOME/restic-restore}" echo "Restoring snapshot $SNAPSHOT to $TARGET" ${pkgs.restic}/bin/restic restore "$SNAPSHOT" --target "$TARGET" ''; }; }