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:
parent
f9e1247b8a
commit
78ecdd2780
12 changed files with 128 additions and 67 deletions
|
@ -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];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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"];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
79
modules/backups.nix
Normal 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"
|
||||
];
|
||||
};
|
||||
}));
|
||||
};
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
./config/users.nix
|
||||
|
||||
./acme-wildcard.nix
|
||||
./backups.nix
|
||||
./deterministic-ids.nix
|
||||
./distributed-config.nix
|
||||
./kanidm.nix
|
||||
|
|
|
@ -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ØÅ
|
BIN
secrets/generated/sire-paperless/restic-ssh-privkey.age
Normal file
BIN
secrets/generated/sire-paperless/restic-ssh-privkey.age
Normal file
Binary file not shown.
BIN
secrets/generated/ward-radicale/restic-encryption-password.age
Normal file
BIN
secrets/generated/ward-radicale/restic-encryption-password.age
Normal file
Binary file not shown.
BIN
secrets/generated/ward-radicale/restic-ssh-privkey.age
Normal file
BIN
secrets/generated/ward-radicale/restic-ssh-privkey.age
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue