148 lines
5.7 KiB
Nix
148 lines
5.7 KiB
Nix
{
|
|
lib,
|
|
config,
|
|
pkgs,
|
|
...
|
|
}:
|
|
{
|
|
|
|
# container builder
|
|
lib.mySystem.mkContainer =
|
|
options:
|
|
(
|
|
let
|
|
containerExtraOptions =
|
|
lib.optionals (lib.attrsets.attrByPath [ "caps" "privileged" ] false options) [ "--privileged" ]
|
|
++ lib.optionals (lib.attrsets.attrByPath [ "caps" "readOnly" ] false options) [ "--read-only" ]
|
|
++ lib.optionals (lib.attrsets.attrByPath [ "caps" "tmpfs" ] false options) (
|
|
map (folders: "--tmpfs=${folders}") options.caps.tmpfsFolders
|
|
)
|
|
++ lib.optionals (lib.attrsets.attrByPath [ "caps" "noNewPrivileges" ] false options) [
|
|
"--security-opt=no-new-privileges"
|
|
]
|
|
++ lib.optionals (lib.attrsets.attrByPath [ "caps" "dropAll" ] false options) [ "--cap-drop=ALL" ];
|
|
in
|
|
{
|
|
${options.app} = {
|
|
image = "${options.image}";
|
|
user = "${options.user}:${options.group}";
|
|
environment = {
|
|
TZ = config.time.timeZone;
|
|
} // lib.attrsets.attrByPath [ "env" ] { } options;
|
|
dependsOn = lib.attrsets.attrByPath [ "dependsOn" ] [ ] options;
|
|
entrypoint = lib.attrsets.attrByPath [ "entrypoint" ] null options;
|
|
cmd = lib.attrsets.attrByPath [ "cmd" ] [ ] options;
|
|
environmentFiles = lib.attrsets.attrByPath [ "envFiles" ] [ ] options;
|
|
volumes = [
|
|
"/etc/localtime:/etc/localtime:ro"
|
|
] ++ lib.attrsets.attrByPath [ "volumes" ] [ ] options;
|
|
ports = lib.attrsets.attrByPath [ "ports" ] [ ] options;
|
|
extraOptions = containerExtraOptions;
|
|
};
|
|
}
|
|
);
|
|
|
|
## Creates a standardized restic backup configuration for both local and remote backups per app.
|
|
# One S3 bucket per server. Each app has its own repository in the bucket.
|
|
# Or backup each app it's own remote repository.
|
|
# Takes an attribute set with:
|
|
# - app: name of the application (used for backup naming)
|
|
# - user: user to run the backup as
|
|
# - localResticTemplate: template for local restic backup
|
|
# - passwordFile: path to the password file
|
|
# - paths: list of paths to backup
|
|
# - remoteResticTemplate: template for remote restic backup
|
|
# - environmentFile (optional): path to the env file
|
|
# - excludePaths (optional): list of paths to exclude from backup
|
|
# Configures:
|
|
# - Daily backups at 02:05 with 3h random delay
|
|
# - Retention: 7 daily, 5 weekly, 12 monthly backups
|
|
# - Automatic stale lock removal
|
|
# - Uses system-configured backup paths and credentials
|
|
#
|
|
# Example usage:
|
|
# services.restic.backups = config.lib.mySystem.mkRestic {
|
|
# app = "nextcloud";
|
|
# paths = [ "/nahar/containers/volumes/nextcloud" ];
|
|
# excludePaths = [ "/nahar/containers/volumes/nextcloud/data/cache" ];
|
|
# user = "kah";
|
|
# localResticTemplate = "/eru/restic/nextcloud";
|
|
# remoteResticTemplate = "rest:https://user:password@x.repo.borgbase.com";
|
|
# remoteResticTemplate = "s3:https://x.r2.cloudflarestorage.com/resticRepos";
|
|
# remoteResticTemplateFile = "/run/secrets/restic/nextcloud/template";
|
|
# passwordFile = "/run/secrets/restic/nextcloud/password";
|
|
# environmentFile = "/run/secrets/restic/nextcloud/env";
|
|
# };
|
|
# This creates two backup jobs:
|
|
# - nextcloud-local: backs up to local storage
|
|
# - nextcloud-remote: backs up to remote storage (e.g. S3)
|
|
lib.mySystem.mkRestic =
|
|
options:
|
|
let
|
|
# excludePaths is optional
|
|
excludePaths = if builtins.hasAttr "excludePaths" options then options.excludePaths else [ ];
|
|
# Decide which mutually exclusive options to use
|
|
remoteResticTemplateFile =
|
|
if builtins.hasAttr "remoteResticTemplateFile" options then
|
|
options.remoteResticTemplateFile
|
|
else
|
|
null;
|
|
remoteResticTemplate =
|
|
if builtins.hasAttr "remoteResticTemplate" options then options.remoteResticTemplate else null;
|
|
# 2:05 daily backup with 3h random delay
|
|
timerConfig = {
|
|
OnCalendar = "06:05"; # night snap is taken at 02:10
|
|
Persistent = true;
|
|
RandomizedDelaySec = "30m";
|
|
};
|
|
# 7 daily, 5 weekly, 12 monthly backups
|
|
pruneOpts = [
|
|
"--keep-daily 7"
|
|
"--keep-weekly 5"
|
|
];
|
|
# Initialize the repository if it doesn't exist
|
|
initialize = true;
|
|
# Only one backup is ever running at a time it's safe to say that we can remove stale locks
|
|
backupPrepareCommand = ''
|
|
# remove stale locks - this avoids some occasional annoyance
|
|
#
|
|
${pkgs.restic}/bin/restic unlock --remove-all || true
|
|
'';
|
|
in
|
|
{
|
|
# local backup
|
|
"${options.app}-local" = {
|
|
inherit
|
|
pruneOpts
|
|
timerConfig
|
|
initialize
|
|
backupPrepareCommand
|
|
;
|
|
inherit (options) user passwordFile environmentFile;
|
|
# Move the path to the zfs snapshot path
|
|
paths = map (x: "${config.mySystem.services.zfs-nightly-snap.mountPath}/${x}") options.paths;
|
|
exclude = map (
|
|
x: "${config.mySystem.services.zfs-nightly-snap.mountPath}/${x}"
|
|
) options.excludePaths;
|
|
repository = "${options.localResticTemplate}";
|
|
};
|
|
|
|
# remote backup
|
|
"${options.app}-remote" = {
|
|
inherit
|
|
pruneOpts
|
|
timerConfig
|
|
initialize
|
|
backupPrepareCommand
|
|
;
|
|
inherit (options) user passwordFile environmentFile;
|
|
# Move the path to the zfs snapshot path
|
|
paths = map (x: "${config.mySystem.services.zfs-nightly-snap.mountPath}/${x}") options.paths;
|
|
repository = remoteResticTemplate;
|
|
repositoryFile = remoteResticTemplateFile;
|
|
exclude = map (
|
|
x: "${config.mySystem.services.zfs-nightly-snap.mountPath}/${x}"
|
|
) options.excludePaths;
|
|
};
|
|
};
|
|
}
|