1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-10 23:00:39 +02:00

feat: add paperless and radicale backups to hetzner

This commit is contained in:
oddlama 2024-01-20 03:02:26 +01:00
parent f9e1247b8a
commit 78ecdd2780
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
12 changed files with 128 additions and 67 deletions

View file

@ -1,10 +1,12 @@
{
config,
lib,
nodes,
...
}: let
sentinelCfg = nodes.sentinel.config;
paperlessDomain = "paperless.${sentinelCfg.repo.secrets.local.personalDomain}";
paperlessBackupDir = "/var/cache/paperless-backup";
in {
microvm.mem = 1024 * 6;
microvm.vcpu = 8;
@ -92,4 +94,29 @@ in {
};
systemd.services.paperless.serviceConfig.RestartSec = "600"; # Retry every 10 minutes
systemd.tmpfiles.settings."10-paperless".${paperlessBackupDir}.d = {
inherit (config.services.paperless) user;
mode = "0700";
};
systemd.services.paperless-backup = let
cfg = config.systemd.services.paperless-consumer;
in {
description = "Paperless documents backup";
serviceConfig = lib.recursiveUpdate cfg.serviceConfig {
ExecStart = "${config.services.paperless.package}/bin/paperless-ngx document_exporter -na -nt -f -d ${paperlessBackupDir}";
ReadWritePaths = cfg.serviceConfig.ReadWritePaths ++ [paperlessBackupDir];
Restart = "no";
Type = "oneshot";
};
inherit (cfg) environment;
requiredBy = ["restic-backups-storage-box-dusk.service"];
};
backups.storageBoxes.dusk = {
subuser = "paperless";
user = "paperless";
paths = [paperlessBackupDir];
};
}

View file

@ -246,7 +246,7 @@ in {
"/shares/users/${user}-paperless".d = {
user = "paperless";
group = "paperless";
mode = "0750";
mode = "0550";
};
"/paperless/consume/${user}".d = {
user = "paperless";
@ -347,37 +347,9 @@ in {
}
// lib.mapAttrs (_: cfg: {gid = cfg.id;}) (smbUsers // smbGroups);
# Backups
# ========================================================================
age.secrets.restic-encryption-password.generator.script = "alnum";
age.secrets.restic-ssh-privkey.generator.script = "ssh-ed25519";
services.restic.backups.main = {
hetznerStorageBox = let
box = config.repo.secrets.global.hetzner.storageboxes.dusk;
in {
enable = true;
inherit (box) mainUser;
inherit (box.users.samba) subUid path;
sshAgeSecret = "restic-ssh-privkey";
};
# We need to backup stuff from other users, so run as root.
backups.storageBoxes.dusk = {
subuser = "samba";
user = "root";
timerConfig = {
OnCalendar = "06:15";
RandomizedDelaySec = "3h";
Persistent = true;
};
initialize = true;
passwordFile = config.age.secrets.restic-encryption-password.path;
paths = ["/bunker"];
pruneOpts = [
"--keep-daily 14"
"--keep-weekly 7"
"--keep-monthly 12"
"--keep-yearly 75"
];
};
}

View file

@ -82,4 +82,10 @@ in {
};
systemd.services.radicale.serviceConfig.RestartSec = "600"; # Retry every 10 minutes
backups.storageBoxes.dusk = {
subuser = "radicale";
user = "radicale";
paths = ["/var/lib/radicale"];
};
}

View file

@ -74,7 +74,6 @@ in {
smtpSecurity = "force_tls";
smtpPort = 465;
};
#backupDir = "/data/backup";
environmentFile = config.age.secrets.vaultwarden-env.path;
};
@ -85,36 +84,9 @@ in {
RestartSec = "600"; # Retry every 10 minutes
};
# Backups
# ========================================================================
age.secrets.restic-encryption-password.generator.script = "alnum";
age.secrets.restic-ssh-privkey.generator.script = "ssh-ed25519";
services.restic.backups.main = {
hetznerStorageBox = let
box = config.repo.secrets.global.hetzner.storageboxes.dusk;
in {
enable = true;
inherit (box) mainUser;
inherit (box.users.vaultwarden) subUid path;
sshAgeSecret = "restic-ssh-privkey";
};
backups.storageBoxes.dusk = {
subuser = "vaultwarden";
user = "vaultwarden";
timerConfig = {
OnCalendar = "06:15";
RandomizedDelaySec = "3h";
Persistent = true;
};
initialize = true;
passwordFile = config.age.secrets.restic-encryption-password.path;
paths = [config.services.vaultwarden.backupDir];
pruneOpts = [
"--keep-daily 14"
"--keep-weekly 7"
"--keep-monthly 12"
"--keep-yearly 75"
];
};
}

View file

@ -104,12 +104,6 @@ in {
masquerade = true;
};
# Rule needed to allow local-vms wireguard traffic
lan-to-local = {
from = ["lan"];
to = ["local"];
};
outbound = {
from = ["lan"];
to = ["lan" "untrusted"];

79
modules/backups.nix Normal file
View file

@ -0,0 +1,79 @@
{
config,
lib,
...
}: let
inherit
(lib)
attrValues
flip
mkIf
mkMerge
mkOption
types
;
in {
options.backups.storageBoxes = mkOption {
description = "Backups to Hetzner Storage Boxes using restic";
default = {};
type = types.attrsOf (types.submodule (submod: {
options = {
name = mkOption {
description = "The name of the storage box to backup to. The box must be defined in the global secrets. Defaults to the attribute name.";
default = submod.config._module.args.name;
type = types.str;
};
subuser = mkOption {
description = "The name of the storage box subuser as defined in the global secrets, mapping this user to a subuser id.";
type = types.str;
};
user = mkOption {
description = "The user as which restic should run.";
type = types.str;
};
paths = mkOption {
description = "The paths to backup.";
type = types.listOf types.path;
};
};
}));
};
config = mkIf (config.backups.storageBoxes != {}) {
age.secrets.restic-encryption-password.generator.script = "alnum";
age.secrets.restic-ssh-privkey.generator.script = "ssh-ed25519";
services.restic.backups = mkMerge (flip map (attrValues config.backups.storageBoxes)
(boxCfg: {
"storage-box-${boxCfg.name}" = {
hetznerStorageBox = let
box = config.repo.secrets.global.hetzner.storageboxes.${boxCfg.name};
in {
enable = true;
inherit (box) mainUser;
inherit (box.users.${boxCfg.subuser}) subUid path;
sshAgeSecret = "restic-ssh-privkey";
};
# We need to backup stuff from other users, so run as root.
inherit (boxCfg) user paths;
timerConfig = {
OnCalendar = "06:15";
RandomizedDelaySec = "3h";
Persistent = true;
};
initialize = true;
passwordFile = config.age.secrets.restic-encryption-password.path;
pruneOpts = [
"--keep-daily 14"
"--keep-weekly 7"
"--keep-monthly 12"
"--keep-yearly 75"
];
};
}));
};
}

View file

@ -27,6 +27,7 @@
./config/users.nix
./acme-wildcard.nix
./backups.nix
./deterministic-ids.nix
./distributed-config.nix
./kanidm.nix

View file

@ -0,0 +1,10 @@
age-encryption.org/v1
-> X25519 yVph6Vasomk5FHVnvYCP9EIWNTDUV9VLjT3tLWO6V2U
jiNBCi4nwRT5BraQtwlF1NLEC8ed6kEvg1D6XKT808g
-> piv-p256 xqSe8Q Aj4vwj2hYJUA4EhprNegsyBlBERNaC4JOQSYFDTA4JPL
EEqBpXe1tPZfngPeuZ4I/cUkFhoG5Z4P2bjUQ8xIRoM
-> n-grease g)hu +9qNhz-|
oXZBv+XwPtRbS7tlKyekxGJAhn1Qje/y2nAjjFg+8Ap+oxwpdMwJ4iFG2yxsWdew
XcdgOj/61A
--- ZSNOvD2AbvfGqKJ+bGh4n6EZOuiIs0KsB+CDGjmojJY
œ(™ŽôÄI .MþülB‹'ùбð¶B½ˆ<±`¿ºE¯iÐ[¾&%†„Kø‘@"?ÿ±§§ˆAà¼ÁëXn"£!ñ üTØÅ

Binary file not shown.

Binary file not shown.