{ config, lib, pkgs, ... }: with lib; let cfg = config.clerie.nginx-port-forward; certs = config.security.acme.certs; sslDhparam = config.services.nginx.sslDhparam; mkServerBlock = isUDP: port: forward: '' server { listen ${port}${optionalString isUDP " udp"}${optionalString (forward.certName != null) " ssl"}; listen [::]:${port}${optionalString isUDP " udp"}${optionalString (forward.certName != null) " ssl"}; ${ optionalString (forward.certName != null) '' ssl_certificate ${certs.${forward.certName}.directory}/fullchain.pem; ssl_certificate_key ${certs.${forward.certName}.directory}/key.pem; ${ optionalString (sslDhparam != null) "ssl_dhparam ${sslDhparam};" } '' } proxy_pass ${forward.host}:${toString forward.port}; } ''; portForwardConf = '' stream { ${ concatStringsSep "\n" (mapAttrsToList (mkServerBlock false) cfg.tcpPorts) } ${ concatStringsSep "\n" (mapAttrsToList (mkServerBlock true) cfg.udpPorts) } } ''; portOpts = { config, ... }@moduleAttrs: { options = { host = mkOption { type = types.str; }; port = mkOption { type = types.int; }; certName = mkOption { type = with types; nullOr str; default = null; }; }; }; in { options = { clerie.nginx-port-forward = { enable = mkEnableOption "Nginx Port Forward"; tcpPorts = mkOption { type = with types; attrsOf (submodule portOpts); default = {}; }; udpPorts = mkOption { type = with types; attrsOf (submodule portOpts); default = {}; }; }; }; config = mkIf cfg.enable { services.nginx.enable = true; services.nginx.appendConfig = portForwardConf; networking.firewall.allowedTCPPorts = mapAttrsToList ( port: dontcare: toInt port ) cfg.tcpPorts; networking.firewall.allowedUDPPorts = mapAttrsToList ( port: dontcare: toInt port ) cfg.udpPorts; }; }