aboutsummaryrefslogblamecommitdiff
path: root/home/profiles/restic.nix
blob: 96ae8d45c71faddd8eabdc045faaf088bf66dd75 (plain) (tree)




































































































































































































                                                                         
{
  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 <snapshot-id> [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"
    '';
  };
}