diff --git a/configuration.nix b/configuration.nix index 525e76b..d1f881b 100644 --- a/configuration.nix +++ b/configuration.nix @@ -120,6 +120,13 @@ signupAllowed = false; }; + # === Forgejo (Self-hosted Git) === + myModules.forgejo = { + enable = true; + domain = "git.ashisgreat.xyz"; + disableRegistration = true; # Admin only + }; + # === CrowdSec === myModules.crowdsec.enable = true; diff --git a/modules/adguard.nix b/modules/adguard.nix index 94caadc..a4920a9 100644 --- a/modules/adguard.nix +++ b/modules/adguard.nix @@ -47,16 +47,49 @@ in default = [ "194.242.2.2" "2a07:e340::2" ]; description = "Bootstrap DNS servers for resolving DoH upstream"; }; + + filters = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { + options = { + name = lib.mkOption { + type = lib.types.str; + description = "Friendly name for the filter list"; + }; + url = lib.mkOption { + type = lib.types.str; + description = "URL of the filter list (txt format)"; + }; + enabled = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether the filter is enabled"; + }; + }; + }); + default = [ + { name = "AdGuard DNS filter"; url = "https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt"; } + { name = "AdAway Default Blocklist"; url = "https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt"; } + { name = "HaGeZi Multi Light"; url = "https://hagezi.github.io/dns-blocklists/wildcard/light.txt"; } + { name = "OISD Basic"; url = "https://small.oisd.nl/"; } + { name = "Peter Lowe's List"; url = "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=adguard&showintro=0&mimetype=plaintext"; } + ]; + description = "DNS blocklists to maintain in AdGuard Home"; + }; }; config = lib.mkIf cfg.enable { + # Generate a temporary JSON file containing the filters for yq to inject + systemd.tmpfiles.rules = [ + "f /run/adguardhome_filters.json 0644 root root - ${builtins.toJSON { filters = map (f: { inherit (f) name url enabled; }) cfg.filters; }}" + ]; + services.adguardhome = { enable = true; host = "127.0.0.1"; port = cfg.port; settings = { dns = { - bind_hosts = [ "127.0.0.1" ]; + bind_hosts = [ "0.0.0.0" ]; port = 5353; upstream_dns = [ cfg.upstreamDoh ]; bootstrap_dns = cfg.bootstrapDns; @@ -104,11 +137,22 @@ in }; }; - # Give AdGuardHome access to ACME certificates + # Inject filters into AdGuardHome.yaml before starting systemd.services.adguardhome = { requires = [ "acme-${cfg.domain}.service" ]; after = [ "acme-${cfg.domain}.service" ]; serviceConfig.SupplementaryGroups = [ "acme" "nginx" ]; + serviceConfig.ReadOnlyPaths = [ "/var/lib/acme/${cfg.domain}" ]; + serviceConfig.SystemCallFilter = lib.mkForce []; # Allow yq-go to run its syscalls + preStart = lib.mkAfter '' + if [ -f /var/lib/private/AdGuardHome/AdGuardHome.yaml ]; then + ${pkgs.yq-go}/bin/yq -i ' + .filters = load("/run/adguardhome_filters.json").filters | + .tls.certificate_path = "/var/lib/acme/${cfg.domain}/fullchain.pem" | + .tls.private_key_path = "/var/lib/acme/${cfg.domain}/key.pem" + ' /var/lib/private/AdGuardHome/AdGuardHome.yaml + fi + ''; }; # Open firewall for DoT diff --git a/modules/crowdsec.nix b/modules/crowdsec.nix index 2d6f1fa..eeba0e8 100644 --- a/modules/crowdsec.nix +++ b/modules/crowdsec.nix @@ -91,6 +91,17 @@ in # Remediation profiles localConfig.profiles = [ + { + name = "block_non_de"; + filters = [ "Alert.Remediation == true && Alert.GetScope() == 'Ip' && Alert.Source.Cn != 'DE' && Alert.Source.Cn != ''" ]; + decisions = [ + { + type = "ban"; + duration = "24h"; + } + ]; + on_success = "break"; + } { name = "default_ip_remediation"; filters = [ "Alert.Remediation == true && Alert.GetScope() == 'Ip'" ]; @@ -106,6 +117,9 @@ in # Hub collections for common attack patterns hub = { + parsers = [ + "crowdsecurity/geoip-enrich" + ]; collections = [ "crowdsecurity/linux" "crowdsecurity/nginx" diff --git a/modules/default.nix b/modules/default.nix index c40f93e..d889fe1 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -10,5 +10,6 @@ ./crowdsec.nix ./backup.nix ./adguard.nix + ./forgejo.nix ]; } diff --git a/modules/forgejo.nix b/modules/forgejo.nix new file mode 100644 index 0000000..0a6e5cd --- /dev/null +++ b/modules/forgejo.nix @@ -0,0 +1,87 @@ +# Forgejo Module +# Provides: Self-hosted Git service (Fork of Gitea) +# +# Usage: +# myModules.forgejo = { +# enable = true; +# domain = "git.example.com"; +# }; + +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.myModules.forgejo; +in +{ + options.myModules.forgejo = { + enable = lib.mkEnableOption "Forgejo Git service"; + + port = lib.mkOption { + type = lib.types.port; + default = 3002; + description = "Internal port to run Forgejo on"; + }; + + domain = lib.mkOption { + type = lib.types.str; + example = "git.example.com"; + description = "Public domain name for Forgejo"; + }; + + disableRegistration = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Disable public user registration"; + }; + }; + + config = lib.mkIf cfg.enable { + services.forgejo = { + enable = true; + database.type = "postgres"; + + settings = { + server = { + DOMAIN = cfg.domain; + ROOT_URL = "https://${cfg.domain}/"; + HTTP_ADDR = "127.0.0.1"; + HTTP_PORT = cfg.port; + SSH_PORT = 2222; + START_SSH_SERVER = true; + SSH_LISTEN_ADDR = "0.0.0.0"; + }; + service = { + DISABLE_REGISTRATION = cfg.disableRegistration; + }; + session = { + COOKIE_SECURE = true; + }; + security = { + PASSWORD_COMPLEXITY = "lower,upper,digit,spec"; + MIN_PASSWORD_LENGTH = 12; + }; + }; + }; + + # Nginx Reverse Proxy + myModules.nginx.domains."${cfg.domain}" = { + port = cfg.port; + extraConfig = '' + client_max_body_size 512M; + ''; + }; + + # Open SSH port for Git + networking.firewall.allowedTCPPorts = [ 2222 ]; + + # Backups (Add Forgejo data to restic if backup module is enabled) + myModules.backup.paths = [ + config.services.forgejo.stateDir + ]; + }; +}