# nodes is all the nodes { lib, config, nodes, pkgs, ... }: with lib; let name = "backup"; cfg = config.services.skynet."${name}"; enable_client = cfg.normal.backups != null && cfg.normal.backups != []; # since they should all have the same config we can do this base = { paths = cfg.normal.backups; exclude = cfg.normal.exclude; initialize = true; passwordFile = config.age.secrets.restic.path; pruneOpts = [ #"--keep-within 0y2m0d0h" #"--keep-monthly 2" ]; timerConfig = { OnCalendar = "daily"; Persistent = true; RandomizedDelaySec = "5h"; }; }; # takes nodes, # for each check if iut has teh abckup attribute, # then if the server is enabled, # then pull relevant dtails ownServers = builtins.listToAttrs (builtins.concatLists ( lib.attrsets.mapAttrsToList ( key: value: let backup = value.config.services.skynet.backup; backup_host = value.config.services.skynet.host; in if ( (builtins.hasAttr "backup" value.config.services.skynet) && backup.server.enable # chgeck that its not itself && backup_host.name != config.services.skynet.host.name && !backup.server.appendOnly ) then [ { name = backup_host.name; value = base // { repositoryFile = "/etc/skynet/restic/${backup_host.name}"; backupPrepareCommand = '' #!${pkgs.stdenv.shell} set -euo pipefail baseDir="/etc/skynet/restic" mkdir -p $baseDir cd $baseDir echo -n "rest:http://root:password@${backup_host.ip}:${toString backup.server.port}/root/${config.services.skynet.host.name}" > ${backup_host.name} # read in teh password #PW = `cat ${config.age.secrets.restic.path}` line=$(head -n 1 ${config.age.secrets.restic.path}) sed -i "s/password/$line/g" ${backup_host.name} ''; }; } ] else [] ) nodes )); in { imports = [ ./dns.nix ./nginx.nix ./acme.nix ]; # using https://github.com/greaka/ops/blob/818be4c4dea9129abe0f086d738df4cb0bb38288/apps/restic/options.nix as a base # https://git.hrnz.li/Ulli/nixos/src/commit/5edca2dfdab3ce52208e4dfd2b92951e500f8418/profiles/server/restic.nix # will eb enabled on every server options.services.skynet."${name}" = { enable = mkEnableOption "Skynet backup"; # what folders to backup normal = { backups = lib.mkOption { default = []; type = lib.types.listOf lib.types.str; description = '' A list of paths to backup. ''; }; exclude = lib.mkOption { default = []; type = lib.types.listOf lib.types.str; description = '' A list of paths to exclide . ''; }; }; # append only data so space limited secure = { backups = lib.mkOption { default = []; type = lib.types.listOf lib.types.str; description = '' A list of paths to backup. ''; }; exclude = lib.mkOption { default = []; type = lib.types.listOf lib.types.str; description = '' A list of paths to exclide . ''; }; }; server = { enable = mkEnableOption "Skynet backup Server"; port = mkOption { type = types.port; default = 8765; }; appendOnly = mkOption { type = types.bool; default = false; }; }; nuked = { enable = mkEnableOption "Nuked Backup server"; port = mkOption { type = types.port; default = 8765; }; appendOnly = mkOption { type = types.bool; default = false; }; }; }; config = mkMerge [ { # these values are anabled for every client environment.systemPackages = with pkgs; [ restic ]; } (mkIf cfg.server.enable { networking.firewall.allowedTCPPorts = [ cfg.server.port ]; age.secrets.restic_pw = { file = ../secrets/backup/restic_pw.age; path = "${config.services.restic.server.dataDir}/.htpasswd"; symlink = false; mode = "770"; owner = "restic"; group = "restic"; }; services.restic.server = { enable = true; listenAddress = "${config.services.skynet.host.ip}:${toString cfg.server.port}"; appendOnly = cfg.server.appendOnly; privateRepos = true; }; }) (mkIf enable_client { # client stuff here # A list of all login accounts. To create the password hashes, use # nix-shell -p apacheHttpd # htpasswd -nbB "" "password" | cut -d: -f2 age.secrets.restic.file = ../secrets/backup/restic.age; services.restic.backups = mkMerge [ ownServers { # merge teh two configs together # backblaze = base // { # # backupos for each server are stored in a folder under their name # repository = "b2:NixOS-Main2:/${config.services.skynet.host.name}"; # #environmentFile = config.age.secrets.backblaze.path; # }; } ]; }) # restic -r rest:https://skynet:testing@nuked.skynet.ie/ init (mkIf cfg.nuked.enable { assertions = [ { assertion = !cfg.server.enable; message = "Our backup and Nuked backup cannot co-exist"; } ]; services.skynet.acme.domains = [ "nuked.skynet.ie" ]; services.skynet.dns.records = [ { record = "nuked"; r_type = "CNAME"; value = config.services.skynet.host.name; } ]; services.nginx.virtualHosts = { "nuked.skynet.ie" = { forceSSL = true; useACMEHost = "skynet"; locations."/" = { proxyPass = "http://${config.services.restic.server.listenAddress}"; proxyWebsockets = true; }; }; }; networking.firewall.allowedTCPPorts = [ cfg.nuked.port ]; age.secrets.restic_pw = { file = ../secrets/backup/nuked.age; path = "${config.services.restic.server.dataDir}/.htpasswd"; symlink = false; mode = "770"; owner = "restic"; group = "restic"; }; services.restic.server = { enable = true; listenAddress = "${config.services.skynet.host.ip}:${toString cfg.server.port}"; appendOnly = cfg.nuked.appendOnly; privateRepos = true; }; }) ]; }