diff --git a/modules/nixos/services/arr/jellyfin/default.nix b/modules/nixos/services/arr/jellyfin/default.nix index da5fc1d..99b3b3b 100644 --- a/modules/nixos/services/arr/jellyfin/default.nix +++ b/modules/nixos/services/arr/jellyfin/default.nix @@ -58,9 +58,34 @@ forceSSL = true; locations."/" = { proxyPass = "http://localhost:8096/"; + extraConfig = '' + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + ''; }; }; }; }; + + services.fail2ban.jails.jellyfin = { + enabled = true; + filter = "jellyfin"; + }; + + environment.etc = { + jellyfin = { + target = "fail2ban/filter.d/jellyfin.conf"; + text = '' + [INCLUDES] + before = common.conf + + [Definition] + failregex = ^.*Authentication request for .* has been denied \(IP: ""\)\. + ignoreregex = + journalmatch = _SYSTEMD_UNIT=jellyfin.service + ''; + }; + }; }; } diff --git a/modules/nixos/services/arr/jellyseerr/default.nix b/modules/nixos/services/arr/jellyseerr/default.nix index e299e8e..08b29c9 100644 --- a/modules/nixos/services/arr/jellyseerr/default.nix +++ b/modules/nixos/services/arr/jellyseerr/default.nix @@ -22,5 +22,20 @@ }; }; }; + environment.etc = { + jellyseerr = { + target = "fail2ban/filter.d/jellyseerr.conf"; + text = '' + [INCLUDES] + before = common.conf + + [Definition] + failregex = ^.*\[warn\]\[API\]: Failed sign-in attempt using invalid Overseerr password {"ip":"","email": + ^.*\[warn\]\[Auth\]: Failed login attempt from user with incorrect Jellyfin credentials {"account":{"ip":"","email": + ignoreregex = + journalmatch = _SYSTEMD_UNIT=jellyseerr.service + ''; + }; + }; }; } diff --git a/modules/nixos/services/fail2ban/default.nix b/modules/nixos/services/fail2ban/default.nix new file mode 100644 index 0000000..373d4e0 --- /dev/null +++ b/modules/nixos/services/fail2ban/default.nix @@ -0,0 +1,67 @@ +{ + config, + lib, + ... +}: { + options.snowflake.services.fail2ban = { + enable = lib.mkEnableOption "Enable fail2ban service"; + + extraIgnoreIPs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + description = "List of IPs to ignore for fail2ban alongside the default local subnets and loopback"; + }; + }; + + config = let + cfg = config.snowflake.services.fail2ban; + in + lib.mkIf cfg.enable { + services.fail2ban = { + enable = true; + maxretry = 3; + banaction-allports = "iptables-allports"; + + bantime-increment = { + enable = true; + maxtime = "168h"; + factor = "4"; + }; + + ignoreIPs = + [ + "192.168.69.0/16" + "172.16.0.0/12" + "127.0.0.0/8" + ] + ++ cfg.extraIgnoreIPs; + + jails = { + DEFAULT = { + blocktype = "DROP"; + bantime = "6h"; + findtime = "6h"; + }; + + sshd = { + settings = { + enabled = true; + findtime = "1d"; + maxretry = 4; + mode = "aggressive"; + port = "ssh"; + logpath = "%(sshd_log)s"; + backend = "%(sshd_backend)s"; + }; + }; + + port-scan = { + filter = "port-scan"; + action = "iptables-allports[name=port-scan]"; + bantime = 86400; + maxretry = 2; + }; + }; + }; + }; +} diff --git a/modules/nixos/services/gitea/default.nix b/modules/nixos/services/gitea/default.nix index 68658d9..e8dfa23 100644 --- a/modules/nixos/services/gitea/default.nix +++ b/modules/nixos/services/gitea/default.nix @@ -108,5 +108,22 @@ }; }; }; + + services.fail2ban.jails.gitea = { + enabled = true; + filter = "gitea"; + }; + + environment.etc = { + gitea = { + target = "fail2ban/filter.d/gitea.conf"; + text = '' + [Definition] + failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from + ignoreregex = + journalmatch = _SYSTEMD_UNIT=gitea.service + ''; + }; + }; }; } diff --git a/modules/nixos/services/immich/default.nix b/modules/nixos/services/immich/default.nix index 66650be..2bb3c6e 100644 --- a/modules/nixos/services/immich/default.nix +++ b/modules/nixos/services/immich/default.nix @@ -47,5 +47,25 @@ }; }; }; + + services.fail2ban.jails.immich = { + enabled = true; + filter = "immich"; + }; + + environment.etc = { + immich = { + target = "fail2ban/filter.d/immich.conf"; + text = '' + [INCLUDES] + before = common.conf + + [Definition] + failregex = ^.*Username or password is incorrect\. Try again\. IP: \. Username:.*$ + ignoreregex = + journalmatch = _SYSTEMD_UNIT=immich-server.service + ''; + }; + }; }; } diff --git a/modules/nixos/services/miniflux/default.nix b/modules/nixos/services/miniflux/default.nix index 01c9cdf..9a57228 100644 --- a/modules/nixos/services/miniflux/default.nix +++ b/modules/nixos/services/miniflux/default.nix @@ -1,5 +1,8 @@ -{ config, lib, ... }: { + config, + lib, + ... +}: { options.snowflake.services.miniflux = { enable = lib.mkEnableOption "Enable miniflux service"; @@ -20,10 +23,9 @@ }; }; - config = - let - cfg = config.snowflake.services.miniflux; - in + config = let + cfg = config.snowflake.services.miniflux; + in lib.mkIf cfg.enable { age.secrets.miniflux = { inherit (cfg.adminTokenFile) file; @@ -49,7 +51,6 @@ proxyPass = "http://localhost:${toString cfg.listenPort}"; extraConfig = '' proxy_redirect off; - proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; ''; @@ -57,5 +58,22 @@ }; }; }; + + services.fail2ban.jails.miniflux = { + enabled = true; + filter = "miniflux"; + }; + + environment.etc = { + miniflux = { + target = "fail2ban/filter.d/miniflux.conf"; + text = '' + [Definition] + failregex = ^.*msg="[^"]*(Incorrect|Invalid) username or password[^"]*".*client_ip= + ignoreregex = + journalmatch = _SYSTEMD_UNIT=miniflux.service + ''; + }; + }; }; } diff --git a/modules/nixos/services/ntfy-sh/default.nix b/modules/nixos/services/ntfy-sh/default.nix index b5c1fd4..2ceb359 100644 --- a/modules/nixos/services/ntfy-sh/default.nix +++ b/modules/nixos/services/ntfy-sh/default.nix @@ -48,7 +48,6 @@ proxy_redirect off; proxy_buffering off; proxy_request_buffering off; - proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; client_max_body_size 0; diff --git a/modules/nixos/services/paperless/default.nix b/modules/nixos/services/paperless/default.nix index bae1a68..13a10f7 100644 --- a/modules/nixos/services/paperless/default.nix +++ b/modules/nixos/services/paperless/default.nix @@ -73,5 +73,22 @@ echo ${path}/exported/ ''; }; + + services.fail2ban.jails.paperless = { + enabled = true; + filter = "paperless"; + }; + + environment.etc = { + paperless-ngx = { + target = "fail2ban/filter.d/paperless.conf"; + text = '' + [Definition] + failregex = Login failed for user `.*` from (?:IP|private IP) ``\.$ + ignoreregex = + journalmatch = _SYSTEMD_UNIT=paperless-web.service + ''; + }; + }; }; } diff --git a/modules/nixos/services/vaultwarden/default.nix b/modules/nixos/services/vaultwarden/default.nix index 45e988f..69b8151 100644 --- a/modules/nixos/services/vaultwarden/default.nix +++ b/modules/nixos/services/vaultwarden/default.nix @@ -77,5 +77,20 @@ snowflake.services.backups.config.vaultwarden.paths = [ "/var/lib/bitwarden_rs" ]; + + environment.etc = { + vaultwarden = { + target = "fail2ban/filter.d/vaultwarden.conf"; + text = '' + [INCLUDES] + before = common.conf + + [Definition] + failregex = ^.*Username or password is incorrect\. Try again\. IP: \. Username:.*$ + ignoreregex = + journalmatch = _SYSTEMD_UNIT=vaultwarden.service + ''; + }; + }; }; }