From 818106a50fc2c2700dda20fa19946ba69964553e Mon Sep 17 00:00:00 2001 From: arcnmx Date: Sat, 20 Apr 2024 15:08:27 -0700 Subject: [PATCH] refactor(nginx): fastcgi params --- modules/nixos/barcodebuddy.nix | 47 ++++++++++------- modules/nixos/nginx/fastcgi.nix | 94 +++++++++++++++++++++++++++++++++ modules/nixos/nginx/proxied.nix | 9 ++++ modules/nixos/nginx/proxy.nix | 6 +-- modules/nixos/nginx/xvars.nix | 4 +- nixos/access/grocy.nix | 2 + nixos/barcodebuddy.nix | 33 +++++------- nixos/grocy.nix | 85 +++++++++++++++-------------- 8 files changed, 197 insertions(+), 83 deletions(-) create mode 100644 modules/nixos/nginx/fastcgi.nix diff --git a/modules/nixos/barcodebuddy.nix b/modules/nixos/barcodebuddy.nix index 8c86cdc9..d7068f5a 100644 --- a/modules/nixos/barcodebuddy.nix +++ b/modules/nixos/barcodebuddy.nix @@ -1,7 +1,7 @@ -{ config, lib, inputs, pkgs, ... }: let - inherit (inputs.self.lib.lib) mkAlmostOptionDefault mapOptionDefaults; +{ config, lib, gensokyo-zone, pkgs, ... }: let + inherit (gensokyo-zone.lib) mkAlmostOptionDefault mapOptionDefaults unmerged; inherit (lib.options) mkOption mkEnableOption mkPackageOption; - inherit (lib.modules) mkIf mkMerge mkAfter mkDefault mkOptionDefault; + inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; inherit (lib.attrsets) mapAttrs' nameValuePair; inherit (lib.lists) isList imap0; inherit (lib.strings) concatStringsSep; @@ -77,8 +77,17 @@ in { nginxConfig = mkOption { type = lines; }; - nginxPhpConfig = mkOption { - type = lines; + nginxPhpLocation = mkOption { + type = str; + default = "~ \\.php$"; + }; + nginxPhpSettings = mkOption { + type = unmerged.type; + }; + phpConfig = mkOption { + type = str; + default = ""; + description = "CONFIG_PATH (conf.php) contents"; }; }; @@ -92,7 +101,7 @@ in { DISABLE_AUTHENTICATION = false; DATABASE_PATH = cfg.databasePath; AUTHDB_PATH = cfg.authDatabasePath; - CONFIG_PATH = "${pkgs.writeText "barcodebuddy.conf.php" ""}"; + CONFIG_PATH = "${pkgs.writeText "barcodebuddy.conf.php" cfg.phpConfig}"; }; redis = mapOptionDefaults { USE_REDIS = cfg.redis.enable; @@ -101,19 +110,19 @@ in { REDIS_PW = toString cfg.redis.password; }; in mkMerge [ defaults (mkIf cfg.redis.enable redis) ]; - nginxConfig = mkMerge [ - '' - index index.php index.html index.htm; - include ${config.services.nginx.package}/conf/fastcgi.conf; - fastcgi_read_timeout 80s; - '' - (mkIf cfg.reverseProxy.enable '' - fastcgi_pass_header "X-Accel-Buffering"; - '') - ]; - nginxPhpConfig = mkAfter '' - fastcgi_pass unix:${config.services.phpfpm.pools.barcodebuddy.socket}; + nginxConfig = '' + index index.php index.html index.htm; ''; + nginxPhpSettings = { + fastcgi = { + enable = true; + phpfpmPool = "barcodebuddy"; + passHeaders.X-Accel-Buffering = mkIf cfg.reverseProxy.enable (mkOptionDefault true); + }; + extraConfig = '' + fastcgi_read_timeout 80s; + ''; + }; redis = let redis = config.services.redis.servers.${cfg.redis.server}; in mkIf (cfg.redis.server != null) { @@ -175,7 +184,7 @@ in { "/api/".extraConfig = '' try_files $uri /api/index.php$is_args$query_string; ''; - "~ \\.php$".extraConfig = cfg.nginxPhpConfig; + ${cfg.nginxPhpLocation} = unmerged.merge cfg.nginxPhpSettings; }; extraConfig = cfg.nginxConfig; }; diff --git a/modules/nixos/nginx/fastcgi.nix b/modules/nixos/nginx/fastcgi.nix new file mode 100644 index 00000000..313dc10d --- /dev/null +++ b/modules/nixos/nginx/fastcgi.nix @@ -0,0 +1,94 @@ +let + locationModule = { + config, + virtualHost, + nixosConfig, + xvars, + gensokyo-zone, + lib, + ... + }: let + inherit (gensokyo-zone.lib) mapOptionDefaults mkAlmostBefore mkJustAfter mkAlmostOptionDefault; + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkMerge; + inherit (lib.attrsets) attrNames filterAttrs mapAttrsToList; + inherit (lib.trivial) id; + inherit (nixosConfig.services) nginx; + cfg = config.fastcgi; + passHeaders = attrNames (filterAttrs (_: id) cfg.passHeaders); + params = filterAttrs (_: value: value != null) cfg.params; + in { + options.fastcgi = with lib.types; { + enable = mkEnableOption "fastcgi_pass"; + phpfpmPool = mkOption { + type = nullOr str; + default = null; + }; + includeDefaults = mkOption { + type = bool; + default = true; + }; + passHeaders = mkOption { + type = attrsOf bool; + default = { }; + description = "fastcgi_pass_header"; + }; + socket = mkOption { + type = nullOr path; + }; + params = mkOption { + type = attrsOf (nullOr str); + }; + }; + + config = { + fastcgi = { + socket = mkIf (cfg.phpfpmPool != null) (mkAlmostOptionDefault + nixosConfig.services.phpfpm.pools.${cfg.phpfpmPool}.socket + ); + params = mapOptionDefaults { + HTTPS = "${xvars.get.https} if_not_empty"; + REQUEST_SCHEME = xvars.get.scheme; + HTTP_HOST = xvars.get.host; + HTTP_REFERER = "${xvars.get.referer} if_not_empty"; + REMOTE_ADDR = xvars.get.remote_addr; + # TODO: SERVER_ADDR + # TODO: SERVER_PORT + # TODO: SERVER_NAME? + }; + }; + extraConfig = let + passHeadersConfig = map (header: "fastcgi_pass_header ${xvars.escapeString header};") passHeaders; + paramsConfig = mapAttrsToList (param: value: mkJustAfter "fastcgi_param ${param} ${xvars.escapeString value};") params; + in mkIf cfg.enable (mkMerge ([ + (mkIf cfg.includeDefaults (mkAlmostBefore '' + include ${nginx.package}/conf/fastcgi.conf; + '')) + (mkIf (cfg.socket != null) (mkJustAfter '' + fastcgi_pass unix:${cfg.socket}; + '')) + ] ++ passHeadersConfig + ++ paramsConfig)); + }; + }; + hostModule = {config, lib, ...}: let + inherit (lib.options) mkOption; + in { + options = with lib.types; { + locations = mkOption { + type = attrsOf (submodule [locationModule]); + }; + }; + }; +in { + lib, + ... +}: let + inherit (lib.options) mkOption; +in { + options = with lib.types; { + services.nginx.virtualHosts = mkOption { + type = attrsOf (submodule [hostModule]); + }; + }; +} diff --git a/modules/nixos/nginx/proxied.nix b/modules/nixos/nginx/proxied.nix index 405dc615..e1d070b2 100644 --- a/modules/nixos/nginx/proxied.nix +++ b/modules/nixos/nginx/proxied.nix @@ -11,6 +11,10 @@ if ($http_x_forwarded_proto) { ${xvars.init "scheme" "$http_x_forwarded_proto"} } + ${xvars.init "https" ""} + if (${xvars.get.scheme} = https) { + ${xvars.init "https" "on"} + } if ($http_x_real_ip) { ${xvars.init "remote_addr" "$http_x_real_ip"} } @@ -49,6 +53,11 @@ }; redirect.enable = mkIf cfg.enabled (mkAlmostOptionDefault true); }; + fastcgi = { + passHeaders = { + X-Accel-Buffering = mkOptionDefault true; + }; + }; xvars.enable = mkIf cfg.enabled true; extraConfig = mkMerge [ (mkIf emitVars ( diff --git a/modules/nixos/nginx/proxy.nix b/modules/nixos/nginx/proxy.nix index 07f12323..a21f01a4 100644 --- a/modules/nixos/nginx/proxy.nix +++ b/modules/nixos/nginx/proxy.nix @@ -93,9 +93,8 @@ let xvars.get.proxy_host ]; rewriteReferer = '' - set $x_set_referer ${xvars.get.referer}; if (${xvars.get.referer_host} = $host) { - set $x_set_referer ${config.proxy.parsed.scheme}://${hostHeader}${xvars.get.referer_path}; + ${xvars.init "referer" "${config.proxy.parsed.scheme}://${hostHeader}${xvars.get.referer_path}"} } ''; redirect = '' @@ -106,6 +105,7 @@ let name: value: "proxy_set_header ${name} ${xvars.escapeString value};" ) setHeaders'); in { + xvars.enable = mkIf cfg.headers.rewriteReferer.enable true; proxy = { enabled = mkOptionDefault (config.proxyPass != null); path = mkIf (hasPrefix "/" name) (mkOptionDefault name); @@ -122,7 +122,7 @@ let Host = mkIf (cfg.headers.enableRecommended != "nixpkgs") (mkAlmostOptionDefault cfg.host); }) (mkIf cfg.headers.rewriteReferer.enable { - Referer = mkAlmostOptionDefault "$x_set_referer"; + Referer = mkAlmostOptionDefault xvars.get.referer; }) (mkIf cfg.websocket.enable (mapOptionDefaults { Upgrade = "$http_upgrade"; diff --git a/modules/nixos/nginx/xvars.nix b/modules/nixos/nginx/xvars.nix index 183dc293..c316bea6 100644 --- a/modules/nixos/nginx/xvars.nix +++ b/modules/nixos/nginx/xvars.nix @@ -33,6 +33,7 @@ let forwarded_server = host; host = "$host"; referer = "$http_referer"; + https = "$https"; proxy_host = null; proxy_scheme = null; }; @@ -57,7 +58,8 @@ let name: value: "set $x_${name} ${escapeString value};" ) (filterAttrs (_: value: value != null) cfg.defaults)); parseReferer = '' - if (${xvars.get.referer} ~ "^(https?)://([^/]*)(/.*)$") { + set $hack_referer $http_referer; + if ($hack_referer ~ "^(https?)://([^/]+)(/.*)$") { ${xvars.init "referer_scheme" "$1"} ${xvars.init "referer_host" "$2"} ${xvars.init "referer_path" "$3"} diff --git a/nixos/access/grocy.nix b/nixos/access/grocy.nix index be0dd0e3..76dc135c 100644 --- a/nixos/access/grocy.nix +++ b/nixos/access/grocy.nix @@ -51,6 +51,8 @@ in { virtualHosts = { grocy'php = mkIf grocy.enable { inherit serverName; + proxied.enable = true; + local.denyGlobal = true; }; grocy = mkMerge [ luaAuthHost { inherit name extraConfig locations; diff --git a/nixos/barcodebuddy.nix b/nixos/barcodebuddy.nix index d6297665..53d2a4fd 100644 --- a/nixos/barcodebuddy.nix +++ b/nixos/barcodebuddy.nix @@ -1,36 +1,27 @@ -{config, lib, ...}: let - inherit (lib.modules) mkIf mkMerge mkAfter mkDefault; +{config, access, lib, ...}: let + inherit (lib.modules) mkIf mkDefault; inherit (config.services) nginx; cfg = config.services.barcodebuddy; in { config.services.barcodebuddy = { enable = mkDefault true; hostName = mkDefault "barcodebuddy'php"; - reverseProxy.enable = mkDefault true; + reverseProxy = { + enable = mkDefault nginx.virtualHosts.${cfg.hostName}.proxied.enable; + trustedAddresses = access.cidrForNetwork.allLan.all; + }; settings = { EXTERNAL_GROCY_URL = "https://grocy.${config.networking.domain}"; DISABLE_AUTHENTICATION = true; }; - nginxConfig = let - xvars = nginx.virtualHosts.barcodebuddy'php.xvars.lib; - in mkMerge [ - '' - include ${config.sops.secrets.barcodebuddy-fastcgi-params.path}; - '' - (mkIf cfg.reverseProxy.enable (mkAfter '' - set $bbuddy_https ""; - if (${xvars.get.scheme} = https) { - set $bbuddy_https 1; - } - fastcgi_param HTTPS $bbuddy_https if_not_empty; - fastcgi_param REQUEST_SCHEME ${xvars.get.scheme}; - fastcgi_param HTTP_HOST ${xvars.get.host}; - '')) - ]; + nginxPhpSettings.extraConfig = '' + include ${config.sops.secrets.barcodebuddy-fastcgi-params.path}; + ''; }; - config.services.nginx.virtualHosts.barcodebuddy'php = mkIf cfg.enable { - proxied.enable = cfg.reverseProxy.enable; + config.services.nginx.virtualHosts.${cfg.hostName} = mkIf cfg.enable { name.shortServer = mkDefault "bbuddy"; + proxied.enable = mkDefault true; + local.denyGlobal = mkDefault true; }; config.users.users.barcodebuddy = mkIf cfg.enable { uid = 912; diff --git a/nixos/grocy.nix b/nixos/grocy.nix index 4b485e92..278786bb 100644 --- a/nixos/grocy.nix +++ b/nixos/grocy.nix @@ -1,5 +1,5 @@ {config, lib, ...}: let - inherit (lib.modules) mkIf mkDefault mkAfter; + inherit (lib.modules) mkIf mkMerge mkBefore mkDefault; cfg = config.services.grocy; in { config = { @@ -12,50 +12,57 @@ in { }; }; services.nginx.virtualHosts = { - grocy'php = mkIf cfg.enable ({config, xvars, ...}: let - extraConfig = mkAfter '' - set $grocy_user guest; - set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware; - set $grocy_auth_header GENSO_GROCY_USER; - set $grocy_auth_env true; - - if ($http_grocy_api_key) { - set $grocy_user ""; - } - if ($request_uri ~ "^/api(/.*|)$") { - set $grocy_user ""; - } - if ($http_x_vouch_user ~ "^([^@]+)@.*$") { - set $grocy_user $1; - } - if ($http_x_grocy_user) { - #set $grocy_auth_header X-Grocy-User; - #set $grocy_auth_env false; - set $grocy_user $http_x_grocy_user; - } - if ($grocy_user = "") { + grocy'php = mkIf cfg.enable ({config, ...}: let + authHeader = "GENSO_GROCY_USER"; + extraConfig = mkMerge [ + (mkBefore '' set $grocy_middleware Grocy\Middleware\DefaultAuthMiddleware; - } + set $grocy_user ""; + '') + (mkIf config.proxied.enable '' + set $grocy_user guest; + set $grocy_auth_header ${authHeader}; + set $grocy_auth_env true; - fastcgi_param GROCY_AUTH_CLASS $grocy_middleware; - fastcgi_param GROCY_REVERSE_PROXY_AUTH_USE_ENV $grocy_auth_env; - fastcgi_param GROCY_REVERSE_PROXY_AUTH_HEADER $grocy_auth_header; - fastcgi_param GENSO_GROCY_USER $grocy_user; + if ($http_grocy_api_key) { + set $grocy_user ""; + } + if ($request_uri ~ "^/api(/.*|)$") { + set $grocy_user ""; + } + if ($http_x_vouch_user ~ "^([^@]+)@.*$") { + set $grocy_user $1; + } + if ($http_x_grocy_user) { + #set $grocy_auth_header X-Grocy-User; + #set $grocy_auth_env false; + set $grocy_user $http_x_grocy_user; + } - set $grocy_https ""; - if (${xvars.get.scheme} = https) { - set $grocy_https 1; - } - fastcgi_param HTTP_HOST ${xvars.get.host}; - fastcgi_param REQUEST_SCHEME ${xvars.get.scheme}; - fastcgi_param HTTPS $grocy_https if_not_empty; - ''; + if ($grocy_user) { + set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware; + } + '') + ]; in { name.shortServer = mkDefault "grocy"; - proxied.enable = true; - xvars.enable = true; - local.denyGlobal = true; locations."~ \\.php$" = { + fastcgi = { + enable = true; + phpfpmPool = "grocy"; + socket = null; + includeDefaults = false; + params = mkMerge [ + { + GROCY_AUTH_CLASS = "$grocy_middleware"; + } + (mkIf config.proxied.enable { + GROCY_REVERSE_PROXY_AUTH_USE_ENV = "$grocy_auth_env"; + GROCY_REVERSE_PROXY_AUTH_HEADER = "$grocy_auth_header"; + ${authHeader} = "$grocy_user"; + }) + ]; + }; inherit extraConfig; }; });