diff --git a/modules/nixos-modules/server/default.nix b/modules/nixos-modules/server/default.nix index e4a68c2..2b33089 100644 --- a/modules/nixos-modules/server/default.nix +++ b/modules/nixos-modules/server/default.nix @@ -1,8 +1,8 @@ {...}: { imports = [ ./reverseProxy - ./fail2ban.nix - ./postgres.nix + ./fail2ban + ./postgres ./network_storage ./actual @@ -17,7 +17,7 @@ ./lidarr ./panoramax ./paperless - ./qbittorent.nix + ./qbittorent ./radarr ./searx ./sonarr diff --git a/modules/nixos-modules/server/fail2ban.nix b/modules/nixos-modules/server/fail2ban.nix deleted file mode 100644 index d19aeeb..0000000 --- a/modules/nixos-modules/server/fail2ban.nix +++ /dev/null @@ -1,74 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: let - dataFolder = "/var/lib/fail2ban"; - dataFile = "fail2ban.sqlite3"; -in { - config = lib.mkIf config.services.fail2ban.enable (lib.mkMerge [ - { - environment.etc = { - "fail2ban/filter.d/nginx.local".text = lib.mkIf config.services.nginx.enable ( - pkgs.lib.mkDefault (pkgs.lib.mkAfter '' - [Definition] - failregex = "limiting requests, excess:.* by zone.*client: " - '') - ); - }; - - services.fail2ban = { - maxretry = 5; - ignoreIP = [ - # Whitelist local networks - "10.0.0.0/8" - "172.16.0.0/12" - "192.168.0.0/16" - - # tail scale tailnet - "100.64.0.0/10" - "fd7a:115c:a1e0::/48" - ]; - bantime = "24h"; # Ban IPs for one day on the first ban - bantime-increment = { - enable = true; # Enable increment of bantime after each violation - formula = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)"; - maxtime = "168h"; # Do not ban for more than 1 week - overalljails = true; # Calculate the ban time based on all the violations - }; - jails = { - nginx-iptables.settings = lib.mkIf config.services.nginx.enable { - enabled = true; - filter = "nginx"; - action = ''iptables-multiport[name=HTTP, port="http,https"]''; - backend = "auto"; - findtime = 600; - bantime = 600; - maxretry = 5; - }; - # TODO; figure out if there is any fail2ban things we can do on searx - # searx-iptables.settings = lib.mkIf config.services.searx.enable {}; - }; - }; - } - (lib.mkIf config.host.impermanence.enable { - assertions = [ - { - assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}"; - message = "fail2ban data file does not match persistence"; - } - ]; - - environment.persistence."/persist/system/root" = { - directories = [ - { - directory = dataFolder; - user = "fail2ban"; - group = "fail2ban"; - } - ]; - }; - }) - ]); -} diff --git a/modules/nixos-modules/server/fail2ban/default.nix b/modules/nixos-modules/server/fail2ban/default.nix new file mode 100644 index 0000000..30fca99 --- /dev/null +++ b/modules/nixos-modules/server/fail2ban/default.nix @@ -0,0 +1,6 @@ +{...}: { + imports = [ + ./fail2ban.nix + ./impermanence.nix + ]; +} diff --git a/modules/nixos-modules/server/fail2ban/fail2ban.nix b/modules/nixos-modules/server/fail2ban/fail2ban.nix new file mode 100644 index 0000000..261c68f --- /dev/null +++ b/modules/nixos-modules/server/fail2ban/fail2ban.nix @@ -0,0 +1,51 @@ +{ + lib, + pkgs, + config, + ... +}: { + config = lib.mkIf config.services.fail2ban.enable { + environment.etc = { + "fail2ban/filter.d/nginx.local".text = lib.mkIf config.services.nginx.enable ( + pkgs.lib.mkDefault (pkgs.lib.mkAfter '' + [Definition] + failregex = "limiting requests, excess:.* by zone.*client: " + '') + ); + }; + + services.fail2ban = { + maxretry = 5; + ignoreIP = [ + # Whitelist local networks + "10.0.0.0/8" + "172.16.0.0/12" + "192.168.0.0/16" + + # tail scale tailnet + "100.64.0.0/10" + "fd7a:115c:a1e0::/48" + ]; + bantime = "24h"; # Ban IPs for one day on the first ban + bantime-increment = { + enable = true; # Enable increment of bantime after each violation + formula = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)"; + maxtime = "168h"; # Do not ban for more than 1 week + overalljails = true; # Calculate the ban time based on all the violations + }; + jails = { + nginx-iptables.settings = lib.mkIf config.services.nginx.enable { + enabled = true; + filter = "nginx"; + action = ''iptables-multiport[name=HTTP, port="http,https"]''; + backend = "auto"; + findtime = 600; + bantime = 600; + maxretry = 5; + }; + # TODO; figure out if there is any fail2ban things we can do on searx + # searx-iptables.settings = lib.mkIf config.services.searx.enable {}; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/fail2ban/impermanence.nix b/modules/nixos-modules/server/fail2ban/impermanence.nix new file mode 100644 index 0000000..5bc4673 --- /dev/null +++ b/modules/nixos-modules/server/fail2ban/impermanence.nix @@ -0,0 +1,27 @@ +{ + lib, + config, + ... +}: let + dataFolder = "/var/lib/fail2ban"; + dataFile = "fail2ban.sqlite3"; +in { + config = lib.mkIf (config.services.fail2ban.enable && config.host.impermanence.enable) { + assertions = [ + { + assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}"; + message = "fail2ban data file does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = dataFolder; + user = "fail2ban"; + group = "fail2ban"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/postgres.nix b/modules/nixos-modules/server/postgres.nix deleted file mode 100644 index 71ce44c..0000000 --- a/modules/nixos-modules/server/postgres.nix +++ /dev/null @@ -1,121 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - dataDir = "/var/lib/postgresql/16"; - adminUsers = lib.lists.filter (user: user.isAdmin) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); - clientUsers = lib.lists.filter (user: user.isClient) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); - createUsers = lib.lists.filter (user: user.createUser) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); - createDatabases = lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraDatabases; -in { - options = { - host.postgres = { - enable = lib.mkEnableOption "enable postgres"; - extraUsers = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { - options = { - name = lib.mkOption { - type = lib.types.str; - default = name; - }; - isAdmin = lib.mkOption { - type = lib.types.bool; - default = false; - }; - isClient = lib.mkOption { - type = lib.types.bool; - default = false; - }; - createUser = lib.mkOption { - type = lib.types.bool; - default = false; - }; - }; - })); - default = {}; - }; - extraDatabases = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { - options = { - name = lib.mkOption { - type = lib.types.str; - default = name; - }; - }; - })); - default = {}; - }; - }; - }; - - config = lib.mkIf config.host.postgres.enable (lib.mkMerge [ - { - services = { - postgresql = { - enable = true; - package = pkgs.postgresql_16; - ensureUsers = - [ - { - name = "postgres"; - } - ] - ++ ( - builtins.map (user: { - name = user.name; - ensureDBOwnership = true; - }) - createUsers - ); - ensureDatabases = builtins.map (database: database.name) createDatabases; - identMap = - '' - # ArbitraryMapName systemUser DBUser - - # Administration Users - superuser_map root postgres - superuser_map postgres postgres - '' - + ( - lib.strings.concatLines (builtins.map (user: "superuser_map ${user.name} postgres") adminUsers) - ) - + '' - - # Client Users - '' - + ( - lib.strings.concatLines (builtins.map (user: "user_map ${user.name} ${user.name}") clientUsers) - ); - # configuration here lets users access the db that matches their name and lets user postgres access everything - authentication = pkgs.lib.mkOverride 10 '' - # type database DBuser origin-address auth-method optional_ident_map - local all postgres peer map=superuser_map - local sameuser all peer map=user_map - ''; - }; - }; - } - - (lib.mkIf config.host.impermanence.enable { - assertions = [ - { - assertion = config.services.postgresql.dataDir == dataDir; - message = "postgres data directory does not match persistence"; - } - ]; - environment.persistence."/persist/system/root" = { - enable = true; - hideMounts = true; - directories = [ - { - directory = dataDir; - user = "postgres"; - group = "postgres"; - } - ]; - }; - }) - ]); -} diff --git a/modules/nixos-modules/server/postgres/default.nix b/modules/nixos-modules/server/postgres/default.nix new file mode 100644 index 0000000..abf4ade --- /dev/null +++ b/modules/nixos-modules/server/postgres/default.nix @@ -0,0 +1,6 @@ +{...}: { + imports = [ + ./postgres.nix + ./impermanence.nix + ]; +} diff --git a/modules/nixos-modules/server/postgres/impermanence.nix b/modules/nixos-modules/server/postgres/impermanence.nix new file mode 100644 index 0000000..6c2d295 --- /dev/null +++ b/modules/nixos-modules/server/postgres/impermanence.nix @@ -0,0 +1,27 @@ +{ + config, + lib, + ... +}: let + dataDir = "/var/lib/postgresql/16"; +in { + config = lib.mkIf (config.host.postgres.enable && config.host.impermanence.enable) { + assertions = [ + { + assertion = config.services.postgresql.dataDir == dataDir; + message = "postgres data directory does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = dataDir; + user = "postgres"; + group = "postgres"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/postgres/postgres.nix b/modules/nixos-modules/server/postgres/postgres.nix new file mode 100644 index 0000000..e76857c --- /dev/null +++ b/modules/nixos-modules/server/postgres/postgres.nix @@ -0,0 +1,98 @@ +{ + config, + lib, + pkgs, + ... +}: let + adminUsers = lib.lists.filter (user: user.isAdmin) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); + clientUsers = lib.lists.filter (user: user.isClient) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); + createUsers = lib.lists.filter (user: user.createUser) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); + createDatabases = lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraDatabases; +in { + options = { + host.postgres = { + enable = lib.mkEnableOption "enable postgres"; + extraUsers = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + }; + isAdmin = lib.mkOption { + type = lib.types.bool; + default = false; + }; + isClient = lib.mkOption { + type = lib.types.bool; + default = false; + }; + createUser = lib.mkOption { + type = lib.types.bool; + default = false; + }; + }; + })); + default = {}; + }; + extraDatabases = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + }; + }; + })); + default = {}; + }; + }; + }; + + config = lib.mkIf config.host.postgres.enable { + services = { + postgresql = { + enable = true; + package = pkgs.postgresql_16; + ensureUsers = + [ + { + name = "postgres"; + } + ] + ++ ( + builtins.map (user: { + name = user.name; + ensureDBOwnership = true; + }) + createUsers + ); + ensureDatabases = builtins.map (database: database.name) createDatabases; + identMap = + '' + # ArbitraryMapName systemUser DBUser + + # Administration Users + superuser_map root postgres + superuser_map postgres postgres + '' + + ( + lib.strings.concatLines (builtins.map (user: "superuser_map ${user.name} postgres") adminUsers) + ) + + '' + + # Client Users + '' + + ( + lib.strings.concatLines (builtins.map (user: "user_map ${user.name} ${user.name}") clientUsers) + ); + # configuration here lets users access the db that matches their name and lets user postgres access everything + authentication = pkgs.lib.mkOverride 10 '' + # type database DBuser origin-address auth-method optional_ident_map + local all postgres peer map=superuser_map + local sameuser all peer map=user_map + ''; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/qbittorent.nix b/modules/nixos-modules/server/qbittorent.nix deleted file mode 100644 index 2d54587..0000000 --- a/modules/nixos-modules/server/qbittorent.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ - lib, - config, - ... -}: let - qbittorent_profile_directory = "/var/lib/qBittorrent/"; -in { - options.services.qbittorrent = { - mediaDir = lib.mkOption { - type = lib.types.path; - description = lib.mdDoc '' - The directory to create to store qbittorrent media. - ''; - }; - }; - - config = lib.mkIf config.services.qbittorrent.enable (lib.mkMerge [ - (lib.mkIf config.host.impermanence.enable { - fileSystems."/persist/system/qbittorrent".neededForBoot = true; - - host.storage.pool.extraDatasets = { - # sops age key needs to be available to pre persist for user generation - "persist/system/qbittorrent" = { - type = "zfs_fs"; - mountpoint = "/persist/system/qbittorrent"; - options = { - canmount = "on"; - }; - }; - }; - - assertions = [ - { - assertion = config.services.qbittorrent.profileDir == qbittorent_profile_directory; - message = "qbittorrent data directory does not match persistence"; - } - ]; - - environment.persistence = { - "/persist/system/root" = { - directories = [ - { - directory = qbittorent_profile_directory; - user = "qbittorrent"; - group = "qbittorrent"; - } - ]; - }; - - "/persist/system/qbittorrent" = { - enable = true; - hideMounts = true; - directories = [ - { - directory = config.services.qbittorrent.mediaDir; - user = "qbittorrent"; - group = "qbittorrent"; - mode = "1775"; - } - ]; - }; - }; - }) - ]); -} diff --git a/modules/nixos-modules/server/qbittorent/default.nix b/modules/nixos-modules/server/qbittorent/default.nix new file mode 100644 index 0000000..f7511e6 --- /dev/null +++ b/modules/nixos-modules/server/qbittorent/default.nix @@ -0,0 +1,6 @@ +{...}: { + imports = [ + ./qbittorent.nix + ./impermanence.nix + ]; +} diff --git a/modules/nixos-modules/server/qbittorent/impermanence.nix b/modules/nixos-modules/server/qbittorent/impermanence.nix new file mode 100644 index 0000000..da47d1a --- /dev/null +++ b/modules/nixos-modules/server/qbittorent/impermanence.nix @@ -0,0 +1,54 @@ +{ + lib, + config, + ... +}: let + qbittorent_profile_directory = "/var/lib/qBittorrent/"; +in { + config = lib.mkIf (config.services.qbittorrent.enable && config.host.impermanence.enable) { + fileSystems."/persist/system/qbittorrent".neededForBoot = true; + + host.storage.pool.extraDatasets = { + # sops age key needs to be available to pre persist for user generation + "persist/system/qbittorrent" = { + type = "zfs_fs"; + mountpoint = "/persist/system/qbittorrent"; + options = { + canmount = "on"; + }; + }; + }; + + assertions = [ + { + assertion = config.services.qbittorrent.profileDir == qbittorent_profile_directory; + message = "qbittorrent data directory does not match persistence"; + } + ]; + + environment.persistence = { + "/persist/system/root" = { + directories = [ + { + directory = qbittorent_profile_directory; + user = "qbittorrent"; + group = "qbittorrent"; + } + ]; + }; + + "/persist/system/qbittorrent" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = config.services.qbittorrent.mediaDir; + user = "qbittorrent"; + group = "qbittorrent"; + mode = "1775"; + } + ]; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/qbittorent/qbittorent.nix b/modules/nixos-modules/server/qbittorent/qbittorent.nix new file mode 100644 index 0000000..44603c8 --- /dev/null +++ b/modules/nixos-modules/server/qbittorent/qbittorent.nix @@ -0,0 +1,18 @@ +{ + lib, + config, + ... +}: { + options.services.qbittorrent = { + mediaDir = lib.mkOption { + type = lib.types.path; + description = lib.mdDoc '' + The directory to create to store qbittorrent media. + ''; + }; + }; + + config = lib.mkIf config.services.qbittorrent.enable { + # Main qbittorrent configuration goes here if needed + }; +}