mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 04:19:19 -08:00
refactor(nginx): ssl module
This commit is contained in:
parent
69c014b24e
commit
a7e35fbc88
28 changed files with 794 additions and 546 deletions
71
modules/nixos/nginx/listen.nix
Normal file
71
modules/nixos/nginx/listen.nix
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault mkForce mkOverride;
|
||||
inherit (lib.attrsets) mapAttrsToList filterAttrs removeAttrs;
|
||||
inherit (lib.lists) concatMap;
|
||||
mkAlmostOptionDefault = mkOverride 1250;
|
||||
inherit (config.services) nginx;
|
||||
extraListenAttrs = [ "enable" ];
|
||||
listenModule = { config, virtualHost, ... }: {
|
||||
options = with lib.types; {
|
||||
enable = mkEnableOption "this port" // {
|
||||
default = true;
|
||||
};
|
||||
ssl = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
port = mkOption {
|
||||
type = nullOr port;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
enable = mkIf (config.ssl && !virtualHost.ssl.enable) (mkForce false);
|
||||
_module.freeformType = with lib.types; attrsOf (oneOf [
|
||||
str (listOf str) (nullOr port) bool
|
||||
]);
|
||||
port = mkOptionDefault (
|
||||
if config.ssl then nginx.defaultSSLListenPort else nginx.defaultHTTPListenPort
|
||||
);
|
||||
};
|
||||
};
|
||||
hostModule = { config, ... }: let
|
||||
cfg = config.listenPorts;
|
||||
enabledPorts = filterAttrs (_: port: port.enable) cfg;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
listenPorts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ listenModule ];
|
||||
specialArgs = {
|
||||
virtualHost = config;
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
listen = let
|
||||
addresses = if config.listenAddresses != [ ] then config.listenAddresses else nginx.defaultListenAddresses;
|
||||
in mkIf (cfg != { }) (mkAlmostOptionDefault (
|
||||
concatMap (addr: mapAttrsToList (_: listen: {
|
||||
addr = mkDefault addr;
|
||||
} // removeAttrs listen extraListenAttrs) enabledPorts) addresses
|
||||
));
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
enable = mkOptionDefault virtualHost.local.enable;
|
||||
denyGlobal = mkOptionDefault virtualHost.local.denyGlobal;
|
||||
trusted = mkOptionDefault virtualHost.local.trusted;
|
||||
emitDenyGlobal = virtualHost.local.emitDenyGlobal;
|
||||
emitDenyGlobal = config.local.denyGlobal && !virtualHost.local.emitDenyGlobal;
|
||||
};
|
||||
};
|
||||
hostModule = {config, ...}: {
|
||||
|
|
|
|||
69
modules/nixos/nginx/name.nix
Normal file
69
modules/nixos/nginx/name.nix
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
inherit (lib.strings) optionalString;
|
||||
inherit (config.services) tailscale;
|
||||
inherit (config) networking;
|
||||
hostModule = {config, ...}: let
|
||||
cfg = config.name;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
name = {
|
||||
shortServer = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
qualifier = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
includeLocal = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
includeTailscale = mkOption {
|
||||
type = bool;
|
||||
};
|
||||
};
|
||||
allServerNames = mkOption {
|
||||
type = listOf str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
name = {
|
||||
qualifier = mkOptionDefault (
|
||||
if config.local.enable then "local"
|
||||
else null
|
||||
);
|
||||
includeTailscale = mkOptionDefault (
|
||||
config.local.enable && tailscale.enable && cfg.qualifier != "tail"
|
||||
);
|
||||
};
|
||||
serverName = mkIf (cfg.shortServer != null) (mkDefault (
|
||||
cfg.shortServer
|
||||
+ optionalString (cfg.qualifier != null) ".${cfg.qualifier}"
|
||||
+ ".${networking.domain}"
|
||||
));
|
||||
serverAliases = mkIf (cfg.shortServer != null) (mkDefault [
|
||||
(mkIf cfg.includeLocal "${cfg.shortServer}.local.${networking.domain}")
|
||||
(mkIf cfg.includeTailscale "${cfg.shortServer}.tail.${networking.domain}")
|
||||
]);
|
||||
allServerNames = mkOptionDefault (
|
||||
[ config.serverName ] ++ config.serverAliases
|
||||
);
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [hostModule];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
204
modules/nixos/nginx/proxied.nix
Normal file
204
modules/nixos/nginx/proxied.nix
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkAfter mkOrder mkDefault mkOptionDefault mkOverride;
|
||||
inherit (lib.strings) optionalString splitString match;
|
||||
inherit (lib.attrsets) attrValues;
|
||||
inherit (lib.lists) length head /*optional*/ any;
|
||||
inherit (lib.trivial) mapNullable;
|
||||
#inherit (config) networking;
|
||||
inherit (config.services) nginx;
|
||||
mkAlmostAfter = mkOrder 1250;
|
||||
mkAlmostOptionDefault = mkOverride 1250;
|
||||
schemeForUrl = url: let
|
||||
parts = splitString ":" url;
|
||||
in if length parts == 1 then null else head parts;
|
||||
pathForUrl = url: let
|
||||
parts = match ''[^:]+://[^/]+(.*)'' url;
|
||||
in if parts == null then null else head parts;
|
||||
hostForUrl = url: let
|
||||
parts = match ''[^:]+://([^/]+).*'' url;
|
||||
in if parts == null then null else head parts;
|
||||
xHeadersDefaults = ''
|
||||
set $x_scheme $scheme;
|
||||
set $x_forwarded_for $remote_addr;
|
||||
set $x_remote_addr $remote_addr;
|
||||
set $x_forwarded_host $host;
|
||||
set $x_forwarded_server $host;
|
||||
set $x_host $host;
|
||||
set $x_referer $http_referer;
|
||||
set $x_proxy_host $x_host;
|
||||
'';
|
||||
xHeadersProxied = ''
|
||||
set $x_forwarded_for $proxy_add_x_forwarded_for;
|
||||
if ($http_x_forwarded_proto) {
|
||||
set $x_scheme $http_x_forwarded_proto;
|
||||
}
|
||||
if ($http_x_real_ip) {
|
||||
set $x_remote_addr $http_x_real_ip;
|
||||
}
|
||||
if ($http_x_forwarded_host) {
|
||||
set $x_forwarded_host $http_x_forwarded_host;
|
||||
}
|
||||
if ($http_x_forwarded_server) {
|
||||
set $x_forwarded_server $http_x_forwarded_server;
|
||||
}
|
||||
if ($x_referer ~ "^https?://([^/]*)/(.*)$") {
|
||||
set $x_referer_host $1;
|
||||
set $x_referer_path $2;
|
||||
}
|
||||
'';
|
||||
locationModule = { config, virtualHost, ... }: let
|
||||
cfg = config.proxied;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
proxied = {
|
||||
enable = mkOption {
|
||||
type = enum [ false true "cloudflared" ];
|
||||
default = false;
|
||||
};
|
||||
enabled = mkOption {
|
||||
type = bool;
|
||||
readOnly = true;
|
||||
};
|
||||
xvars.enable = mkEnableOption "$x_variables";
|
||||
redirectScheme = mkEnableOption "redirect to X-Forwarded-Proto" // {
|
||||
default = cfg.enabled;
|
||||
};
|
||||
rewriteReferer = mkEnableOption "rewrite Referer header" // {
|
||||
default = cfg.enabled;
|
||||
};
|
||||
};
|
||||
proxy = {
|
||||
enabled = mkOption {
|
||||
type = bool;
|
||||
readOnly = true;
|
||||
};
|
||||
scheme = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
path = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
host = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
headers.enableRecommended = mkOption {
|
||||
type = enum [ true false "nixpkgs" ];
|
||||
};
|
||||
};
|
||||
force = mkEnableOption "redirect to SSL";
|
||||
};
|
||||
config = let
|
||||
emitVars = cfg.enabled && !virtualHost.proxied.enabled;
|
||||
emitRedirectScheme = config.proxy.enabled && cfg.redirectScheme;
|
||||
emitRefererRewrite = config.proxy.enabled && cfg.rewriteReferer;
|
||||
emitHeaders = config.proxy.enabled && config.proxy.headers.enableRecommended == true;
|
||||
in {
|
||||
proxied = {
|
||||
enabled = mkOptionDefault (virtualHost.proxied.enabled || cfg.enable != false);
|
||||
xvars.enable = mkIf (cfg.enabled || emitRedirectScheme || emitHeaders) true;
|
||||
};
|
||||
proxy = {
|
||||
enabled = mkOptionDefault (config.proxyPass != null);
|
||||
headers.enableRecommended = mkOptionDefault (
|
||||
if !virtualHost.recommendedProxySettings then false
|
||||
else if cfg.enabled then true
|
||||
else "nixpkgs"
|
||||
);
|
||||
scheme = mkOptionDefault (
|
||||
mapNullable schemeForUrl config.proxyPass
|
||||
);
|
||||
path = mkOptionDefault (
|
||||
mapNullable pathForUrl config.proxyPass
|
||||
);
|
||||
host = mkOptionDefault (
|
||||
mapNullable hostForUrl config.proxyPass
|
||||
);
|
||||
};
|
||||
recommendedProxySettings = mkMerge [
|
||||
(mkAlmostOptionDefault (config.proxy.headers.enableRecommended == "nixpkgs"))
|
||||
];
|
||||
extraConfig = mkMerge [
|
||||
(mkIf emitVars (
|
||||
mkBefore xHeadersProxied
|
||||
))
|
||||
(mkIf emitRedirectScheme ''
|
||||
proxy_redirect ${config.proxy.scheme}://$host/ $x_scheme://$host/;
|
||||
'')
|
||||
(mkIf emitRefererRewrite ''
|
||||
if ($x_referer_host = $host) {
|
||||
set $x_referer "${config.proxy.scheme}://${config.proxy.host}/$x_referer_path";
|
||||
}
|
||||
'')
|
||||
(mkIf emitHeaders (mkAlmostAfter ''
|
||||
if ($x_proxy_host = "") {
|
||||
set $x_proxy_host $proxy_host;
|
||||
}
|
||||
if ($x_proxy_host = "") {
|
||||
set $x_proxy_host ${config.proxy.host};
|
||||
}
|
||||
proxy_set_header Host $x_proxy_host;
|
||||
proxy_set_header Referer $x_referer;
|
||||
proxy_set_header X-Real-IP $x_remote_addr;
|
||||
proxy_set_header X-Forwarded-For $x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $x_scheme;
|
||||
proxy_set_header X-Forwarded-Host $x_forwarded_host;
|
||||
proxy_set_header X-Forwarded-Server $x_forwarded_server;
|
||||
''))
|
||||
];
|
||||
};
|
||||
};
|
||||
hostModule = { config, ... }: let
|
||||
cfg = config.proxied;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
proxied = {
|
||||
enable = mkOption {
|
||||
type = enum [ false true "cloudflared" ];
|
||||
default = false;
|
||||
};
|
||||
enabled = mkOption {
|
||||
type = bool;
|
||||
default = cfg.enable != false;
|
||||
};
|
||||
xvars.enable = mkEnableOption "$x_variables" // {
|
||||
default = cfg.enabled;
|
||||
};
|
||||
};
|
||||
recommendedProxySettings = mkOption {
|
||||
type = bool;
|
||||
default = nginx.recommendedProxySettings;
|
||||
};
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ locationModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
proxied = {
|
||||
xvars.enable = mkIf (any (loc: loc.proxied.xvars.enable) (attrValues config.locations)) true;
|
||||
};
|
||||
local.denyGlobal = mkIf (cfg.enable == "cloudflared") (mkDefault true);
|
||||
extraConfig = mkIf cfg.xvars.enable (mkBefore ''
|
||||
${xHeadersDefaults}
|
||||
${optionalString cfg.enabled xHeadersProxied}
|
||||
'');
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
92
modules/nixos/nginx/ssl.nix
Normal file
92
modules/nixos/nginx/ssl.nix
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault mkOverride;
|
||||
mkAlmostOptionDefault = mkOverride 1250;
|
||||
forceRedirectConfig = virtualHost: ''
|
||||
if ($x_scheme = http) {
|
||||
return ${toString virtualHost.redirectCode} https://$host$request_uri;
|
||||
}
|
||||
'';
|
||||
locationModule = { config, virtualHost, ... }: let
|
||||
cfg = config.ssl;
|
||||
emitForce = cfg.force && !virtualHost.ssl.forced;
|
||||
in {
|
||||
options.ssl = {
|
||||
force = mkEnableOption "redirect to SSL";
|
||||
};
|
||||
config = {
|
||||
proxied.xvars.enable = mkIf emitForce true;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig virtualHost);
|
||||
};
|
||||
};
|
||||
hostModule = { config, name, ... }: let
|
||||
cfg = config.ssl;
|
||||
emitForce = cfg.forced && config.proxied.enabled;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
ssl = {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
};
|
||||
force = mkOption {
|
||||
# TODO: "force-nonlocal"? exceptions for tailscale?
|
||||
type = enum [ false true "only" "reject" ];
|
||||
default = false;
|
||||
};
|
||||
forced = mkOption {
|
||||
type = bool;
|
||||
readOnly = true;
|
||||
};
|
||||
cert = {
|
||||
name = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
keyPath = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
};
|
||||
path = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ locationModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
config = {
|
||||
ssl = {
|
||||
enable = mkOptionDefault (cfg.cert.name != null || cfg.cert.keyPath != null);
|
||||
forced = mkOptionDefault (cfg.force != false && cfg.force != "reject");
|
||||
};
|
||||
addSSL = mkIf (cfg.enable && (cfg.force == false || emitForce)) (mkDefault true);
|
||||
forceSSL = mkIf (cfg.enable && cfg.force == true && !emitForce) (mkDefault true);
|
||||
onlySSL = mkIf (cfg.enable && cfg.force == "only" && !emitForce) (mkDefault true);
|
||||
rejectSSL = mkIf (cfg.force == "reject") (mkDefault true);
|
||||
useACMEHost = mkAlmostOptionDefault cfg.cert.name;
|
||||
sslCertificate = mkIf (cfg.cert.path != null) (mkAlmostOptionDefault cfg.cert.path);
|
||||
sslCertificateKey = mkIf (cfg.cert.keyPath != null) (mkAlmostOptionDefault cfg.cert.keyPath);
|
||||
|
||||
proxied.xvars.enable = mkIf emitForce true;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig config);
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -6,11 +6,123 @@
|
|||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
|
||||
inherit (config) networking;
|
||||
inherit (config.services) vouch-proxy tailscale;
|
||||
vouchModule = {config, ...}: {
|
||||
inherit (config.services) vouch-proxy nginx tailscale;
|
||||
inherit (nginx) vouch;
|
||||
locationModule = {config, virtualHost, ...}: {
|
||||
options.vouch = with lib.types; {
|
||||
requireAuth = mkEnableOption "require auth to access this location";
|
||||
};
|
||||
config = mkIf config.vouch.requireAuth {
|
||||
proxied.xvars.enable = true;
|
||||
extraConfig = assert virtualHost.vouch.enable; mkMerge [
|
||||
''
|
||||
add_header Access-Control-Allow-Origin ${vouch.url};
|
||||
add_header Access-Control-Allow-Origin ${vouch.authUrl};
|
||||
''
|
||||
(mkIf (vouch.localSso.enable && config.local.enable) ''
|
||||
add_header Access-Control-Allow-Origin ${vouch.localUrl};
|
||||
'')
|
||||
(mkIf (vouch.localSso.enable && config.local.enable && tailscale.enable) ''
|
||||
add_header Access-Control-Allow-Origin $x_scheme://${vouch.tailDomain};
|
||||
'')
|
||||
''
|
||||
proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
|
||||
''
|
||||
];
|
||||
};
|
||||
};
|
||||
hostModule = {config, ...}: let
|
||||
cfg = config.vouch;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
locations = mkOption {
|
||||
type = attrsOf (submodule locationModule);
|
||||
};
|
||||
vouch = {
|
||||
enable = mkEnableOption "vouch auth proxy";
|
||||
requireAuth = mkEnableOption "require auth to access this host" // {
|
||||
default = true;
|
||||
};
|
||||
errorLocation = mkOption {
|
||||
type = str;
|
||||
default = "@error401";
|
||||
};
|
||||
authRequestLocation = mkOption {
|
||||
type = str;
|
||||
default = "/validate";
|
||||
};
|
||||
authRequestDirective = mkOption {
|
||||
type = lines;
|
||||
default = ''
|
||||
auth_request ${cfg.authRequestLocation};
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
extraConfig = mkIf (cfg.enable && cfg.requireAuth) ''
|
||||
${cfg.authRequestDirective}
|
||||
error_page 401 = ${cfg.errorLocation};
|
||||
'';
|
||||
locations = mkIf cfg.enable {
|
||||
"/" = mkIf cfg.requireAuth {
|
||||
vouch.requireAuth = true;
|
||||
};
|
||||
${cfg.errorLocation} = {
|
||||
proxied.xvars.enable = true;
|
||||
extraConfig = let
|
||||
localVouchUrl = ''
|
||||
if ($x_forwarded_host ~ "\.local\.${networking.domain}$") {
|
||||
set $vouch_url ${vouch.localUrl};
|
||||
}
|
||||
'';
|
||||
tailVouchUrl = ''
|
||||
if ($x_forwarded_host ~ "\.tail\.${networking.domain}$") {
|
||||
set $vouch_url $x_scheme://${vouch.tailDomain};
|
||||
}
|
||||
'';
|
||||
in
|
||||
mkMerge [
|
||||
(mkBefore ''
|
||||
set $vouch_url ${vouch.url};
|
||||
'')
|
||||
(mkIf (vouch.localSso.enable && config.local.enable or false) localVouchUrl)
|
||||
(mkIf (vouch.localSso.enable && config.local.enable or false && tailscale.enable) tailVouchUrl)
|
||||
''
|
||||
return 302 $vouch_url/login?url=$x_scheme://$x_forwarded_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
|
||||
''
|
||||
];
|
||||
};
|
||||
${cfg.authRequestLocation} = {
|
||||
proxyPass = "${vouch.proxyOrigin}/validate";
|
||||
proxy.headers.enableRecommended = true;
|
||||
extraConfig = let
|
||||
# nginx-proxied vouch must use X-Forwarded-Host, but vanilla vouch requires Host
|
||||
vouchProxyHost = if vouch.doubleProxy
|
||||
then "''"
|
||||
else "$x_forwarded_host";
|
||||
in ''
|
||||
set $x_proxy_host ${vouchProxyHost};
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
|
||||
auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
|
||||
auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
|
||||
auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx = {
|
||||
vouch = {
|
||||
enable = mkEnableOption "vouch auth proxy";
|
||||
localSso = {
|
||||
# NOTE: this won't work without multiple vouch-proxy instances with different auth urls...
|
||||
enable = mkEnableOption "lan-local auth";
|
||||
};
|
||||
proxyOrigin = mkOption {
|
||||
type = str;
|
||||
default = "https://login.local.${networking.domain}";
|
||||
|
|
@ -35,117 +147,32 @@
|
|||
type = str;
|
||||
default = "login.tail.${networking.domain}";
|
||||
};
|
||||
authRequestDirective = mkOption {
|
||||
type = lines;
|
||||
default = ''
|
||||
auth_request /validate;
|
||||
'';
|
||||
};
|
||||
};
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule hostModule);
|
||||
};
|
||||
};
|
||||
config = mkMerge [
|
||||
};
|
||||
config.services.nginx = {
|
||||
vouch = mkMerge [
|
||||
{
|
||||
vouch = mkIf vouch-proxy.enable {
|
||||
proxyOrigin = let
|
||||
inherit (vouch-proxy.settings.vouch) listen port;
|
||||
host =
|
||||
if listen == "0.0.0.0" || listen == "[::]"
|
||||
then "localhost"
|
||||
else listen;
|
||||
in
|
||||
mkDefault "http://${host}:${toString port}";
|
||||
authUrl = mkDefault vouch-proxy.authUrl;
|
||||
url = mkDefault vouch-proxy.url;
|
||||
doubleProxy = mkDefault false;
|
||||
};
|
||||
}
|
||||
{
|
||||
vouch.proxyOrigin = mkIf (tailscale.enable && !vouch-proxy.enable) (
|
||||
mkDefault
|
||||
"http://login.tail.${networking.domain}"
|
||||
proxyOrigin = mkIf (tailscale.enable && !vouch-proxy.enable) (
|
||||
mkDefault "http://login.tail.${networking.domain}"
|
||||
);
|
||||
}
|
||||
(mkIf config.vouch.enable {
|
||||
extraConfig = ''
|
||||
${config.vouch.authRequestDirective}
|
||||
error_page 401 = @error401;
|
||||
'';
|
||||
locations = {
|
||||
"/" = {
|
||||
extraConfig = mkMerge [
|
||||
''
|
||||
add_header Access-Control-Allow-Origin ${config.vouch.url};
|
||||
add_header Access-Control-Allow-Origin ${config.vouch.authUrl};
|
||||
''
|
||||
(mkIf config.local.enable ''
|
||||
add_header Access-Control-Allow-Origin ${config.vouch.localUrl};
|
||||
'')
|
||||
(mkIf (config.local.enable && tailscale.enable) ''
|
||||
add_header Access-Control-Allow-Origin $scheme://${config.vouch.tailDomain};
|
||||
'')
|
||||
''
|
||||
proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
|
||||
''
|
||||
];
|
||||
};
|
||||
"@error401" = {
|
||||
extraConfig = let
|
||||
localVouchUrl = ''
|
||||
if ($http_host ~ "\.local\.${networking.domain}$") {
|
||||
set $vouch_url ${config.vouch.localUrl};
|
||||
}
|
||||
'';
|
||||
tailVouchUrl = ''
|
||||
if ($http_host ~ "\.tail\.${networking.domain}$") {
|
||||
set $vouch_url $vouch_scheme://${config.vouch.tailDomain};
|
||||
}
|
||||
'';
|
||||
in
|
||||
mkMerge [
|
||||
(mkBefore ''
|
||||
set $vouch_url ${config.vouch.url};
|
||||
set $vouch_scheme $scheme;
|
||||
'')
|
||||
(mkIf config.local.trusted (mkBefore ''
|
||||
if ($http_x_forwarded_proto) {
|
||||
set $vouch_scheme $http_x_forwarded_proto;
|
||||
}
|
||||
''))
|
||||
(mkIf (config.local.enable or false) localVouchUrl)
|
||||
(mkIf (config.local.enable or false && tailscale.enable) tailVouchUrl)
|
||||
''
|
||||
return 302 $vouch_url/login?url=$vouch_scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
|
||||
''
|
||||
];
|
||||
};
|
||||
"/validate" = {
|
||||
recommendedProxySettings = false;
|
||||
proxyPass = "${config.vouch.proxyOrigin}/validate";
|
||||
extraConfig = mkMerge [
|
||||
(mkIf (!config.vouch.doubleProxy) ''
|
||||
proxy_set_header Host $host;
|
||||
'')
|
||||
(mkIf config.vouch.doubleProxy ''
|
||||
proxy_set_header X-Host $host;
|
||||
'')
|
||||
''
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
|
||||
auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
|
||||
auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
|
||||
auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
|
||||
''
|
||||
];
|
||||
};
|
||||
};
|
||||
(mkIf vouch-proxy.enable {
|
||||
proxyOrigin = let
|
||||
inherit (vouch-proxy.settings.vouch) listen port;
|
||||
host =
|
||||
if listen == "0.0.0.0" || listen == "[::]"
|
||||
then "localhost"
|
||||
else listen;
|
||||
in
|
||||
mkDefault "http://${host}:${toString port}";
|
||||
authUrl = mkDefault vouch-proxy.authUrl;
|
||||
url = mkDefault vouch-proxy.url;
|
||||
doubleProxy = mkDefault false;
|
||||
})
|
||||
];
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submodule vouchModule);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
};
|
||||
config = mkIf config.proxy.websocket.enable {
|
||||
extraConfig = ''
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
'';
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
}: let
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
cfg = config.services.bazarr;
|
||||
access = config.services.nginx.access.bazarr;
|
||||
proxyPass = mkDefault "https://${access.host}:${toString access.port}";
|
||||
locations = {
|
||||
"/" = {
|
||||
inherit proxyPass;
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.nginx.access.bazarr = with lib.types; {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "bazarr.${config.networking.domain}";
|
||||
};
|
||||
port = mkOption {
|
||||
type = port;
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.bazarr = mkIf cfg.enable {
|
||||
host = mkOptionDefault "localhost";
|
||||
port = mkOptionDefault cfg.listenPort;
|
||||
};
|
||||
virtualHosts = {
|
||||
${access.domain} = {
|
||||
inherit locations;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -7,7 +7,8 @@
|
|||
}: let
|
||||
inherit (lib.modules) mkDefault;
|
||||
in {
|
||||
services.nginx.virtualHosts.${config.networking.domain} = {
|
||||
services.nginx.virtualHosts.gensokyoZone = {
|
||||
serverName = config.networking.domain;
|
||||
locations = {
|
||||
"/" = {
|
||||
root = inputs.website.packages.${pkgs.system}.gensokyoZone;
|
||||
|
|
|
|||
|
|
@ -3,20 +3,29 @@
|
|||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.modules) mkIf mkDefault;
|
||||
inherit (config.services) home-assistant tailscale;
|
||||
proxyPass = "http://localhost:${toString home-assistant.config.http.server_port}/";
|
||||
inherit (lib.modules) mkIf mkMerge mkDefault;
|
||||
inherit (config.services) home-assistant nginx;
|
||||
name.shortServer = mkDefault "home";
|
||||
listenPorts = {
|
||||
http = { };
|
||||
https.ssl = true;
|
||||
hass = mkIf (!home-assistant.enable) { port = mkDefault home-assistant.config.http.server_port; };
|
||||
};
|
||||
in {
|
||||
services.nginx.virtualHosts."home.local.${config.networking.domain}" = mkIf home-assistant.enable {
|
||||
local.enable = mkDefault true;
|
||||
locations."/" = {
|
||||
inherit proxyPass;
|
||||
};
|
||||
};
|
||||
services.nginx.virtualHosts."home.tail.${config.networking.domain}" = mkIf (home-assistant.enable && tailscale.enable) {
|
||||
local.enable = mkDefault true;
|
||||
locations."/" = {
|
||||
inherit proxyPass;
|
||||
config.services.nginx.virtualHosts = {
|
||||
home-assistant = {
|
||||
inherit name listenPorts;
|
||||
locations."/".proxyPass = mkIf home-assistant.enable (mkDefault
|
||||
"http://localhost:${toString home-assistant.config.http.server_port}"
|
||||
);
|
||||
};
|
||||
home-assistant'local = {
|
||||
inherit name listenPorts;
|
||||
local.enable = mkDefault true;
|
||||
locations."/".proxyPass = mkIf home-assistant.enable (mkDefault
|
||||
nginx.virtualHosts.home-assistant.locations."/".proxyPass
|
||||
);
|
||||
};
|
||||
};
|
||||
config.networking.firewall.allowedTCPPorts = [ home-assistant.config.http.server_port ];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
}: let
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
cfg = config.services.jackett;
|
||||
access = config.services.nginx.access.jackett;
|
||||
proxyPass = mkDefault "https://${access.host}:${toString access.port}";
|
||||
locations = {
|
||||
"/" = {
|
||||
inherit proxyPass;
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.nginx.access.jackett = with lib.types; {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "jackett.${config.networking.domain}";
|
||||
};
|
||||
port = mkOption {
|
||||
type = port;
|
||||
default = cfg.port;
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.jackett = mkIf cfg.enable {
|
||||
host = mkOptionDefault "localhost";
|
||||
};
|
||||
virtualHosts = {
|
||||
${access.domain} = {
|
||||
inherit locations;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
54
nixos/access/keycloak.nix
Normal file
54
nixos/access/keycloak.nix
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
inherit (lib.modules) mkIf mkDefault;
|
||||
cfg = config.services.keycloak;
|
||||
inherit (config) networking;
|
||||
inherit (config.services) nginx;
|
||||
access = nginx.access.keycloak;
|
||||
locations = {
|
||||
"/" = {
|
||||
proxyPass = mkDefault access.url;
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.nginx.access.keycloak = with lib.types; {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
default = "keycloak.local.${networking.domain}";
|
||||
};
|
||||
url = mkOption {
|
||||
type = str;
|
||||
default = "https://${access.host}";
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.keycloak = mkIf cfg.enable {
|
||||
host = mkDefault "localhost";
|
||||
url = mkDefault (if cfg.sslCertificate != null then "https://${access.host}" else "http://${access.host}");
|
||||
};
|
||||
virtualHosts = {
|
||||
keycloak = {
|
||||
name.shortServer = mkDefault "sso";
|
||||
ssl.force = mkDefault true;
|
||||
inherit locations;
|
||||
};
|
||||
keycloak'local = {
|
||||
name.shortServer = mkDefault "sso";
|
||||
ssl.force = mkDefault true;
|
||||
local.enable = true;
|
||||
inherit locations;
|
||||
extraConfig = mkIf nginx.vouch.localSso.enable ''
|
||||
set $vouch_local_url ${nginx.vouch.localUrl};
|
||||
if ($x_forwarded_host ~ "\.tail\.${networking.domain}$") {
|
||||
set $vouch_local_url $x_scheme://${nginx.vouch.tailDomain};
|
||||
}
|
||||
proxy_redirect ${nginx.vouch.url}/ $vouch_local_url/;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -27,18 +27,6 @@ in {
|
|||
type = str;
|
||||
default = "http://${access.host}:${toString access.streamPort}";
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "kitchen.${config.networking.domain}";
|
||||
};
|
||||
localDomain = mkOption {
|
||||
type = str;
|
||||
default = "kitchen.local.${config.networking.domain}";
|
||||
};
|
||||
tailDomain = mkOption {
|
||||
type = str;
|
||||
default = "kitchen.tail.${config.networking.domain}";
|
||||
};
|
||||
useACMEHost = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
|
|
@ -46,7 +34,6 @@ in {
|
|||
};
|
||||
config.services.nginx = {
|
||||
virtualHosts = let
|
||||
addSSL = access.useACMEHost != null || virtualHosts.${access.domain}.addSSL || virtualHosts.${access.domain}.forceSSL;
|
||||
extraConfig = ''
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
|
|
@ -64,47 +51,22 @@ in {
|
|||
inherit extraConfig;
|
||||
};
|
||||
};
|
||||
streamListen = {config, ...}: {
|
||||
listen =
|
||||
concatMap (addr: [
|
||||
(mkIf config.addSSL {
|
||||
inherit addr;
|
||||
port = nginx.defaultSSLListenPort;
|
||||
ssl = true;
|
||||
})
|
||||
{
|
||||
inherit addr;
|
||||
port = nginx.defaultHTTPListenPort;
|
||||
}
|
||||
{
|
||||
inherit addr;
|
||||
port = access.streamPort;
|
||||
}
|
||||
])
|
||||
nginx.defaultListenAddresses;
|
||||
listenPorts = {
|
||||
http = { };
|
||||
https.ssl = true;
|
||||
stream.port = mkDefault access.streamPort;
|
||||
};
|
||||
name.shortServer = mkDefault "kitchen";
|
||||
kTLS = mkDefault true;
|
||||
in {
|
||||
${access.domain} = mkMerge [
|
||||
{
|
||||
vouch.enable = true;
|
||||
kTLS = mkDefault true;
|
||||
inherit (access) useACMEHost;
|
||||
addSSL = mkDefault (access.useACMEHost != null);
|
||||
inherit locations;
|
||||
}
|
||||
streamListen
|
||||
];
|
||||
${access.localDomain} = mkMerge [
|
||||
{
|
||||
serverAliases = mkIf config.services.tailscale.enable [access.tailDomain];
|
||||
inherit (virtualHosts.${access.domain}) useACMEHost;
|
||||
addSSL = mkDefault addSSL;
|
||||
kTLS = mkDefault true;
|
||||
local.enable = true;
|
||||
inherit locations;
|
||||
}
|
||||
streamListen
|
||||
];
|
||||
kitchencam = {
|
||||
inherit name locations listenPorts kTLS;
|
||||
vouch.enable = true;
|
||||
};
|
||||
kitchencam'local = {
|
||||
inherit name locations listenPorts kTLS;
|
||||
local.enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
config.networking.firewall.allowedTCPPorts = [
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
meta,
|
||||
...
|
||||
}:
|
||||
with lib; {
|
||||
services.nginx.virtualHosts."cloud.${config.networking.domain}" = {
|
||||
locations = {
|
||||
"/".proxyPass = meta.tailnet.yukari.ppp 4 80 "nextcloud/";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
}: let
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
cfg = config.services.ombi;
|
||||
access = config.services.nginx.access.ombi;
|
||||
proxyPass = mkDefault "https://${access.host}:${toString access.port}";
|
||||
locations = {
|
||||
"/" = {
|
||||
inherit proxyPass;
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.nginx.access.ombi = with lib.types; {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "ombi.${config.networking.domain}";
|
||||
};
|
||||
port = mkOption {
|
||||
type = port;
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.ombi = mkIf cfg.enable {
|
||||
host = mkOptionDefault "localhost";
|
||||
port = mkOptionDefault cfg.port;
|
||||
};
|
||||
virtualHosts = {
|
||||
${access.domain} = {
|
||||
inherit locations;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -13,14 +13,6 @@ in {
|
|||
url = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "plex.${config.networking.domain}";
|
||||
};
|
||||
localDomain = mkOption {
|
||||
type = str;
|
||||
default = "plex.local.${config.networking.domain}";
|
||||
};
|
||||
externalPort = mkOption {
|
||||
type = nullOr port;
|
||||
default = null;
|
||||
|
|
@ -51,33 +43,25 @@ in {
|
|||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
'';
|
||||
location = {
|
||||
locations."/" = {
|
||||
proxy.websocket.enable = true;
|
||||
proxyPass = access.url;
|
||||
};
|
||||
name.shortServer = mkDefault "plex";
|
||||
kTLS = mkDefault true;
|
||||
in {
|
||||
${access.domain} = {
|
||||
locations."/" = location;
|
||||
kTLS = mkDefault true;
|
||||
inherit extraConfig;
|
||||
plex = {
|
||||
inherit name locations extraConfig kTLS;
|
||||
};
|
||||
${access.localDomain} = {
|
||||
plex'local = {
|
||||
inherit name locations extraConfig kTLS;
|
||||
local.enable = true;
|
||||
locations."/" = location;
|
||||
kTLS = mkDefault true;
|
||||
inherit extraConfig;
|
||||
};
|
||||
plex-external = mkIf (access.externalPort != null) {
|
||||
serverName = mkDefault access.domain;
|
||||
serverName = mkDefault "plex.${config.networking.domain}";
|
||||
default = mkDefault true;
|
||||
listen =
|
||||
map (addr: {
|
||||
inherit addr;
|
||||
port = access.externalPort;
|
||||
})
|
||||
nginx.defaultListenAddresses;
|
||||
locations."/" = location;
|
||||
inherit extraConfig;
|
||||
listenPorts.external.port = access.externalPort;
|
||||
inherit extraConfig locations;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
}: let
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
cfg = config.services.radarr;
|
||||
access = config.services.nginx.access.radarr;
|
||||
proxyPass = mkDefault "https://${access.host}:${toString access.port}";
|
||||
locations = {
|
||||
"/" = {
|
||||
inherit proxyPass;
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.nginx.access.radarr = with lib.types; {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "radarr.${config.networking.domain}";
|
||||
};
|
||||
port = mkOption {
|
||||
type = port;
|
||||
default = cfg.port;
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.radarr = mkIf cfg.enable {
|
||||
host = mkOptionDefault "localhost";
|
||||
};
|
||||
virtualHosts = {
|
||||
${access.domain} = {
|
||||
inherit locations;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
}: let
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
cfg = config.services.sonarr;
|
||||
access = config.services.nginx.access.sonarr;
|
||||
proxyPass = mkDefault "https://${access.host}:${toString access.port}";
|
||||
locations = {
|
||||
"/" = {
|
||||
inherit proxyPass;
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.nginx.access.sonarr = with lib.types; {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "sonarr.${config.networking.domain}";
|
||||
};
|
||||
port = mkOption {
|
||||
type = port;
|
||||
default = cfg.port;
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.sonarr = mkIf cfg.enable {
|
||||
host = mkOptionDefault "localhost";
|
||||
};
|
||||
virtualHosts = {
|
||||
${access.domain} = {
|
||||
inherit locations;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
}: let
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
cfg = config.services.tautulli;
|
||||
access = config.services.nginx.access.tautulli;
|
||||
proxyPass = mkDefault "https://${access.host}:${toString access.port}";
|
||||
locations = {
|
||||
"/" = {
|
||||
inherit proxyPass;
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.nginx.access.tautulli = with lib.types; {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "tautulli.${config.networking.domain}";
|
||||
};
|
||||
port = mkOption {
|
||||
type = port;
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.tautulli = mkIf cfg.enable {
|
||||
host = mkOptionDefault "localhost";
|
||||
port = mkOptionDefault cfg.port;
|
||||
};
|
||||
virtualHosts = {
|
||||
${access.domain} = {
|
||||
inherit locations;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -14,22 +14,6 @@ in {
|
|||
url = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "login.${networking.domain}";
|
||||
};
|
||||
localDomain = mkOption {
|
||||
type = str;
|
||||
default = "login.local.${networking.domain}";
|
||||
};
|
||||
tailDomain = mkOption {
|
||||
type = str;
|
||||
default = "login.tail.${networking.domain}";
|
||||
};
|
||||
useACMEHost = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.vouch = mkIf cfg.enable {
|
||||
|
|
@ -51,42 +35,52 @@ in {
|
|||
'';
|
||||
};
|
||||
"/validate" = {config, ...}: {
|
||||
proxied.enable = true;
|
||||
proxyPass = mkDefault (access.url + "/validate");
|
||||
recommendedProxySettings = mkDefault false;
|
||||
extraConfig =
|
||||
if config.local.trusted
|
||||
then ''
|
||||
if ($http_x_host = ''') {
|
||||
set $http_x_host $host;
|
||||
}
|
||||
proxy_set_header Host $http_x_host;
|
||||
''
|
||||
else ''
|
||||
proxy_set_header Host $host;
|
||||
'';
|
||||
proxy.headers.enableRecommended = true;
|
||||
local.denyGlobal = true;
|
||||
extraConfig = ''
|
||||
set $x_proxy_host $x_forwarded_host;
|
||||
'';
|
||||
};
|
||||
};
|
||||
localLocations = kanidmDomain: {
|
||||
"/".extraConfig = ''
|
||||
proxy_redirect $scheme://sso.${networking.domain}/ $scheme://${kanidmDomain}/;
|
||||
'';
|
||||
localLocations = kanidmDomain: mkIf nginx.vouch.localSso.enable {
|
||||
"/" = {
|
||||
proxied.xvars.enable = true;
|
||||
extraConfig = ''
|
||||
proxy_redirect https://sso.${networking.domain}/ $x_scheme://${kanidmDomain}/;
|
||||
'';
|
||||
};
|
||||
};
|
||||
name.shortServer = mkDefault "login";
|
||||
in {
|
||||
${access.localDomain} = mkIf (access.useACMEHost != null) {
|
||||
local.enable = true;
|
||||
locations = mkMerge [
|
||||
locations
|
||||
];
|
||||
useACMEHost = mkDefault access.useACMEHost;
|
||||
forceSSL = true;
|
||||
vouch = {
|
||||
inherit name locations;
|
||||
ssl.force = true;
|
||||
};
|
||||
${access.tailDomain} = mkIf tailscale.enable {
|
||||
vouch'local = {
|
||||
name = {
|
||||
inherit (name) shortServer;
|
||||
qualifier = mkDefault "local";
|
||||
includeTailscale = false;
|
||||
};
|
||||
local.enable = true;
|
||||
ssl.force = true;
|
||||
locations = mkMerge [
|
||||
locations
|
||||
(localLocations "sso.local.${networking.domain}")
|
||||
];
|
||||
};
|
||||
vouch'tail = mkIf tailscale.enable {
|
||||
name = {
|
||||
inherit (name) shortServer;
|
||||
qualifier = mkDefault "tail";
|
||||
};
|
||||
local.enable = true;
|
||||
locations = mkMerge [
|
||||
locations
|
||||
(localLocations "sso.tail.${networking.domain}")
|
||||
];
|
||||
useACMEHost = mkDefault access.useACMEHost;
|
||||
addSSL = mkIf (access.useACMEHost != null) (mkDefault true);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,47 +7,35 @@
|
|||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
cfg = config.services.zigbee2mqtt;
|
||||
access = config.services.nginx.access.zigbee2mqtt;
|
||||
location = {
|
||||
locations."/" = {
|
||||
proxy.websocket.enable = true;
|
||||
proxyPass = mkDefault "http://${access.host}:${toString access.port}";
|
||||
};
|
||||
name.shortServer = mkDefault "z2m";
|
||||
in {
|
||||
options.services.nginx.access.zigbee2mqtt = with lib.types; {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
};
|
||||
localDomain = mkOption {
|
||||
type = str;
|
||||
default = "z2m.local.${config.networking.domain}";
|
||||
};
|
||||
tailDomain = mkOption {
|
||||
type = str;
|
||||
default = "z2m.tail.${config.networking.domain}";
|
||||
};
|
||||
port = mkOption {
|
||||
type = port;
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
access.zigbee2mqtt = mkIf cfg.enable {
|
||||
domain = mkOptionDefault cfg.domain;
|
||||
host = mkOptionDefault "localhost";
|
||||
port = mkIf (cfg.settings ? frontend.port) (
|
||||
mkOptionDefault cfg.settings.frontend.port
|
||||
);
|
||||
};
|
||||
virtualHosts = {
|
||||
${access.domain} = {
|
||||
zigbee2mqtt = {
|
||||
inherit name locations;
|
||||
vouch.enable = true;
|
||||
locations."/" = location;
|
||||
};
|
||||
${access.localDomain} = {
|
||||
serverAliases = mkIf config.services.tailscale.enable [access.tailDomain];
|
||||
zigbee2mqtt'local = {
|
||||
inherit name locations;
|
||||
local.enable = true;
|
||||
locations."/" = location;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ in {
|
|||
settings = {
|
||||
hostname = mkDefault hostname;
|
||||
proxy = mkDefault (if cfg.sslCertificate != null then "reencrypt" else "edge");
|
||||
proxy-headers = mkDefault "xforwarded";
|
||||
};
|
||||
|
||||
sslCertificate = mkDefault "${cert}/fullchain.pem";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
vouch-client-secret: ENC[AES256_GCM,data:RWGjoC+L0FilUipBgvCy5t1bJEzDM8THc/m6RjwSPs9qPqfQCbSQWt/XXtQMR0VJ,iv:PJREZcXjLf3JVU4W5jD/6ruoaCIUV5TRocrmb1PjQeE=,tag:ZgKi+rI4ok7aIB3TOCXFKg==,type:str]
|
||||
vouch-client-secret: ENC[AES256_GCM,data:gmCOrC3FDSUw/V1FZywiq0MWgKTK7j2ojb/fZahFS4g=,iv:D6UfdfeRaqzEhK9yVsc0TfIfQ/EBzWdtzLt/vUKPR8I=,tag:EZ+XHvi0gnhvJ6s1d6KviA==,type:str]
|
||||
vouch-jwt: ENC[AES256_GCM,data:7G1/pzEmR7NM7eFb2wED4HR/A00TNdBjBs/OdziDgIuPttqp4AeLRnJ0UhRps5taEx2cTH0U5GyCR/A9ef9hfA==,iv:ugOuH35frzoT6lX9UTJjzoTm2OTCqS3sNJGq8TfViEY=,tag:jvv4DkLwMB9ytefpGpIqPQ==,type:str]
|
||||
sops:
|
||||
shamir_threshold: 1
|
||||
|
|
@ -70,8 +70,8 @@ sops:
|
|||
RkQvakRmdjB3ME1rbnNTWjVDQU5QSmcKi1KhB8zpSLlaCgSelaEYdtOGHFLlc+Z3
|
||||
hagYdJqojaOYbTGVBkWAYK0Zfh++1/QbDYJH6ySjDC8mFFCqEdSuYQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2024-01-16T19:11:11Z"
|
||||
mac: ENC[AES256_GCM,data:1J3dCx5ptr2ah2LbvoP/rcUzPlzm3wZvpWLffIvh7PriNJ6vx2xj5fFK9s2AhIunxAaef0KJLzwzcfNwxEkJO3M6QSf0UUw3wopah1W3ZKLE2H/Z8bNncaNzSuh6QODbYShSG2yK4HmQApd8R9NfKlAHsDno+aRhuh7OYM7CaLI=,iv:KzMfJDJOqYm2epLM6Epd44aRoU7uJcusCl6m6/+cDtQ=,tag:tQ8MQ1NWey4E1dFu2YnOQw==,type:str]
|
||||
lastmodified: "2024-03-20T00:39:56Z"
|
||||
mac: ENC[AES256_GCM,data:JY2ttbttavS4RqYEFf95BkiPrK1r4r6hXnoQMCqtoQmBhSbUF9X5gvxZuqBFF7as9KgwiWHXFJ6S0FccmDDcBA/QoGxI4IJoR4nEIp7Y/YHTY6Ni0vZfO27yAtGmnViXadOeVyFChVN6GjRnxLp/FaBdXxtjSH8x4sQqf/2VWCw=,iv:/pnWEOcclzw0xcpL6lwErJLOBE9tBk1pOZZe3ew20TM=,tag:WNWiSG7Buve8YxJb1XxFwg==,type:str]
|
||||
pgp:
|
||||
- created_at: "2024-03-19T02:39:12Z"
|
||||
enc: |-
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
tei = access.nixosFor "tei";
|
||||
inherit (mediabox.services) plex;
|
||||
inherit (keycloak.services) vouch-proxy;
|
||||
inherit (tei.services) home-assistant;
|
||||
inherit (config.services) nginx tailscale;
|
||||
in {
|
||||
imports = let
|
||||
|
|
@ -31,11 +32,13 @@ in {
|
|||
nixos.access.nginx
|
||||
nixos.access.global
|
||||
nixos.access.gensokyo
|
||||
nixos.access.keycloak
|
||||
nixos.access.vouch
|
||||
nixos.access.freeipa
|
||||
nixos.access.freepbx
|
||||
nixos.access.unifi
|
||||
nixos.access.kitchencam
|
||||
nixos.access.home-assistant
|
||||
nixos.access.proxmox
|
||||
nixos.access.plex
|
||||
nixos.access.invidious
|
||||
|
|
@ -61,14 +64,31 @@ in {
|
|||
};
|
||||
|
||||
security.acme.certs = let
|
||||
inherit (nginx) access;
|
||||
inherit (nginx) access virtualHosts;
|
||||
in {
|
||||
${access.vouch.localDomain} = {
|
||||
keycloak = {
|
||||
inherit (nginx) group;
|
||||
domain = virtualHosts.keycloak.serverName;
|
||||
extraDomainNames = mkMerge [
|
||||
(mkIf tailscale.enable [
|
||||
access.vouch.tailDomain
|
||||
])
|
||||
virtualHosts.keycloak.serverAliases
|
||||
virtualHosts.keycloak'local.allServerNames
|
||||
];
|
||||
};
|
||||
home-assistant = {
|
||||
inherit (nginx) group;
|
||||
domain = virtualHosts.home-assistant.serverName;
|
||||
extraDomainNames = mkMerge [
|
||||
virtualHosts.home-assistant.serverAliases
|
||||
virtualHosts.home-assistant'local.allServerNames
|
||||
];
|
||||
};
|
||||
vouch = {
|
||||
inherit (nginx) group;
|
||||
domain = virtualHosts.vouch.serverName;
|
||||
extraDomainNames = mkMerge [
|
||||
virtualHosts.vouch.serverAliases
|
||||
virtualHosts.vouch'local.allServerNames
|
||||
(mkIf tailscale.enable virtualHosts.vouch'tail.allServerNames)
|
||||
];
|
||||
};
|
||||
${access.unifi.domain} = {
|
||||
|
|
@ -116,19 +136,20 @@ in {
|
|||
])
|
||||
];
|
||||
};
|
||||
${access.plex.domain} = {
|
||||
inherit (nginx) group;
|
||||
extraDomainNames = [access.plex.localDomain];
|
||||
};
|
||||
${access.kitchencam.domain} = {
|
||||
plex = {
|
||||
inherit (nginx) group;
|
||||
domain = virtualHosts.plex.serverName;
|
||||
extraDomainNames = mkMerge [
|
||||
[
|
||||
access.kitchencam.localDomain
|
||||
]
|
||||
(mkIf tailscale.enable [
|
||||
access.kitchencam.tailDomain
|
||||
])
|
||||
virtualHosts.plex.serverAliases
|
||||
virtualHosts.plex'local.allServerNames
|
||||
];
|
||||
};
|
||||
kitchencam = {
|
||||
inherit (nginx) group;
|
||||
domain = virtualHosts.kitchencam.serverName;
|
||||
extraDomainNames = mkMerge [
|
||||
virtualHosts.kitchencam.serverAliases
|
||||
virtualHosts.kitchencam'local.allServerNames
|
||||
];
|
||||
};
|
||||
${access.invidious.domain} = {
|
||||
|
|
@ -153,7 +174,6 @@ in {
|
|||
};
|
||||
access.vouch = assert vouch-proxy.enable; {
|
||||
url = "http://${keycloak.lib.access.hostnameForNetwork.local}:${toString vouch-proxy.settings.vouch.port}";
|
||||
useACMEHost = access.vouch.localDomain;
|
||||
};
|
||||
access.unifi = {
|
||||
host = tei.lib.access.hostnameForNetwork.local;
|
||||
|
|
@ -169,24 +189,40 @@ in {
|
|||
};
|
||||
access.kitchencam = {
|
||||
streamPort = 41081;
|
||||
useACMEHost = access.kitchencam.domain;
|
||||
};
|
||||
access.invidious = {
|
||||
url = "http://${mediabox.lib.access.hostnameForNetwork.local}:${toString mediabox.services.invidious.port}";
|
||||
};
|
||||
virtualHosts = {
|
||||
gensokyoZone.proxied.enable = "cloudflared";
|
||||
keycloak = {
|
||||
# we're not the real sso record-holder, so don't respond globally..
|
||||
local.denyGlobal = true;
|
||||
ssl.cert.name = "keycloak";
|
||||
};
|
||||
keycloak'local.ssl.cert.name = "keycloak";
|
||||
vouch.ssl.cert.name = "vouch";
|
||||
vouch'local.ssl.cert.name = "vouch";
|
||||
vouch'tail = mkIf tailscale.enable {
|
||||
ssl.cert.name = "vouch";
|
||||
};
|
||||
home-assistant = {
|
||||
# not the real hass record-holder, so don't respond globally..
|
||||
local.denyGlobal = true;
|
||||
ssl.cert.name = "home-assistant";
|
||||
locations."/".proxyPass = "http://${tei.lib.access.hostnameForNetwork.tail}:${toString home-assistant.config.http.server_port}";
|
||||
};
|
||||
home-assistant'local.ssl.cert.name = "home-assistant";
|
||||
${access.freepbx.domain} = {
|
||||
local.enable = true;
|
||||
};
|
||||
${access.proxmox.domain} = {
|
||||
useACMEHost = access.proxmox.domain;
|
||||
};
|
||||
${access.plex.domain} = {
|
||||
addSSL = true;
|
||||
useACMEHost = access.plex.domain;
|
||||
};
|
||||
${access.kitchencam.domain} = {
|
||||
};
|
||||
plex.ssl.cert.name = "plex";
|
||||
plex'local.ssl.cert.name = "plex";
|
||||
kitchencam.ssl.cert.name = "kitchencam";
|
||||
kitchencam'local.ssl.cert.name = "kitchencam";
|
||||
${access.invidious.domain} = {
|
||||
useACMEHost = access.invidious.domain;
|
||||
forceSSL = true;
|
||||
|
|
|
|||
|
|
@ -17,18 +17,20 @@
|
|||
tunnels.${tunnelId} = {
|
||||
default = "http_status:404";
|
||||
credentialsFile = config.sops.secrets.cloudflared-tunnel-keycloak.path;
|
||||
ingress = {
|
||||
${keycloak.settings.hostname} = assert keycloak.enable; let
|
||||
scheme = if keycloak.sslCertificate != null then "https" else "http";
|
||||
port = keycloak.settings."${scheme}-port";
|
||||
in {
|
||||
service = "${scheme}://localhost:${toString port}";
|
||||
originRequest.${if scheme == "https" then "noTLSVerify" else null} = true;
|
||||
ingress = let
|
||||
keycloakHost = if keycloak.settings.hostname != null then keycloak.settings.hostname else "sso.${config.networking.domain}";
|
||||
keyCloakScheme = if keycloak.sslCertificate != null then "https" else "http";
|
||||
keycloakPort = keycloak.settings."${keyCloakScheme}-port";
|
||||
in {
|
||||
${keycloakHost} = assert keycloak.enable; {
|
||||
service = "${keyCloakScheme}://localhost:${toString keycloakPort}";
|
||||
originRequest.${if keyCloakScheme == "https" then "noTLSVerify" else null} = true;
|
||||
};
|
||||
${vouch-proxy.domain}.service = assert vouch-proxy.enable; "http://localhost:${toString vouch-proxy.settings.vouch.port}";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sops.secrets.cloudflared-tunnel-keycloak = {
|
||||
owner = config.services.cloudflared.user;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -153,9 +153,9 @@ chmod 0755 /rpool/caches/plex/tautulli/cache
|
|||
mkshared hass 100286 100286 0700
|
||||
mkshared kanidm 100994 100993 0700
|
||||
mkshared mosquitto 100246 100246 0700
|
||||
mkshared plex 100193 100193 0755
|
||||
mkshared plex 100193 100193 0750
|
||||
mkshared postgresql 100071 100071 0750
|
||||
mkshared unifi 100990 100990 0755
|
||||
mkshared unifi 100990 100990 0750
|
||||
mkshared zigbee2mqtt 100317 100317 0700
|
||||
|
||||
ln -sf /lib/systemd/system/auth-rpcgss-module.service /etc/systemd/system/
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ in {
|
|||
nixos.postgres
|
||||
nixos.nginx
|
||||
nixos.access.zigbee2mqtt
|
||||
nixos.access.home-assistant
|
||||
nixos.access.unifi
|
||||
nixos.unifi
|
||||
nixos.mosquitto
|
||||
|
|
@ -27,13 +26,9 @@ in {
|
|||
./cloudflared.nix
|
||||
];
|
||||
|
||||
services.nginx = let
|
||||
inherit (config.services.nginx) access;
|
||||
in {
|
||||
services.nginx = {
|
||||
virtualHosts = {
|
||||
${access.zigbee2mqtt.domain} = {
|
||||
local.denyGlobal = true;
|
||||
};
|
||||
zigbee2mqtt.proxied.enable = "cloudflared";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,12 +19,14 @@ module "hakurei_system_records" {
|
|||
"prox",
|
||||
"id",
|
||||
"login",
|
||||
"sso",
|
||||
"ldap",
|
||||
"freeipa",
|
||||
"unifi",
|
||||
"pbx",
|
||||
"smb",
|
||||
"kitchen",
|
||||
"home",
|
||||
"yt",
|
||||
]
|
||||
global_subdomains = [
|
||||
|
|
@ -87,7 +89,6 @@ module "tewi_system_records" {
|
|||
local_subdomains = [
|
||||
"mqtt",
|
||||
"z2m",
|
||||
"home",
|
||||
"postgresql",
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue