158 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{
 | 
						|
  config,
 | 
						|
  pkgs,
 | 
						|
  lib,
 | 
						|
  ...
 | 
						|
}: {
 | 
						|
  options = {
 | 
						|
    host.restic = {
 | 
						|
      enable = lib.mkEnableOption "enable restic";
 | 
						|
      passwordFile = lib.mkOption {
 | 
						|
        type = lib.types.path;
 | 
						|
        description = "path to the file containing the restic repository password.";
 | 
						|
      };
 | 
						|
      repositoryFile = lib.mkOption {
 | 
						|
        type = lib.types.nullOr lib.types.path;
 | 
						|
        description = "path to the file containing the restic repository url/path";
 | 
						|
        default = null;
 | 
						|
      };
 | 
						|
      repository = lib.mkOption {
 | 
						|
        type = lib.types.nullOr lib.types.str;
 | 
						|
        default = null;
 | 
						|
        description = "restic repository url/path";
 | 
						|
      };
 | 
						|
      server = {
 | 
						|
        enable = lib.mkEnableOption "enable restic server (must have nginx enabled and setup, and host.restic.passwordFile populated.)";
 | 
						|
        repositoryPath = lib.mkOption {
 | 
						|
          type = lib.types.path;
 | 
						|
          description = "path of repository";
 | 
						|
        };
 | 
						|
        htpasswdPath = lib.mkOption {
 | 
						|
          type = lib.types.nullOr lib.types.path;
 | 
						|
          description = "path to the repositories .htpasswd file";
 | 
						|
          default = null;
 | 
						|
        };
 | 
						|
        domain = lib.mkOption {
 | 
						|
          type = lib.types.str;
 | 
						|
          description = "domain name to serve the restic server under. (for nginx virtualHosts)";
 | 
						|
        };
 | 
						|
        port = lib.mkOption {
 | 
						|
          type = lib.types.str;
 | 
						|
          description = "(internal) port to use between nginx and restic-server";
 | 
						|
        };
 | 
						|
      };
 | 
						|
      backups = lib.mkOption {
 | 
						|
        description = "backups to create";
 | 
						|
        default = {};
 | 
						|
        type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
 | 
						|
          options = {
 | 
						|
            paths = lib.mkOption {
 | 
						|
              type = lib.types.listOf lib.types.path;
 | 
						|
              description = "paths to back up.";
 | 
						|
            };
 | 
						|
            user = lib.mkOption {
 | 
						|
              type = lib.types.str;
 | 
						|
              description = "what user to run the backup under.";
 | 
						|
              default = "root";
 | 
						|
            };
 | 
						|
            preBackupCommands = lib.mkOption {
 | 
						|
              type = lib.types.nullOr lib.types.lines;
 | 
						|
              description = "commands to run before the start of the backup.";
 | 
						|
              default = null;
 | 
						|
            };
 | 
						|
            postBackupCommands = lib.mkOption {
 | 
						|
              type = lib.types.nullOr lib.types.lines;
 | 
						|
              description = "commands to run after the backup is finished.";
 | 
						|
              default = null;
 | 
						|
            };
 | 
						|
          };
 | 
						|
        }));
 | 
						|
      };
 | 
						|
    };
 | 
						|
  };
 | 
						|
  config = let
 | 
						|
    cfg = config.host.restic;
 | 
						|
    timer = {
 | 
						|
      OnCalendar = "daily";
 | 
						|
      Persistent = true;
 | 
						|
      RandomizedDelaySec = "4h";
 | 
						|
    };
 | 
						|
    pruneOpts = [
 | 
						|
      "--keep-within 14d"
 | 
						|
      "--keep-daily 14"
 | 
						|
      "--keep-weekly 8"
 | 
						|
      "--keep-monthly 12"
 | 
						|
      "--keep-yearly 10"
 | 
						|
    ];
 | 
						|
  in {
 | 
						|
    environment.systemPackages =
 | 
						|
      lib.mkIf
 | 
						|
      (cfg.server.enable || cfg.enable)
 | 
						|
      (with pkgs; [
 | 
						|
        restic
 | 
						|
      ]);
 | 
						|
 | 
						|
    services.restic.server = lib.mkIf cfg.server.enable {
 | 
						|
      enable = true;
 | 
						|
      appendOnly = true;
 | 
						|
      dataDir = cfg.server.repositoryPath;
 | 
						|
      listenAddress = "127.0.0.1:${cfg.server.port}";
 | 
						|
      htpasswd-file = cfg.server.htpasswdPath;
 | 
						|
    };
 | 
						|
 | 
						|
    #Restic submits some huge requests sometimes.
 | 
						|
    services.nginx =
 | 
						|
      lib.mkIf (
 | 
						|
        cfg.server.enable
 | 
						|
        && (lib.asserts.assertMsg
 | 
						|
          (config.services.nginx.enable == true)
 | 
						|
          "NGINX must be enabled")
 | 
						|
      )
 | 
						|
      {
 | 
						|
        clientMaxBodySize = "1000m";
 | 
						|
        virtualHosts."${cfg.server.domain}" = {
 | 
						|
          enableACME = lib.asserts.assertMsg (
 | 
						|
            config.security.acme.acceptTerms
 | 
						|
            == true
 | 
						|
            && config.security.acme.defaults.email != null
 | 
						|
          ) "ACME must be setup";
 | 
						|
          forceSSL = true;
 | 
						|
          locations."/" = {
 | 
						|
            proxyPass = "http://localhost:${cfg.server.port}";
 | 
						|
          };
 | 
						|
        };
 | 
						|
      };
 | 
						|
 | 
						|
    services.restic.backups = lib.mkMerge [
 | 
						|
      (lib.mkIf cfg.server.enable {
 | 
						|
        prune = {
 | 
						|
          repository = cfg.server.repositoryPath;
 | 
						|
          passwordFile = cfg.passwordFile;
 | 
						|
          initialize = true;
 | 
						|
          runCheck = true;
 | 
						|
          paths = null;
 | 
						|
          timerConfig = timer;
 | 
						|
          pruneOpts = pruneOpts;
 | 
						|
          user = "restic";
 | 
						|
        };
 | 
						|
      })
 | 
						|
      (
 | 
						|
        lib.mkIf cfg.enable (
 | 
						|
          builtins.mapAttrs (
 | 
						|
            name: backup: {
 | 
						|
              repositoryFile = cfg.repositoryFile;
 | 
						|
              repository = cfg.repository;
 | 
						|
              passwordFile = cfg.passwordFile;
 | 
						|
              timerConfig = timer;
 | 
						|
              backupPrepareCommand = backup.preBackupCommands;
 | 
						|
              backupCleanupCommand = backup.postBackupCommands;
 | 
						|
              paths = backup.paths;
 | 
						|
              user = backup.user;
 | 
						|
            }
 | 
						|
          )
 | 
						|
          cfg.backups
 | 
						|
        )
 | 
						|
      )
 | 
						|
    ];
 | 
						|
  };
 | 
						|
}
 |