refactor(nginx): fastcgi params

This commit is contained in:
arcnmx 2024-04-20 15:08:27 -07:00
parent aa13db5f96
commit 818106a50f
8 changed files with 197 additions and 83 deletions

View file

@ -1,7 +1,7 @@
{ config, lib, inputs, pkgs, ... }: let { config, lib, gensokyo-zone, pkgs, ... }: let
inherit (inputs.self.lib.lib) mkAlmostOptionDefault mapOptionDefaults; inherit (gensokyo-zone.lib) mkAlmostOptionDefault mapOptionDefaults unmerged;
inherit (lib.options) mkOption mkEnableOption mkPackageOption; 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.attrsets) mapAttrs' nameValuePair;
inherit (lib.lists) isList imap0; inherit (lib.lists) isList imap0;
inherit (lib.strings) concatStringsSep; inherit (lib.strings) concatStringsSep;
@ -77,8 +77,17 @@ in {
nginxConfig = mkOption { nginxConfig = mkOption {
type = lines; type = lines;
}; };
nginxPhpConfig = mkOption { nginxPhpLocation = mkOption {
type = lines; 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; DISABLE_AUTHENTICATION = false;
DATABASE_PATH = cfg.databasePath; DATABASE_PATH = cfg.databasePath;
AUTHDB_PATH = cfg.authDatabasePath; AUTHDB_PATH = cfg.authDatabasePath;
CONFIG_PATH = "${pkgs.writeText "barcodebuddy.conf.php" ""}"; CONFIG_PATH = "${pkgs.writeText "barcodebuddy.conf.php" cfg.phpConfig}";
}; };
redis = mapOptionDefaults { redis = mapOptionDefaults {
USE_REDIS = cfg.redis.enable; USE_REDIS = cfg.redis.enable;
@ -101,19 +110,19 @@ in {
REDIS_PW = toString cfg.redis.password; REDIS_PW = toString cfg.redis.password;
}; };
in mkMerge [ defaults (mkIf cfg.redis.enable redis) ]; in mkMerge [ defaults (mkIf cfg.redis.enable redis) ];
nginxConfig = mkMerge [ nginxConfig = ''
'' index index.php index.html index.htm;
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};
''; '';
nginxPhpSettings = {
fastcgi = {
enable = true;
phpfpmPool = "barcodebuddy";
passHeaders.X-Accel-Buffering = mkIf cfg.reverseProxy.enable (mkOptionDefault true);
};
extraConfig = ''
fastcgi_read_timeout 80s;
'';
};
redis = let redis = let
redis = config.services.redis.servers.${cfg.redis.server}; redis = config.services.redis.servers.${cfg.redis.server};
in mkIf (cfg.redis.server != null) { in mkIf (cfg.redis.server != null) {
@ -175,7 +184,7 @@ in {
"/api/".extraConfig = '' "/api/".extraConfig = ''
try_files $uri /api/index.php$is_args$query_string; try_files $uri /api/index.php$is_args$query_string;
''; '';
"~ \\.php$".extraConfig = cfg.nginxPhpConfig; ${cfg.nginxPhpLocation} = unmerged.merge cfg.nginxPhpSettings;
}; };
extraConfig = cfg.nginxConfig; extraConfig = cfg.nginxConfig;
}; };

View file

@ -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]);
};
};
}

View file

@ -11,6 +11,10 @@
if ($http_x_forwarded_proto) { if ($http_x_forwarded_proto) {
${xvars.init "scheme" "$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) { if ($http_x_real_ip) {
${xvars.init "remote_addr" "$http_x_real_ip"} ${xvars.init "remote_addr" "$http_x_real_ip"}
} }
@ -49,6 +53,11 @@
}; };
redirect.enable = mkIf cfg.enabled (mkAlmostOptionDefault true); redirect.enable = mkIf cfg.enabled (mkAlmostOptionDefault true);
}; };
fastcgi = {
passHeaders = {
X-Accel-Buffering = mkOptionDefault true;
};
};
xvars.enable = mkIf cfg.enabled true; xvars.enable = mkIf cfg.enabled true;
extraConfig = mkMerge [ extraConfig = mkMerge [
(mkIf emitVars ( (mkIf emitVars (

View file

@ -93,9 +93,8 @@ let
xvars.get.proxy_host xvars.get.proxy_host
]; ];
rewriteReferer = '' rewriteReferer = ''
set $x_set_referer ${xvars.get.referer};
if (${xvars.get.referer_host} = $host) { 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 = '' redirect = ''
@ -106,6 +105,7 @@ let
name: value: "proxy_set_header ${name} ${xvars.escapeString value};" name: value: "proxy_set_header ${name} ${xvars.escapeString value};"
) setHeaders'); ) setHeaders');
in { in {
xvars.enable = mkIf cfg.headers.rewriteReferer.enable true;
proxy = { proxy = {
enabled = mkOptionDefault (config.proxyPass != null); enabled = mkOptionDefault (config.proxyPass != null);
path = mkIf (hasPrefix "/" name) (mkOptionDefault name); path = mkIf (hasPrefix "/" name) (mkOptionDefault name);
@ -122,7 +122,7 @@ let
Host = mkIf (cfg.headers.enableRecommended != "nixpkgs") (mkAlmostOptionDefault cfg.host); Host = mkIf (cfg.headers.enableRecommended != "nixpkgs") (mkAlmostOptionDefault cfg.host);
}) })
(mkIf cfg.headers.rewriteReferer.enable { (mkIf cfg.headers.rewriteReferer.enable {
Referer = mkAlmostOptionDefault "$x_set_referer"; Referer = mkAlmostOptionDefault xvars.get.referer;
}) })
(mkIf cfg.websocket.enable (mapOptionDefaults { (mkIf cfg.websocket.enable (mapOptionDefaults {
Upgrade = "$http_upgrade"; Upgrade = "$http_upgrade";

View file

@ -33,6 +33,7 @@ let
forwarded_server = host; forwarded_server = host;
host = "$host"; host = "$host";
referer = "$http_referer"; referer = "$http_referer";
https = "$https";
proxy_host = null; proxy_host = null;
proxy_scheme = null; proxy_scheme = null;
}; };
@ -57,7 +58,8 @@ let
name: value: "set $x_${name} ${escapeString value};" name: value: "set $x_${name} ${escapeString value};"
) (filterAttrs (_: value: value != null) cfg.defaults)); ) (filterAttrs (_: value: value != null) cfg.defaults));
parseReferer = '' parseReferer = ''
if (${xvars.get.referer} ~ "^(https?)://([^/]*)(/.*)$") { set $hack_referer $http_referer;
if ($hack_referer ~ "^(https?)://([^/]+)(/.*)$") {
${xvars.init "referer_scheme" "$1"} ${xvars.init "referer_scheme" "$1"}
${xvars.init "referer_host" "$2"} ${xvars.init "referer_host" "$2"}
${xvars.init "referer_path" "$3"} ${xvars.init "referer_path" "$3"}

View file

@ -51,6 +51,8 @@ in {
virtualHosts = { virtualHosts = {
grocy'php = mkIf grocy.enable { grocy'php = mkIf grocy.enable {
inherit serverName; inherit serverName;
proxied.enable = true;
local.denyGlobal = true;
}; };
grocy = mkMerge [ luaAuthHost { grocy = mkMerge [ luaAuthHost {
inherit name extraConfig locations; inherit name extraConfig locations;

View file

@ -1,36 +1,27 @@
{config, lib, ...}: let {config, access, lib, ...}: let
inherit (lib.modules) mkIf mkMerge mkAfter mkDefault; inherit (lib.modules) mkIf mkDefault;
inherit (config.services) nginx; inherit (config.services) nginx;
cfg = config.services.barcodebuddy; cfg = config.services.barcodebuddy;
in { in {
config.services.barcodebuddy = { config.services.barcodebuddy = {
enable = mkDefault true; enable = mkDefault true;
hostName = mkDefault "barcodebuddy'php"; hostName = mkDefault "barcodebuddy'php";
reverseProxy.enable = mkDefault true; reverseProxy = {
enable = mkDefault nginx.virtualHosts.${cfg.hostName}.proxied.enable;
trustedAddresses = access.cidrForNetwork.allLan.all;
};
settings = { settings = {
EXTERNAL_GROCY_URL = "https://grocy.${config.networking.domain}"; EXTERNAL_GROCY_URL = "https://grocy.${config.networking.domain}";
DISABLE_AUTHENTICATION = true; DISABLE_AUTHENTICATION = true;
}; };
nginxConfig = let nginxPhpSettings.extraConfig = ''
xvars = nginx.virtualHosts.barcodebuddy'php.xvars.lib; include ${config.sops.secrets.barcodebuddy-fastcgi-params.path};
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};
''))
];
}; };
config.services.nginx.virtualHosts.barcodebuddy'php = mkIf cfg.enable { config.services.nginx.virtualHosts.${cfg.hostName} = mkIf cfg.enable {
proxied.enable = cfg.reverseProxy.enable;
name.shortServer = mkDefault "bbuddy"; name.shortServer = mkDefault "bbuddy";
proxied.enable = mkDefault true;
local.denyGlobal = mkDefault true;
}; };
config.users.users.barcodebuddy = mkIf cfg.enable { config.users.users.barcodebuddy = mkIf cfg.enable {
uid = 912; uid = 912;

View file

@ -1,5 +1,5 @@
{config, lib, ...}: let {config, lib, ...}: let
inherit (lib.modules) mkIf mkDefault mkAfter; inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
cfg = config.services.grocy; cfg = config.services.grocy;
in { in {
config = { config = {
@ -12,50 +12,57 @@ in {
}; };
}; };
services.nginx.virtualHosts = { services.nginx.virtualHosts = {
grocy'php = mkIf cfg.enable ({config, xvars, ...}: let grocy'php = mkIf cfg.enable ({config, ...}: let
extraConfig = mkAfter '' authHeader = "GENSO_GROCY_USER";
set $grocy_user guest; extraConfig = mkMerge [
set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware; (mkBefore ''
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 = "") {
set $grocy_middleware Grocy\Middleware\DefaultAuthMiddleware; 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; if ($http_grocy_api_key) {
fastcgi_param GROCY_REVERSE_PROXY_AUTH_USE_ENV $grocy_auth_env; set $grocy_user "";
fastcgi_param GROCY_REVERSE_PROXY_AUTH_HEADER $grocy_auth_header; }
fastcgi_param GENSO_GROCY_USER $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 ($grocy_user) {
if (${xvars.get.scheme} = https) { set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware;
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;
'';
in { in {
name.shortServer = mkDefault "grocy"; name.shortServer = mkDefault "grocy";
proxied.enable = true;
xvars.enable = true;
local.denyGlobal = true;
locations."~ \\.php$" = { 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; inherit extraConfig;
}; };
}); });