Files
dev/configs/nixos/modules/services/reverse-proxy.nix

120 lines
3.1 KiB
Nix

{
config,
lib,
registry,
...
}:
let
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 = lib.listToAttrs generatedVirtualHostList;
# Route registry validation already requires unique domains.
generatedVirtualHostList = lib.concatLists (
lib.mapAttrsToList (
host: routes:
lib.mapAttrsToList (entry: route: mkVirtualHost host entry route.protocol) (
lib.filterAttrs (_entry: route: route.protocol != "udp") 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
{
name = route.domain;
value = {
forceSSL = !isHttp;
enableACME = !isHttp;
extraConfig = lib.optionalString (route.clientMaxBodySize != null) ''
client_max_body_size ${route.clientMaxBodySize};
'';
locations."/".proxyPass = mkBackend address port;
};
};
mkBackend = address: port: "http://${address}:${toString port}";
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 config.modules.services.reverse-proxy.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;
};
};
}