139 lines
3.9 KiB
Nix
139 lines
3.9 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
registry,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.modules.services.reverse-proxy;
|
|
|
|
mkRegistryPath = registryName: host: entry: "registry.${registryName}.${host}.${entry}";
|
|
|
|
mkBackend = address: port: "http://${address}:${toString port}";
|
|
|
|
mkVirtualHost = host: entry: mode:
|
|
let
|
|
compositeEntry = registry.join host entry;
|
|
route = compositeEntry.route;
|
|
address = compositeEntry.address or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}");
|
|
isHttp = mode == "http";
|
|
port = if isHttp then route.http.port else route.port;
|
|
in
|
|
{
|
|
inherit host entry;
|
|
registryName = "route";
|
|
name = route.domain;
|
|
value = {
|
|
forceSSL = !isHttp;
|
|
enableACME = !isHttp;
|
|
locations."/".proxyPass = mkBackend address port;
|
|
};
|
|
};
|
|
|
|
generatedHttpsVirtualHostList = lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
host: routes:
|
|
lib.mapAttrsToList (entry: _route: mkVirtualHost host entry "https") (
|
|
lib.filterAttrs (_entry: route: route.port != null) routes
|
|
)
|
|
) registry.route
|
|
);
|
|
|
|
generatedHttpVirtualHostList = lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
host: routes:
|
|
lib.mapAttrsToList (entry: _route: mkVirtualHost host entry "http") (
|
|
lib.filterAttrs (_entry: route: route.http.port != null) routes
|
|
)
|
|
) registry.route
|
|
);
|
|
|
|
generatedVirtualHostList = generatedHttpsVirtualHostList ++ generatedHttpVirtualHostList;
|
|
|
|
virtualHostsByDomain = lib.foldl' (
|
|
acc: virtualHost:
|
|
acc
|
|
// {
|
|
${virtualHost.name} = (acc.${virtualHost.name} or [ ]) ++ [ virtualHost ];
|
|
}
|
|
) { } 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
|
|
);
|
|
|
|
generatedVirtualHosts =
|
|
if duplicateDomainMessages != [ ] then
|
|
throw (builtins.head duplicateDomainMessages)
|
|
else
|
|
lib.listToAttrs generatedVirtualHostList;
|
|
|
|
mkUdpStream = host: entry: port:
|
|
let
|
|
compositeEntry = registry.join host entry;
|
|
address = compositeEntry.address or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}");
|
|
in
|
|
{
|
|
inherit host entry port address;
|
|
};
|
|
|
|
generatedUdpStreams = lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
host: routes:
|
|
lib.concatLists (
|
|
lib.mapAttrsToList (entry: route: map (mkUdpStream host entry) route.udp.ports) routes
|
|
)
|
|
) registry.route
|
|
);
|
|
|
|
generatedStreamConfig = lib.concatMapStringsSep "\n" (stream: ''
|
|
server {
|
|
listen ${toString stream.port} udp;
|
|
proxy_pass ${stream.address}:${toString stream.port};
|
|
}
|
|
'') generatedUdpStreams;
|
|
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;
|
|
};
|
|
};
|
|
}
|