This repository has been archived on 2024-03-26. You can view files and clone it, but cannot push or open issues or pull requests.
nixos/hosts/hermes/backup.nix
Payas Relekar 527e463208 Hermes: Enable Backup module
This is admittedly a failure, because restic is a one way street. It takes what
is on disk and pushes to backup location.

Which means, if I want to restore the backup, I have to restore first, by way of
imperatively setting up restic repos in advance and then setting up the backup
servies for restic.

This is not ideal, and Syncthing has proven to be more suitable solution for my
needs.

But, considering my possible future requirements, I should start thinking about
solving this problem.
2022-06-02 22:11:24 +05:30

274 lines
11 KiB
Nix

{ config, pkgs, options, ... }:
# Automated Backup and backup notification configuration for NixOS
# Using:
# 1. Restic : encryption, snapshots, dedeuplication
# 2. Rclone : access to free storages (Google Drive, OneDrive etc)
# 3. Systemd/NixOS : automation, notifications etc
# 4. (DBus) : desktop notifications, provided by Plasma desktop
let
payas = "payas";
in
{
environment.systemPackages = with pkgs; [
restic # It is included in system by restic service, but its useful to have the package in PATH to remove occasional locks
rsync
rclone
];
# Le Backups!! Test them every month or so, just to be sure
services.restic.backups =
let
defaultPruneOpts = [
"--keep-last 10"
"--keep-hourly 3"
"--keep-daily 4"
"--keep-weekly 3"
"--keep-monthly 3"
];
defaultBackupFrequency = "hourly";
in
{
# maildir (for one email account, on a shared folder curtosy of family member)
maildir_relekarpayas_onedrive_shared = {
user = payas;
repository = "rclone:relekarpayas_onedrive_shared:/payas_backup/maildir_rpg";
initialize = true; # for now, I want to control repo intialization myself
passwordFile = config.age.secrets.maildir_relekarpayas_onedrive.path;
paths = [ "/home/payas/.mail/" ];
# Run our nice little service every hour. If this proves too taxing, increase duration or give out fixed time.
timerConfig.OnCalendar = defaultBackupFrequency;
pruneOpts = defaultPruneOpts;
};
# Syncthing dir
syncthing_googledrive = {
user = payas;
repository = "rclone:relekarpayas_googledrive:/syncthing";
initialize = true; # for now, I want to control repo intialization myself
passwordFile = config.age.secrets.syncthing_relekarpayas_googledrive.path;
paths = [ "/home/payas/Syncthing/" ];
# Ignore Media dir because it contains non-essential and heavy media files
extraBackupArgs = [ "--exclude=/home/payas/Syncthing/Media" ];
# Run our nice little service every hour. If this proves too taxing, increase duration or give out fixed time.
timerConfig.OnCalendar = defaultBackupFrequency;
pruneOpts = defaultPruneOpts;
};
syncthing_onedrive_shared = {
user = payas;
repository = "rclone:relekarpayas_onedrive_shared:/payas_backup/Syncthing";
initialize = true; # for now, I want to control repo intialization myself
passwordFile = config.age.secrets.syncthing_relekarpayas_onedrive.path;
paths = [ "/home/payas/Syncthing/" ];
# Ignore Media dir because it contains non-essential and heavy media files
extraBackupArgs = [ "--exclude=/home/payas/Syncthing/Media" ];
# Run our nice little service every hour. If this proves too taxing, increase duration or give out fixed time.
timerConfig.OnCalendar = defaultBackupFrequency;
pruneOpts = defaultPruneOpts;
};
# Org-mode notes
org_googledrive = {
user = payas;
repository = "rclone:relekarpayas_googledrive:/org";
initialize = true; # for now, I want to control repo intialization myself
passwordFile = config.age.secrets.org_relekarpayas_googledrive.path;
paths = [ "/home/payas/org/" ];
# Run our nice little service every hour. If this proves too taxing, increase duration or give out fixed time.
timerConfig.OnCalendar = defaultBackupFrequency;
pruneOpts = defaultPruneOpts;
};
org_onedrive_shared = {
user = payas;
repository = "rclone:relekarpayas_onedrive_shared:/payas_backup/org";
initialize = true; # for now, I want to control repo intialization myself
passwordFile = config.age.secrets.org_relekarpayas_onedrive.path;
paths = [ "/home/payas/org/" ];
# Run our nice little service every hour. If this proves too taxing, increase duration or give out fixed time.
timerConfig.OnCalendar = defaultBackupFrequency;
pruneOpts = defaultPruneOpts;
};
};
# Le Backup notifications : So I find out about success/failure of backups without having to check logs every now and then
# This generates actual desktop notifications, and integrates nicely (as long as DBus is accessible to service)
#
# Backup notification idea (for now) is this:
# 1. Detect service failure: handled by systemd
# 2. Invoke alert service: handled by systemd
# 3. touch a BACKUP_Failure file in ~: probably unnecessary, but I intent to delete these files after
# investigating/fixing failures so as to have greater visibility and
# don't want file-not-exist conflicts
# 4. Show desktop notification for exactly which backup failed
systemd.services =
let
defaultBackupServiceEnv = {
DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/1000/bus";
};
defaultDescr = "Backup notification";
failureDescr = ": Failure: ";
orgDescr = "Org";
syncthingDescr = "Syncthing";
maildirDescr = "Maildir";
googDescr = "goog";
msDescr = "ms";
oneshot = "oneshot";
backupFailedPrefix = "/home/payas/BACKUP_FAILED";
in
{
# Syncthing failure notification
backup-failure-alert-syncthing-goog = {
description = defaultDescr + failureDescr + syncthingDescr;
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/touch '${backupFailedPrefix}_${syncthingDescr}_${googDescr}'"
"${pkgs.libnotify}/bin/notify-send --hint='string:desktop-entry:org.kde.konsole' 'Backup failure: Syncthing: Goog'"
];
User = payas;
};
};
# Syncthing success: Remove failure indicator file if present
backup-success-alert-syncthing-goog = {
description = "Syncthing_goog backup success: Remove failure indicator file if present";
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/rm '${backupFailedPrefix}_${syncthingDescr}_${googDescr}'"
];
User = payas;
};
};
# Configure notification services for restic backup service
restic-backups-syncthing_googledrive = {
onFailure = [ "backup-failure-alert-syncthing-goog.service" ];
unitConfig.OnSuccess = [ "backup-success-alert-syncthing-goog.service" ];
};
backup-failure-alert-syncthing-ms = {
description = defaultDescr + failureDescr + syncthingDescr;
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/touch '${backupFailedPrefix}_${syncthingDescr}_${msDescr}'"
"${pkgs.libnotify}/bin/notify-send --hint='string:desktop-entry:org.kde.konsole' 'Backup failure: Syncthing: MS'"
];
User = payas;
};
};
backup-success-alert-syncthing-ms = {
description = "Syncthing_ms backup success: Remove failure indicator file if present";
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/rm '${backupFailedPrefix}_${syncthingDescr}_${msDescr}'"
];
User = payas;
};
};
restic-backups-syncthing_onedrive_shared = {
onFailure = [ "backup-failure-alert-syncthing-ms.service" ];
unitConfig.OnSuccess = [ "backup-success-alert-syncthing-ms.service" ];
};
# Org failure notification
backup-failure-alert-org-goog = {
description = defaultDescr + failureDescr + orgDescr;
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/touch '${backupFailedPrefix}_${orgDescr}_${googDescr}'"
"${pkgs.libnotify}/bin/notify-send --hint='string:desktop-entry:org.kde.konsole' 'Backup failure: Org: Goog'"
];
User = payas;
};
};
# Org success: Remove failure indicator file if present
backup-success-alert-org-goog = {
description = "Org backup success: Remove failure indicator file if present";
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/rm '${backupFailedPrefix}_${orgDescr}_${googDescr}'"
];
User = payas;
};
};
# Configure notification services for restic backup service
restic-backups-org_googledrive = {
onFailure = [ "backup-failure-alert-org-goog.service" ];
unitConfig.OnSuccess = [ "backup-success-alert-org-goog.service" ];
};
backup-failure-alert-org-ms = {
description = defaultDescr + failureDescr + syncthingDescr;
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/touch '${backupFailedPrefix}_${orgDescr}_${msDescr}'"
"${pkgs.libnotify}/bin/notify-send --hint='string:desktop-entry:org.kde.konsole' 'Backup failure: Org: MS'"
];
User = payas;
};
};
backup-success-alert-org-ms = {
description = "${orgDescr}_${msDescr} backup success: Remove failure indicator file if present";
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/rm '${backupFailedPrefix}_${orgDescr}_${msDescr}'"
];
User = payas;
};
};
restic-backups-org_onedrive_shared = {
onFailure = [ "backup-failure-alert-org-ms.service" ];
unitConfig.OnSuccess = [ "backup-success-alert-org-ms.service" ];
};
# Maildir backup failure notification
backup-failure-alert-maildir_onedrive = {
description = defaultDescr + failureDescr + maildirDescr;
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/touch '${backupFailedPrefix}_${maildirDescr}_${msDescr}'"
"${pkgs.libnotify}/bin/notify-send --hint='string:desktop-entry:org.kde.konsole' 'Backup failure: Maildir: MS_shared'"
];
User = payas;
};
};
backup-success-alert-maildir-onedrive = {
description = "Maildir backup success: Remove failure indicator file if present";
environment = defaultBackupServiceEnv;
serviceConfig = {
Type = oneshot;
ExecStart = [
"${pkgs.coreutils}/bin/rm '${backupFailedPrefix}_${maildirDescr}_${msDescr}'"
];
User = payas;
};
};
# Configure notification services for restic backup service
restic-backups-maildir_relekarpayas_onedrive_shared = {
onFailure = [ "backup-failure-alert-maildir_onedrive.service" ];
unitConfig.OnSuccess = [ "backup-success-alert-maildir-onedrive.service" ];
};
};
}