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"
'';
};
}
|