summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Raymond <robin@robinraymond.de>2018-03-10 18:20:19 +0100
committerGitHub <noreply@github.com>2018-03-10 18:20:19 +0100
commite3a12093b7631677443637f87aed8406b2f41285 (patch)
tree196aca7d97e0b2b06f41d2f7da0b1261c0622d5f
parentf69081226dd7b7863de66b2c0eb8b8d9d34fec09 (diff)
parentb53364715d2149df7e326b07624555753de91300 (diff)
Merge pull request #93 from phdoerfler/borgbackup
Added basic support for borgbackup
-rw-r--r--default.nix132
-rw-r--r--mail-server/borgbackup.nix78
2 files changed, 209 insertions, 1 deletions
diff --git a/default.nix b/default.nix
index 168bbaf..77dca63 100644
--- a/default.nix
+++ b/default.nix
@@ -477,9 +477,138 @@ in
description = ''
The configuration used for monitoring via monit.
Use a mail address that you actively check and set it via 'set alert ...'.
+ '';
+ };
+ };
+
+ borgbackup = {
+ enable = mkEnableOption "backup via borgbackup";
+
+ repoLocation = mkOption {
+ type = types.string;
+ default = "/var/borgbackup";
+ description = ''
+ The location where borg saves the backups.
+ This can be a local path or a remote location such as user@host:/path/to/repo.
+ It is exported and thus available as an environment variable to cmdPreexec and cmdPostexec.
+ '';
+ };
+
+ startAt = mkOption {
+ type = types.string;
+ default = "hourly";
+ description = "When or how often the backup should run. Must be in the format described in systemd.time 7.";
+ };
+
+ user = mkOption {
+ type = types.string;
+ default = "virtualMail";
+ description = "The user borg and its launch script is run as.";
+ };
+
+ group = mkOption {
+ type = types.string;
+ default = "virtualMail";
+ description = "The group borg and its launch script is run as.";
+ };
+
+ compression = {
+ method = mkOption {
+ type = types.nullOr (types.enum ["none" "lz4" "zstd" "zlib" "lzma"]);
+ default = null;
+ description = "Leaving this unset allows borg to choose. The default for borg 1.1.4 is lz4.";
+ };
+
+ level = mkOption {
+ type = types.nullOr types.int;
+ default = null;
+ description = ''
+ Denotes the level of compression used by borg.
+ Most methods accept levels from 0 to 9 but zstd which accepts values from 1 to 22.
+ If null the decision is left up to borg.
'';
- };
};
+
+ auto = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Leaves it to borg to determine whether an individual file should be compressed.";
+ };
+ };
+
+ encryption = {
+ method = mkOption {
+ type = types.enum [
+ "none"
+ "authenticated"
+ "authenticated-blake2"
+ "repokey"
+ "keyfile"
+ "repokey-blake2"
+ "keyfile-blake2"
+ ];
+ default = "none";
+ description = ''
+ The backup can be encrypted by choosing any other value than 'none'.
+ When using encryption the password / passphrase must be provided in passphraseFile.
+ '';
+ };
+
+ passphraseFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ };
+ };
+
+ name = mkOption {
+ type = types.string;
+ default = "{hostname}-{user}-{now}";
+ description = ''
+ The name of the individual backups as used by borg.
+ Certain placeholders will be replaced by borg.
+ '';
+ };
+
+ locations = mkOption {
+ type = types.listOf types.path;
+ default = [cfg.mailDirectory];
+ description = "The locations that are to be backed up by borg.";
+ };
+
+ extraArgumentsForInit = mkOption {
+ type = types.listOf types.string;
+ default = ["--critical"];
+ description = "Additional arguments to add to the borg init command line.";
+ };
+
+ extraArgumentsForCreate = mkOption {
+ type = types.listOf types.string;
+ default = [ ];
+ description = "Additional arguments to add to the borg create command line e.g. '--stats'.";
+ };
+
+ cmdPreexec = mkOption {
+ type = types.nullOr types.string;
+ default = null;
+ description = ''
+ The command to be executed before each backup operation.
+ This is called prior to borg init in the same script that runs borg init and create and cmdPostexec.
+ Example:
+ export BORG_RSH="ssh -i /path/to/private/key"
+ '';
+ };
+
+ cmdPostexec = mkOption {
+ type = types.nullOr types.string;
+ default = null;
+ description = ''
+ The command to be executed after each backup operation.
+ This is called after borg create completed successfully and in the same script that runs
+ cmdPreexec, borg init and create.
+ '';
+ };
+
+ };
backup = {
enable = mkEnableOption "backup via rsnapshot";
@@ -542,6 +671,7 @@ in
};
imports = [
+ ./mail-server/borgbackup.nix
./mail-server/rsnapshot.nix
./mail-server/clamav.nix
./mail-server/monit.nix
diff --git a/mail-server/borgbackup.nix b/mail-server/borgbackup.nix
new file mode 100644
index 0000000..3c60031
--- /dev/null
+++ b/mail-server/borgbackup.nix
@@ -0,0 +1,78 @@
+# nixos-mailserver: a simple mail server
+# Copyright (C) 2016-2018 Robin Raymond
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>
+
+{ config, pkgs, lib, ... }:
+
+let
+ cfg = config.mailserver.borgbackup;
+
+ methodFragment = lib.optional (cfg.compression.method != null) cfg.compression.method;
+ autoFragment =
+ if cfg.compression.auto && cfg.compression.method == null
+ then throw "compression.method must be set when using auto."
+ else lib.optional cfg.compression.auto "auto";
+ levelFragment =
+ if cfg.compression.level != null && cfg.compression.method == null
+ then throw "compression.method must be set when using compression.level."
+ else lib.optional (cfg.compression.level != null) (toString cfg.compression.level);
+ compressionFragment = lib.concatStringsSep "," (lib.flatten [autoFragment methodFragment levelFragment]);
+ compression = lib.optionalString (compressionFragment != "") "--compression ${compressionFragment}";
+
+ encryptionFragment = cfg.encryption.method;
+ passphraseFile = lib.escapeShellArg cfg.encryption.passphraseFile;
+ passphraseFragment = lib.optionalString (cfg.encryption.method != "none")
+ (if cfg.encryption.passphraseFile != null then ''env BORG_PASSPHRASE="$(cat ${passphraseFile})"''
+ else throw "passphraseFile must be set when using encryption.");
+
+ locations = lib.escapeShellArgs cfg.locations;
+ name = lib.escapeShellArg cfg.name;
+
+ repoLocation = lib.escapeShellArg cfg.repoLocation;
+
+ extraInitArgs = lib.escapeShellArgs cfg.extraArgumentsForInit;
+ extraCreateArgs = lib.escapeShellArgs cfg.extraArgumentsForCreate;
+
+ cmdPreexec = lib.optionalString (cfg.cmdPreexec != null) cfg.cmdPreexec;
+ cmdPostexec = lib.optionalString (cfg.cmdPostexec != null) cfg.cmdPostexec;
+
+ borgScript = ''
+ export BORG_REPO=${repoLocation}
+ ${cmdPreexec}
+ ${passphraseFragment} ${pkgs.borgbackup}/bin/borg init ${extraInitArgs} --encryption ${encryptionFragment} || true
+ ${passphraseFragment} ${pkgs.borgbackup}/bin/borg create ${extraCreateArgs} ${compression} ::${name} ${locations}
+ ${cmdPostexec}
+ '';
+in {
+ config = lib.mkIf config.mailserver.borgbackup.enable {
+ environment.systemPackages = with pkgs; [
+ borgbackup
+ ];
+
+ systemd.services.borgbackup = {
+ description = "borgbackup";
+ unitConfig.Documentation = "man:borgbackup";
+ script = borgScript;
+ serviceConfig = {
+ User = cfg.user;
+ Group = cfg.group;
+ CPUSchedulingPolicy = "idle";
+ IOSchedulingClass = "idle";
+ ProtectSystem = "full";
+ };
+ startAt = cfg.startAt;
+ };
+ };
+}