refactor(nginx): proxy upstream modules

This commit is contained in:
arcnmx 2024-04-21 17:17:07 -07:00
parent f7e00a2e64
commit 586efcae0e
21 changed files with 844 additions and 370 deletions

View file

@ -8,6 +8,7 @@
name.shortServer = mkDefault "bbuddy";
serverName = "@bbuddy_internal";
in {
config.services.nginx.vouch.enable = true;
config.services.nginx.virtualHosts = {
barcodebuddy'php = mkIf barcodebuddy.enable {
inherit serverName;

View file

@ -17,12 +17,13 @@ let
extraConfig = ''
ssl_verify_client optional_no_ca;
'';
locations' = domain: {
locations = {
"/" = { config, xvars, ... }: {
proxy = {
enable = true;
url = mkDefault access.proxyPass;
host = mkDefault domain;
host = mkDefault virtualHosts.freeipa.serverName;
ssl.host = mkDefault config.proxy.host;
headers = {
rewriteReferer.enable = true;
set = {
@ -37,15 +38,8 @@ let
};
proxyPass = mkDefault access.proxyPass;
recommendedProxySettings = false;
extraConfig = ''
proxy_ssl_server_name on;
proxy_ssl_name ${domain};
'';
};
};
locations = locations' virtualHosts.freeipa.serverName;
caLocations = locations' virtualHosts.freeipa'ca.serverName;
kTLS = mkDefault true;
in {
imports = let
inherit (meta) nixos;
@ -200,12 +194,12 @@ in {
kticket4 = mkKrb5Server null "ticket4";
};
};
conf.upstreams.ldap'access.servers.ldaps.enable = false;
conf.servers = {
ldap = {
listen = {
ldaps.port = mkIf access.preread.enable (mkDefault access.preread.ldapPort);
};
proxy.upstream = mkDefault "ldap";
ssl.cert.copyFromVhost = mkDefault "freeipa";
};
};
@ -240,7 +234,7 @@ in {
in {
freeipa = {
name.shortServer = mkDefault "idp";
inherit locations extraConfig kTLS;
inherit locations extraConfig;
ssl.force = mkDefault true;
};
freeipa'web = {
@ -248,21 +242,26 @@ in {
force = mkDefault virtualHosts.freeipa.ssl.force;
cert.copyFromVhost = "freeipa";
};
inherit name locations extraConfig kTLS;
inherit name locations extraConfig;
};
freeipa'ca = {
name.shortServer = mkDefault "idp-ca";
locations = caLocations;
locations."/" = mkMerge [
locations."/"
{
proxy.host = virtualHosts.freeipa'ca.serverName;
}
];
ssl = {
force = mkDefault virtualHosts.freeipa.ssl.force;
cert.copyFromVhost = "freeipa";
};
inherit extraConfig kTLS;
inherit extraConfig;
};
freeipa'web'local = {
ssl.cert.copyFromVhost = "freeipa'web";
local.enable = true;
inherit name locations kTLS;
inherit name locations;
};
freeipa'ldap = {
serverName = mkDefault ldap.domain;

View file

@ -51,14 +51,13 @@ in {
}
];
name.shortServer = mkDefault "pbx";
kTLS = mkDefault true;
in {
freepbx = {
vouch.enable = mkDefault true;
ssl.force = true;
proxy.url = mkDefault url;
locations = allLocations;
inherit name extraConfig kTLS;
inherit name extraConfig;
};
freepbx'ucp = {
serverName = mkDefault nginx.virtualHosts.freepbx.serverName;
@ -83,7 +82,7 @@ in {
locations = {
inherit (locations) "/socket.io";
};
inherit extraConfig kTLS;
inherit extraConfig;
};
freepbx'local = {
listen' = {
@ -101,7 +100,7 @@ in {
proxy.url = mkDefault nginx.virtualHosts.freepbx.proxy.url;
local.enable = true;
locations = allLocations;
inherit name extraConfig kTLS;
inherit name extraConfig;
};
};
};

View file

@ -48,6 +48,7 @@
in {
config.services.nginx = {
lua.http.enable = true;
vouch.enable = true;
virtualHosts = {
grocy'php = mkIf grocy.enable {
inherit serverName;

View file

@ -1,11 +1,10 @@
{
config,
lib,
access,
...
}: let
inherit (lib.modules) mkDefault;
inherit (config.services) home-assistant nginx;
inherit (lib.modules) mkIf mkDefault;
inherit (config.services) nginx home-assistant;
name.shortServer = mkDefault "home";
listen' = {
http = { };
@ -16,35 +15,55 @@
extraParameters = [ "default_server" ];
};
};
upstreamName = "home-assistant'access";
in {
config.services.nginx.virtualHosts = {
home-assistant = {
inherit name;
locations."/" = {
proxy = {
websocket.enable = true;
headers.enableRecommended = true;
config.services.nginx = {
upstreams'.${upstreamName}.servers = {
local = {
enable = mkDefault home-assistant.enable;
addr = mkDefault "localhost";
port = mkIf home-assistant.enable (mkDefault home-assistant.config.http.server_port);
};
service = { upstream, ... }: {
enable = mkIf upstream.servers.local.enable (mkDefault false);
accessService = {
name = "home-assistant";
};
proxyPass = mkDefault (
if home-assistant.enable then "http://localhost:${toString home-assistant.config.http.server_port}"
else access.proxyUrlFor { serviceName = "home-assistant"; }
);
};
};
home-assistant'local = {
inherit name listen';
ssl.cert.copyFromVhost = "home-assistant";
local.enable = mkDefault true;
locations."/" = {
proxy = {
websocket.enable = true;
headers.enableRecommended = true;
virtualHosts = let
copyFromVhost = mkDefault "home-assistant";
locations = {
"/" = {
proxy.enable = true;
};
proxyPass = (mkDefault
nginx.virtualHosts.home-assistant.locations."/".proxyPass
);
"/api/websocket" = {
proxy = {
enable = true;
websocket.enable = true;
};
};
};
in {
home-assistant = {
inherit name locations;
proxy.upstream = mkDefault upstreamName;
};
home-assistant'local = {
inherit name listen' locations;
ssl.cert = {
inherit copyFromVhost;
};
proxy = {
inherit copyFromVhost;
};
local.enable = mkDefault true;
};
};
};
config.networking.firewall.allowedTCPPorts = [ home-assistant.config.http.server_port ];
config.networking.firewall.allowedTCPPorts = let
inherit (nginx.virtualHosts.home-assistant'local) listen';
in mkIf nginx.virtualHosts.home-assistant'local.enable [
(mkIf listen'.hass.enable listen'.hass.port)
];
}

View file

@ -1,15 +1,28 @@
{
config,
access,
lib,
...
}: let
inherit (lib.modules) mkMerge mkBefore mkDefault;
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
inherit (lib.strings) replaceStrings concatStringsSep concatMapStringsSep escapeRegex;
inherit (config.services.nginx) virtualHosts;
cfg = config.services.invidious;
upstreamName = "invidious'access";
in {
config.services.nginx = {
upstreams'.${upstreamName}.servers = {
local = {
enable = mkDefault cfg.enable;
addr = mkDefault "localhost";
port = mkIf cfg.enable (mkDefault cfg.port);
};
service = { upstream, ... }: {
enable = mkIf upstream.servers.local.enable (mkDefault false);
accessService = {
name = "invidious";
};
};
};
virtualHosts = let
invidiousDomains =
virtualHosts.invidious.allServerNames
@ -36,12 +49,11 @@ in {
'';
};
name.shortServer = mkDefault "yt";
kTLS = mkDefault true;
localDomains = virtualHosts.invidious'local.allServerNames;
in {
invidious = {
# lua can't handle HTTP 2.0 requests, so layer it behind another proxy...
inherit name extraConfig kTLS;
inherit name extraConfig;
proxy = {
url = mkDefault "http://localhost:${toString config.services.nginx.defaultHTTPListenPort}";
host = mkDefault virtualHosts.invidious'int.serverName;
@ -88,10 +100,7 @@ in {
};
proxy = {
host = mkDefault xvars.get.host;
url = mkDefault (if cfg.enable
then "http://localhost:${toString cfg.port}"
else access.proxyUrlFor { serviceName = "invidious"; }
);
upstream = mkDefault upstreamName;
};
locations = {
"/" = mkMerge [
@ -107,11 +116,11 @@ in {
local.enable = true;
ssl.cert.copyFromVhost = "invidious";
proxy = {
copyFromVhost = mkDefault "invidious'int";
host = mkDefault xvars.get.host;
url = mkDefault virtualHosts.invidious'int.proxy.url;
};
locations."/" = location;
inherit name extraConfig kTLS;
inherit name extraConfig;
};
};
lua.http.enable = true;

View file

@ -1,33 +1,49 @@
{
config,
lib,
access,
...
}: let
inherit (lib.modules) mkDefault;
inherit (lib.modules) mkIf mkDefault;
cfg = config.services.keycloak;
inherit (config.services) nginx;
upstreamName = "keycloak'access";
locations."/".proxy.enable = true;
name.shortServer = mkDefault "sso";
copyFromVhost = mkDefault "keycloak";
in {
config.services.nginx = {
upstreams'.${upstreamName}.servers = {
local = mkIf cfg.enable {
enable = mkDefault true;
addr = mkDefault "localhost";
port = mkDefault cfg.port;
ssl.enable = mkIf (cfg.protocol == "https") true;
};
access = { upstream, ... }: {
enable = mkDefault (!upstream.servers.local.enable or false);
accessService = {
name = "keycloak";
port = "https";
};
};
};
virtualHosts = {
keycloak = {
name.shortServer = mkDefault "sso";
inherit name locations;
ssl.force = mkDefault true;
locations."/".proxyPass = let
url = mkDefault "${cfg.protocol}://localhost:${toString cfg.port}";
in mkDefault (
if cfg.enable then url
else access.proxyUrlFor { serviceName = "keycloak"; portName = "https"; }
);
proxy.upstream = mkDefault upstreamName;
};
keycloak'local = {
name.shortServer = mkDefault "sso";
inherit name locations;
ssl = {
force = mkDefault true;
cert.copyFromVhost = "keycloak";
cert = {
inherit copyFromVhost;
};
};
local.enable = true;
locations."/".proxyPass = mkDefault nginx.virtualHosts.keycloak.locations."/".proxyPass;
proxy = {
inherit copyFromVhost;
};
};
};
};

View file

@ -40,14 +40,13 @@ in {
};
};
name.shortServer = mkDefault "kitchen";
kTLS = mkDefault true;
in {
kitchencam = {
inherit name locations listen' kTLS;
inherit name locations listen';
vouch.enable = true;
};
kitchencam'local = {
inherit name listen' kTLS;
inherit name listen';
ssl.cert.copyFromVhost = "kitchencam";
local.enable = true;
locations = mapAttrs (name: location: location // {

View file

@ -12,8 +12,7 @@ let
inherit (config.services) nginx;
portPlaintext = 389;
portSsl = 636;
system = access.systemForService "ldap";
inherit (system.exports.services) ldap;
upstreamName = "ldap'access";
in {
options.services.nginx.access.ldap = with lib.types; {
domain = mkOption {
@ -36,19 +35,32 @@ in {
config = {
services.nginx = {
stream = {
upstreams = let
addr = mkAlmostOptionDefault (access.getAddressFor system.name "lan");
in {
ldap.servers.access = {
inherit addr;
port = mkOptionDefault ldap.ports.default.port;
upstreams = {
${upstreamName}.servers = {
ldaps = {
accessService = {
inherit (nginx.stream.upstreams.ldaps.servers.access.accessService) system name id port;
};
};
ldap = { upstream, ... }: {
enable = mkIf upstream.servers.ldaps.enable false;
accessService = {
inherit (nginx.stream.upstreams.ldap.servers.access.accessService) system name id port;
};
};
};
ldaps = {
enable = mkAlmostOptionDefault ldap.ports.ssl.enable;
ssl.enable = mkAlmostOptionDefault true;
ldap.servers.access = {
accessService = {
name = "ldap";
};
};
ldaps = { config, ... }: {
enable = mkAlmostOptionDefault config.servers.access.enable;
servers.access = {
inherit addr;
port = mkOptionDefault ldap.ports.ssl.port;
accessService = {
name = "ldap";
port = "ssl";
};
};
};
};
@ -60,9 +72,7 @@ in {
ssl = true;
};
};
proxy.upstream = mkAlmostOptionDefault (
if nginx.stream.upstreams.ldaps.enable then "ldaps" else "ldap"
);
proxy.upstream = mkAlmostOptionDefault upstreamName;
};
};
};

View file

@ -7,41 +7,63 @@
inherit (lib.modules) mkIf mkDefault;
inherit (config.services) nginx;
cfg = config.services.plex;
upstreamName = "plex'access";
in {
config.services.nginx = {
upstreams'.${upstreamName}.servers = {
local = {
enable = mkDefault cfg.enable;
addr = mkDefault "localhost";
port = mkDefault cfg.port;
};
access = { upstream, ... }: {
enable = mkDefault (!upstream.servers.local.enable);
accessService.name = "plex";
};
};
virtualHosts = let
extraConfig = ''
# Some players don't reopen a socket and playback stops totally instead of resuming after an extended pause
send_timeout 100m;
# Plex headers
proxy_set_header X-Plex-Client-Identifier $http_x_plex_client_identifier;
proxy_set_header X-Plex-Device $http_x_plex_device;
proxy_set_header X-Plex-Device-Name $http_x_plex_device_name;
proxy_set_header X-Plex-Platform $http_x_plex_platform;
proxy_set_header X-Plex-Platform-Version $http_x_plex_platform_version;
proxy_set_header X-Plex-Product $http_x_plex_product;
proxy_set_header X-Plex-Token $http_x_plex_token;
proxy_set_header X-Plex-Version $http_x_plex_version;
proxy_set_header X-Plex-Nocache $http_x_plex_nocache;
proxy_set_header X-Plex-Provides $http_x_plex_provides;
proxy_set_header X-Plex-Device-Vendor $http_x_plex_device_vendor;
proxy_set_header X-Plex-Model $http_x_plex_model;
# Buffering off send to the client as soon as the data is received from Plex.
proxy_redirect off;
proxy_buffering off;
'';
locations."/" = {
proxy.websocket.enable = mkDefault true;
proxyPass = mkDefault (if cfg.enable
then "http://localhost:${toString cfg.port}"
else access.proxyUrlFor { serviceName = "plex"; }
);
headers.set = {
X-Plex-Client-Identifier = "$http_x_plex_client_identifier";
X-Plex-Device = "$http_x_plex_device";
X-Plex-Device-Name = "$http_x_plex_device_name";
X-Plex-Platform = "$http_x_plex_platform";
X-Plex-Platform-Version = "$http_x_plex_platform_version";
X-Plex-Product = "$http_x_plex_product";
X-Plex-Token = "$http_x_plex_token";
X-Plex-Version = "$http_x_plex_version";
X-Plex-Nocache = "$http_x_plex_nocache";
X-Plex-Provides = "$http_x_plex_provides";
X-Plex-Device-Vendor = "$http_x_plex_device_vendor";
X-Plex-Model = "$http_x_plex_model";
};
locations = {
"/" = {
proxy = {
enable = true;
inherit headers;
};
};
"/websockets/" = {
proxy = {
enable = true;
websocket.enable = true;
inherit headers;
};
};
};
name.shortServer = mkDefault "plex";
kTLS = mkDefault true;
copyFromVhost = mkDefault "plex";
in {
plex = {
inherit name locations extraConfig kTLS;
inherit name locations extraConfig;
proxy.upstream = mkDefault upstreamName;
listen' = {
http = { };
https.ssl = true;
@ -53,8 +75,13 @@ in {
};
};
plex'local = {
inherit name locations extraConfig kTLS;
ssl.cert.copyFromVhost = "plex";
inherit name locations extraConfig;
ssl.cert = {
inherit copyFromVhost;
};
proxy = {
inherit copyFromVhost;
};
local.enable = true;
};
};

View file

@ -1,14 +1,29 @@
{
config,
lib,
access,
...
}: let
inherit (lib.modules) mkDefault;
inherit (config.services) nginx;
cfg = config.services.unifi;
upstreamName = "unifi'access";
in {
config.services.nginx = {
vouch.enable = true;
upstreams'.${upstreamName}.servers = {
local = {
enable = mkDefault cfg.enable;
addr = mkDefault "localhost";
port = mkDefault 8443;
ssl.enable = mkDefault true;
};
access = { upstream, ... }: {
enable = mkDefault (!upstream.servers.local.enable);
accessService = {
name = "unifi";
port = "management";
};
};
};
virtualHosts = let
extraConfig = ''
proxy_redirect off;
@ -26,22 +41,23 @@ in {
};
};
name.shortServer = mkDefault "unifi";
kTLS = mkDefault true;
copyFromVhost = mkDefault "unifi";
in {
unifi = {
inherit name extraConfig kTLS locations;
inherit name extraConfig locations;
vouch.enable = mkDefault true;
ssl.force = mkDefault true;
proxy.url = mkDefault (if cfg.enable
then "https://localhost:8443"
else access.proxyUrlFor { serviceName = "unifi"; portName = "management"; }
);
proxy.upstream = mkDefault upstreamName;
};
unifi'local = {
inherit name extraConfig kTLS locations;
ssl.cert.copyFromVhost = "unifi";
inherit name extraConfig locations;
ssl.cert = {
inherit copyFromVhost;
};
local.enable = true;
proxy.url = mkDefault nginx.virtualHosts.unifi.proxy.url;
proxy = {
inherit copyFromVhost;
};
};
};
};

View file

@ -1,15 +1,23 @@
{
config,
lib,
access,
...
}: let
inherit (lib.modules) mkIf mkMerge mkDefault;
inherit (config) networking;
inherit (lib.modules) mkIf mkDefault;
inherit (config.services) tailscale nginx;
cfg = config.services.vouch-proxy;
in {
config.services.nginx = {
upstreams'.vouch'access.servers.access = {
accessService = {
inherit (nginx.upstreams'.vouch'auth.servers.service.accessService) system name id port;
};
};
upstreams'.vouch'access'local.servers.access = {
accessService = {
inherit (nginx.upstreams'.vouch'auth'local.servers.service.accessService) system name id port;
};
};
virtualHosts = let
locations = {
"/" = {
@ -25,13 +33,6 @@ in {
local.denyGlobal = true;
};
};
localLocations = kanidmDomain: mkIf (nginx.vouch.localSso.enable && false) {
"/" = { xvars, ... }: {
extraConfig = ''
proxy_redirect https://sso.${networking.domain}/ ${xvars.get.scheme}://${kanidmDomain}/;
'';
};
};
name.shortServer = mkDefault "login";
in {
vouch = { xvars, ... }: {
@ -39,9 +40,7 @@ in {
serverAliases = [ nginx.vouch.doubleProxy.serverName ];
proxied.enable = true;
proxy = {
url = mkDefault (
access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login"; }
);
upstream = mkDefault "vouch'access";
host = mkDefault xvars.get.host;
};
local.denyGlobal = true;
@ -54,9 +53,7 @@ in {
serverAliases = mkIf cfg.enable [ nginx.vouch.doubleProxy.localServerName ];
proxied.enable = true;
proxy = {
url = mkDefault (
access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login.local"; }
);
upstream = mkDefault "vouch'access'local";
host = mkDefault xvars.get.host;
};
local.enable = true;
@ -64,10 +61,7 @@ in {
force = true;
cert.copyFromVhost = "vouch";
};
locations = mkMerge [
locations
(localLocations "sso.local.${networking.domain}")
];
inherit locations;
};
vouch'tail = { xvars, ... }: {
enable = mkDefault (tailscale.enable && !nginx.virtualHosts.vouch'local.name.includeTailscale);
@ -78,13 +72,10 @@ in {
};
local.enable = true;
proxy = {
url = mkDefault nginx.virtualHosts.vouch'local.locations."/".proxyPass;
upstream = mkDefault nginx.virtualHosts.vouch'local.proxy.upstream;
host = mkDefault xvars.get.host;
};
locations = mkMerge [
locations
(localLocations "sso.tail.${networking.domain}")
];
inherit locations;
};
};
};

View file

@ -1,34 +1,56 @@
{
config,
lib,
access,
...
}: let
inherit (lib.modules) mkDefault;
inherit (lib.modules) mkIf mkDefault;
inherit (config.services) nginx zigbee2mqtt;
name.shortServer = mkDefault "z2m";
upstreamName = "zigbee2mqtt'access";
in {
config.services.nginx = {
virtualHosts = {
zigbee2mqtt = {
locations."/" = {
proxy.websocket.enable = true;
proxyPass = mkDefault (
if zigbee2mqtt.enable then "http://localhost:${toString zigbee2mqtt.settings.frontend.port}"
else access.proxyUrlFor { serviceName = "zigbee2mqtt"; }
);
vouch.enable = mkIf nginx.virtualHosts.zigbee2mqtt.enable true;
upstreams'.${upstreamName}.servers = {
local = {
enable = mkDefault zigbee2mqtt.enable;
addr = mkDefault "localhost";
port = mkIf zigbee2mqtt.enable (mkDefault zigbee2mqtt.settings.frontend.port);
};
service = { upstream, ... }: {
enable = mkIf upstream.servers.local.enable (mkDefault false);
accessService = {
name = "zigbee2mqtt";
};
inherit name;
};
};
virtualHosts = let
locations = {
"/" = {
proxy.enable = true;
};
"/api" = {
proxy = {
enable = true;
websocket.enable = true;
};
};
};
name.shortServer = mkDefault "z2m";
copyFromVhost = mkDefault "zigbee2mqtt";
in {
zigbee2mqtt = {
proxy = {
upstream = mkDefault upstreamName;
};
inherit name locations;
vouch.enable = true;
};
zigbee2mqtt'local = {
inherit name;
ssl.cert.copyFromVhost = "zigbee2mqtt";
locations."/" = {
proxy.websocket.enable = true;
proxyPass = mkDefault (
nginx.virtualHosts.zigbee2mqtt.locations."/".proxyPass
);
inherit name locations;
ssl.cert = {
inherit copyFromVhost;
};
proxy = {
inherit copyFromVhost;
};
local.enable = true;
};