diff --git a/default.nix b/default.nix
index 7fd29fd..133774f 100644
--- a/default.nix
+++ b/default.nix
@@ -363,9 +363,69 @@ in
         Runs a local DNS resolver (kresd) as recommended when running rspamd. This prevents your log file from filling up with rspamd_monitored_dns_mon entries.
       '';
     };
+
+    backup = {
+      enable = mkEnableOption "backup via rsnapshot";
+
+      snapshotRoot = mkOption {
+        type = types.path;
+        default = "/var/rsnapshot";
+        description = ''
+          The directory where rsnapshot stores the backup.
+        '';
+      };
+
+      cmdPreexec = mkOption {
+        type = types.nullOr types.string;
+        default = null;
+        description = ''
+          The command to be executed before each backup operation. This is wrapped in a shell script to be called by rsnapshot.
+        '';
+      };
+
+      cmdPostexec = mkOption {
+        type = types.nullOr types.string;
+        default = null;
+        description = "The command to be executed after each backup operation. This is wrapped in a shell script to be called by rsnapshot.";
+      };
+
+      retain = {
+        hourly = mkOption {
+          type = types.int;
+          default = 24;
+          description = "How many hourly snapshots are retained.";
+        };
+        daily = mkOption {
+          type = types.int;
+          default = 7;
+          description = "How many daily snapshots are retained.";
+        };
+        weekly = mkOption {
+          type = types.int;
+          default = 54;
+          description = "How many weekly snapshots are retained.";
+        };
+      };
+
+      cronIntervals = mkOption {
+        type = types.attrsOf types.string;
+        default = {
+                   # minute, hour, day-in-month, month, weekday (0 = sunday)
+          hourly = " 0  *  *  *  *"; # Every full hour
+          daily  = "30  3  *  *  *"; # Every day at 3:30
+          weekly = " 0  5  *  *  0"; # Every sunday at 5:00 AM
+        };
+        description = ''
+          Periodicity at which intervals should be run by cron.
+          Note that the intervals also have to exist in configuration
+          as retain options.
+        '';
+      };
+    };
   };
 
   imports = [
+    ./mail-server/rsnapshot.nix
     ./mail-server/clamav.nix
     ./mail-server/users.nix
     ./mail-server/environment.nix
diff --git a/mail-server/rsnapshot.nix b/mail-server/rsnapshot.nix
new file mode 100644
index 0000000..8365f7b
--- /dev/null
+++ b/mail-server/rsnapshot.nix
@@ -0,0 +1,59 @@
+#  nixos-mailserver: a simple mail server
+#  Copyright (C) 2016-2017  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, ... }:
+
+with lib;
+
+let
+  cfg = config.mailserver;
+
+  preexecDefined = cfg.backup.cmdPreexec != null;
+  preexecWrapped = pkgs.writeScript "rsnapshot-preexec.sh" ''
+    #!${pkgs.stdenv.shell}
+    set -e
+
+    ${cfg.backup.cmdPreexec}
+  '';
+  preexecString = optionalString preexecDefined "cmd_preexec	${preexecWrapped}";
+
+  postexecDefined = cfg.backup.cmdPostexec != null;
+  postexecWrapped = pkgs.writeScript "rsnapshot-postexec.sh" ''
+    #!${pkgs.stdenv.shell}
+    set -e
+
+    ${cfg.backup.cmdPostexec}
+  '';
+  postexecString = optionalString postexecDefined "cmd_postexec	${postexecWrapped}";
+in {
+  config = mkIf cfg.backup.enable {
+    services.rsnapshot = {
+      enable = true;
+      cronIntervals = cfg.backup.cronIntervals;
+      # rsnapshot expects intervals shortest first, e.g. hourly first, then daily.
+      # tabs must separate all elements
+      extraConfig = ''
+        ${preexecString}
+        ${postexecString}
+        snapshot_root	${cfg.backup.snapshotRoot}/
+        retain	hourly	${toString cfg.backup.retain.hourly}
+        retain	daily	${toString cfg.backup.retain.daily}
+        retain	weekly	${toString cfg.backup.retain.weekly}
+        backup	${cfg.mailDirectory}/	localhost/
+      '';
+    };
+  };
+}