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.
This commit is contained in:
Payas Relekar 2022-06-02 22:11:24 +05:30
parent 9ff1246638
commit 527e463208
2 changed files with 275 additions and 0 deletions

View file

@ -98,6 +98,7 @@
# ./hosts/enterprise/backup.nix
./hosts/hermes/configuration.nix
./hosts/hermes/syncthing.nix
./hosts/hermes/backup.nix
# User-specific config : Home-manager
home-manager.nixosModules.home-manager

274
hosts/hermes/backup.nix Normal file
View file

@ -0,0 +1,274 @@
{ 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" ];
};
};
}