158 lines
4.1 KiB
Nix
158 lines
4.1 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
registry,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.modules.services.reverse-proxy; # NOLINT(let_order)
|
|
|
|
generatedUdpStreams = lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
host: routes:
|
|
lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
entry: route: lib.optionals (route.protocol == "udp") (map (mkUdpStream host entry) route.ports)
|
|
) routes
|
|
)
|
|
) registry.route
|
|
);
|
|
|
|
mkUdpStream =
|
|
host: entry: port:
|
|
let
|
|
address =
|
|
compositeEntry.address
|
|
or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}");
|
|
compositeEntry = registry.join host entry;
|
|
in
|
|
{
|
|
inherit
|
|
host
|
|
entry
|
|
port
|
|
address
|
|
;
|
|
};
|
|
|
|
generatedStreamConfig = lib.concatMapStringsSep "\n" (stream: ''
|
|
server {
|
|
listen ${toString stream.port} udp;
|
|
proxy_pass ${stream.address}:${toString stream.port};
|
|
}
|
|
'') generatedUdpStreams;
|
|
generatedVirtualHosts =
|
|
if duplicateDomainMessages != [ ] then
|
|
throw (builtins.head duplicateDomainMessages)
|
|
else
|
|
lib.listToAttrs generatedVirtualHostList;
|
|
|
|
duplicateDomainMessages = lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
domain: virtualHosts:
|
|
if lib.length virtualHosts > 1 then
|
|
[
|
|
"duplicate route domain ${domain} in ${
|
|
lib.concatMapStringsSep " and " (
|
|
virtualHost: mkRegistryPath virtualHost.registryName virtualHost.host virtualHost.entry
|
|
) virtualHosts
|
|
}"
|
|
]
|
|
else
|
|
[ ]
|
|
) virtualHostsByDomain
|
|
);
|
|
|
|
virtualHostsByDomain = lib.foldl' (
|
|
acc: virtualHost:
|
|
acc
|
|
// {
|
|
${virtualHost.name} = (acc.${virtualHost.name} or [ ]) ++ [ virtualHost ];
|
|
}
|
|
) { } generatedVirtualHostList;
|
|
|
|
generatedVirtualHostList = generatedHttpsVirtualHostList ++ generatedHttpVirtualHostList;
|
|
|
|
generatedHttpsVirtualHostList = lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
host: routes:
|
|
lib.mapAttrsToList (entry: _route: mkVirtualHost host entry "https") (
|
|
lib.filterAttrs (_entry: route: route.protocol == "https") routes
|
|
)
|
|
) registry.route
|
|
);
|
|
|
|
mkVirtualHost =
|
|
host: entry: mode:
|
|
let
|
|
isHttp = mode == "http";
|
|
address =
|
|
compositeEntry.address
|
|
or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}");
|
|
compositeEntry = registry.join host entry;
|
|
inherit (compositeEntry) route;
|
|
inherit (route) port;
|
|
in
|
|
{
|
|
inherit host entry;
|
|
registryName = "route";
|
|
name = route.domain;
|
|
value = {
|
|
forceSSL = !isHttp;
|
|
enableACME = !isHttp;
|
|
locations."/".proxyPass = mkBackend address port;
|
|
};
|
|
};
|
|
|
|
mkBackend = address: port: "http://${address}:${toString port}";
|
|
|
|
generatedHttpVirtualHostList = lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
host: routes:
|
|
lib.mapAttrsToList (entry: _route: mkVirtualHost host entry "http") (
|
|
lib.filterAttrs (_entry: route: route.protocol == "http") routes
|
|
)
|
|
) registry.route
|
|
);
|
|
|
|
mkRegistryPath =
|
|
registryName: host: entry:
|
|
"registry.${registryName}.${host}.${entry}";
|
|
|
|
in
|
|
{
|
|
options.modules.services.reverse-proxy = {
|
|
enable = lib.mkEnableOption "the public edge reverse proxy";
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
networking.firewall.allowedTCPPorts = [
|
|
80
|
|
443
|
|
];
|
|
networking.firewall.allowedUDPPorts = map (stream: stream.port) generatedUdpStreams;
|
|
|
|
security.acme = {
|
|
acceptTerms = true;
|
|
defaults.email = "contact@alexion.dev";
|
|
};
|
|
|
|
services.nginx = {
|
|
enable = true;
|
|
commonHttpConfig = ''
|
|
server {
|
|
listen 0.0.0.0:443 ssl default_server;
|
|
listen [::0]:443 ssl default_server;
|
|
ssl_reject_handshake on;
|
|
}
|
|
'';
|
|
recommendedGzipSettings = true;
|
|
recommendedOptimisation = true;
|
|
recommendedProxySettings = true;
|
|
recommendedTlsSettings = true;
|
|
streamConfig = lib.mkIf (generatedUdpStreams != [ ]) generatedStreamConfig;
|
|
virtualHosts = generatedVirtualHosts;
|
|
};
|
|
};
|
|
}
|