diff --git a/modules/nixos/system/network/base/default.nix b/modules/nixos/system/network/base/default.nix index ddca69d..da4cb32 100644 --- a/modules/nixos/system/network/base/default.nix +++ b/modules/nixos/system/network/base/default.nix @@ -7,11 +7,12 @@ firewall = { enable = true; allowedUDPPorts = - (if config.syscfg.server ? wireguard then [ 1515 ] else [ ]) ++ + (if config.syscfg.server && config.syscfg.server.wireguard then [ 1515 ] else [ ]) ++ + (if config.syscfg.server && config.syscfg.server.web then [ 80 443 22 ] else [ ]) ++ [ ]; allowedTCPPorts = - (if config.syscfg.server ? web then [ 80 443 22 ] else [ ]) ++ + (if config.syscfg.server && config.syscfg.server.web then [ 80 443 22 ] else [ ]) ++ [ ]; }; }; diff --git a/modules/server/containers/builder.nix b/modules/server/containers/builder.nix index 8b4e113..86b186c 100644 --- a/modules/server/containers/builder.nix +++ b/modules/server/containers/builder.nix @@ -3,7 +3,7 @@ let builder = { image, secret ? "" , subdomain ? "", ip ? "", port ? 0 - , extraEnv ? { }, extraLabels ? { } + , extraEnv ? { }, extraLabels ? { }, extraOptions ? [ ] , overrides ? { } }: let base = { @@ -23,7 +23,7 @@ let "traefik.enable" = "false"; } // extraLabels; - extraOptions = [ + extraOptions = extraOptions ++ [ "--add-host=host.containers.internal:host-gateway" ] ++ lib.optional (ip != "") "--ip=${ip}"; }; diff --git a/modules/server/containers/defs/authentik.nix b/modules/server/containers/defs/authentik.nix index 30fe24e..99387b1 100644 --- a/modules/server/containers/defs/authentik.nix +++ b/modules/server/containers/defs/authentik.nix @@ -1,5 +1,6 @@ { config, containerCfg, pkgs, lib, builder, ... }: let +version = "2026.2.2"; serverCfg = config.syscfg.server; in { paths = [{ @@ -15,7 +16,7 @@ in { containers = { server = builder.mkContainer { subdomain = containerCfg.subdomain; - image = "ghcr.io/goauthentik/server:latest"; + image = "ghcr.io/goauthentik/server:${version}"; port = containerCfg.port; ip = containerCfg.ip; secret = "authentik"; @@ -31,10 +32,12 @@ in { "AUTHENTIK_EMAIL__USE_SSL" = "false"; "AUTHENTIK_EMAIL__TIMEOUT" = "10"; "AUTHENTIK_EMAIL__FROM" = "sso@noreply.${serverCfg.hostDomain}"; + "AUTHENTIK_DISABLE_UPDATE_CHECK" = "true"; + "AUTHENTIK_POSTGRESQL__SSLMODE" = "disable"; }; overrides = { cmd = [ "server" ]; - ports = [ "9999:${toString containerCfg.port}" ]; + ports = if containerCfg.pubPort != 0 && containerCfg.port != 0 then [ "${toString containerCfg.pubPort}:${toString containerCfg.port}" ] else []; volumes = [ "${serverCfg.dataPath}/authentik/media:/media" "${serverCfg.dataPath}/authentik/templates:/templates" @@ -43,20 +46,23 @@ in { }; worker = builder.mkContainer { - image = "ghcr.io/goauthentik/server:latest"; + image = "ghcr.io/goauthentik/server:${version}"; secret = "authentik"; extraEnv = { "AUTHENTIK_REDIS__HOST" = builder.host; "AUTHENTIK_POSTGRESQL__HOST" = builder.host; "AUTHENTIK_POSTGRESQL__USER" = "authentik_user"; "AUTHENTIK_POSTGRESQL__NAME" = "authentik_db"; + "AUTHENTIK_DISABLE_UPDATE_CHECK" = "true"; + "AUTHENTIK_POSTGRESQL__SSLMODE" = "disable"; }; + extraOptions = [ "--user=:994" ]; #PODMAN GROUP FOR SOCKET ACCESS overrides = { cmd = [ "worker" ]; volumes = [ "${serverCfg.dataPath}/authentik/media:/media" "${serverCfg.dataPath}/authentik/templates:/templates" - "/var/run/docker.sock:/var/run/docker.sock" + "/var/run/podman/podman.sock:/var/run/docker.sock" #PODMAN GROUP FOR SOCKET ACCESS ]; }; }; diff --git a/modules/server/default.nix b/modules/server/default.nix index 997ca33..d7010aa 100644 --- a/modules/server/default.nix +++ b/modules/server/default.nix @@ -1,3 +1,3 @@ { config, pkgs, lib, ... }:{ - imports = [ ./containers ./database ./nftables ./openssh ./sops ]; + imports = [ ./containers ./database ./nftables ./nginx ./openssh ./sops ]; } diff --git a/modules/server/nftables/default.nix b/modules/server/nftables/default.nix index 27a5322..3cd790b 100644 --- a/modules/server/nftables/default.nix +++ b/modules/server/nftables/default.nix @@ -1,5 +1,3 @@ - - { config, lib, ... }:{ config = lib.mkIf (config.syscfg.server.nftables.enable) { boot.kernel.sysctl = { @@ -11,8 +9,12 @@ networking.nftables.ruleset = '' table inet filter { chain input { - type filter hook input priority filter; policy accept; + type filter hook input priority filter; policy drop; + ct state established,related accept + iifname "lo" accept tcp dport {5432, 6379} ip saddr { 10.0.0.0/8 169.254.0.0/16 } accept + tcp dport {80, 443, 22} accept + udp dport {80, 443, 22} accept } } diff --git a/modules/server/nginx/default.nix b/modules/server/nginx/default.nix index d4ff5e3..bcbcfc0 100644 --- a/modules/server/nginx/default.nix +++ b/modules/server/nginx/default.nix @@ -1,45 +1,133 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: let cfg = config.syscfg.server; containers = cfg.containers; - - # Function to convert your container config into an NGINX vhost - mkVhost = name: container: { - forceSSL = true; - useACMEHost = "${cfg.hostDomain}"; - locations."/" = { - proxyPass = "http://${container.ip}:${toString container.port}"; - proxyWebsockets = true; # Recommended for modern apps + faviconOverride = { + " ~* /favicon\.(ico|png|svg|jpg)$" = { + extraConfig = '' + add_header Content-Type image/svg+xml; + return 200 ''; + ''; + # proxyPass = "http://127.0.0.1:9000"; }; }; + # Function to convert your container config into an NGINX vhost + mkVhost = container: { + forceSSL = true; + # quic = true; + # http3 = true; + useACMEHost = "${cfg.hostDomain}"; + locations = faviconOverride // { + "/" = { + proxyPass = "http://${container.ip}:${toString container.port}"; + proxyWebsockets = true; # Recommended for modern apps + }; + }; + }; + in { + config = lib.mkIf ( config.syscfg.server.web) { + security.acme = { + acceptTerms = true; + defaults.email = "admin@domain.org"; + certs."${cfg.hostDomain}" = { + domain = "*.${cfg.hostDomain}"; + extraDomainNames = [ "${cfg.hostDomain}" ]; # Adds the root too + dnsProvider = "infomaniak"; + credentialsFile = config.sops.secrets."INFOMANIAK_API_KEY".path; # File containing your API token (e.g. CLOUDFLARE_DNS_API_TOKEN=...) + group = "nginx"; + }; + }; -security.acme = { - acceptTerms = true; - defaults.email = "admin@domain.org"; + services.nginx = { + enable = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + recommendedGzipSettings = true; - certs."${cfg.hostDomain}" = { - domain = "*.${cfg.hostDomain}"; - extraDomainNames = [ "${cfg.hostDomain}" ]; # Adds the root too - dnsProvider = "cloudflare"; # Change to your provider - # File containing your API token (e.g. CLOUDFLARE_DNS_API_TOKEN=...) - credentialsFile = "/var/lib/secrets/acme-dns.env"; - group = "nginx"; + # appendHttpConfig = '' + # add_header Alt-Svc 'h3=":443"; ma=86400'; + # ''; + commonHttpConfig = '' + proxy_buffer_size 32k; + proxy_buffers 8 16k; + proxy_busy_buffers_size 48k; + port_in_redirect off; + ''; + + virtualHosts = { + "_" = { + default = true; + forceSSL = true; + # quic = true; + # http3 = true; + useACMEHost = "${cfg.hostDomain}"; + + locations = { + "/" = { + extraConfig = '' + return 404; + ''; + }; + }; + }; + "sec.localhost" = { + forceSSL = true; + # quic = true; + # http3 = true; + useACMEHost = "${cfg.hostDomain}"; + + locations = { + "/" = { + extraConfig = '' + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Original-URI $scheme://$http_host$request_uri; + auth_request /outpost.goauthentik.io/auth/nginx; + error_page 401 = @goauthentik_proxy_signin; + auth_request_set $auth_cookie $upstream_http_set_cookie; + add_header Set-Cookie $auth_cookie; + + auth_request_set $authentik_username $upstream_http_x_authentik_username; + auth_request_set $authentik_groups $upstream_http_x_authentik_groups; + auth_request_set $authentik_entitlements $upstream_http_x_authentik_entitlements; + auth_request_set $authentik_email $upstream_http_x_authentik_email; + auth_request_set $authentik_name $upstream_http_x_authentik_name; + auth_request_set $authentik_uid $upstream_http_x_authentik_uid; + + proxy_set_header X-authentik-username $authentik_username; + proxy_set_header X-authentik-groups $authentik_groups; + proxy_set_header X-authentik-entitlements $authentik_entitlements; + proxy_set_header X-authentik-email $authentik_email; + proxy_set_header X-authentik-name $authentik_name; + proxy_set_header X-authentik-uid $authentik_uid; + ''; + }; + + "/outpost.goauthentik.io" = { + proxyPass = "http://${config.syscfg.server.containers.authentik.ip}:${toString config.syscfg.server.containers.authentik.port}/outpost.goauthentik.io"; + extraConfig = '' + proxy_set_header Host $host; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Original-URI $scheme://$http_host$request_uri; + add_header Set-Cookie $auth_cookie; + auth_request_set $auth_cookie $upstream_http_set_cookie; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + ''; + }; + }; + extraConfig = '' + location @goauthentik_proxy_signin { + internal; + add_header Set-Cookie $auth_cookie; + return 302 https://sso.localhost/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri; + } + ''; + }; + } //lib.mapAttrs' (name: v: + lib.nameValuePair "${v.subdomain}.${cfg.hostDomain}" (mkVhost v) + ) containers; + }; }; -}; - - services.nginx = { - enable = true; - - recommendedProxySettings = true; - recommendedTlsSettings = true; - - virtualHosts = lib.mapAttrs' (name: value: - lib.nameValuePair "${value.subdomain}.${cfg.hostDomain}" (mkVhost name value) - ) cfg; - }; - - # Open the firewall - networking.firewall.allowedTCPPorts = [ 80 443 ]; -} +} \ No newline at end of file diff --git a/modules/shared/syscfg/default.nix b/modules/shared/syscfg/default.nix index 0ea4ea2..4c005e5 100644 --- a/modules/shared/syscfg/default.nix +++ b/modules/shared/syscfg/default.nix @@ -107,8 +107,10 @@ let options = { enable = mkOption { type = types.bool;default = false; }; db = mkOption { type = types.bool;default = false; }; - ip = mkOption { type = types.str; }; - port = mkOption { type = types.port; }; + ip = mkOption { type = types.nullOr types.str; default = null;}; + subdomain = mkOption { type = types.nullOr types.str; default=null;}; + port = mkOption { type = types.port; default = 0; }; + pubPort = mkOption { type = types.port; default = 0; }; extraParam = mkOption { type = types.str; default = ""; }; }; });