{ inputs }: let inherit (inputs.nixpkgs.lib) mkOption types listToAttrs nameValuePair ; in rec { # Create a service configuration for Traefik mkService = { name, url, loadBalancer ? { }, }: { inherit name url; config = { loadBalancer = { servers = [{ inherit url; }]; } // loadBalancer; }; }; # Create a router configuration for Traefik mkRouter = { subdomain, domain ? "mjallen.dev", service, entryPoints ? [ "websecure" ], middlewares ? [ "crowdsec" "whitelist-geoblock" ], priority ? null, rule ? null, tls ? { certResolver = "letsencrypt"; }, }: { inherit subdomain service entryPoints middlewares; config = { inherit entryPoints service middlewares tls; rule = if rule != null then rule else "Host(`${subdomain}.${domain}`)"; } // (if priority != null then { inherit priority; } else { }); }; # Create both service and router for a simple reverse proxy setup mkReverseProxy = { name, subdomain, url, domain ? "mjallen.dev", entryPoints ? [ "websecure" ], middlewares ? [ "crowdsec" "whitelist-geoblock" ], priority ? null, rule ? null, tls ? { certResolver = "letsencrypt"; }, loadBalancer ? { }, }: { service = mkService { inherit name url loadBalancer; }; router = mkRouter { inherit subdomain domain entryPoints middlewares priority rule tls; service = name; }; }; # Convert a list of services to the format expected by Traefik module servicesToConfig = services: listToAttrs (map (service: nameValuePair service.name service.config) services); # Convert a list of routers to the format expected by Traefik module routersToConfig = routers: listToAttrs (map (router: nameValuePair router.subdomain router.config) routers); # Helper to create multiple reverse proxies at once mkReverseProxies = proxies: let results = map mkReverseProxy proxies; services = map (result: result.service) results; routers = map (result: result.router) results; in { services = servicesToConfig services; routers = routersToConfig routers; extraServices = services; extraRouters = map (router: { inherit (router) subdomain entryPoints middlewares; service = router.service; }) routers; }; # Common middleware configurations middlewares = { # Authentication middleware auth = [ "authentik" ]; # Basic security (default) basic = [ "crowdsec" "whitelist-geoblock" ]; # Internal only access internal = [ "crowdsec" "whitelist-geoblock" "internal-ipallowlist" ]; # WebSocket support websocket = [ "crowdsec" "whitelist-geoblock" "onlyoffice-websocket" ]; # Authenticated with basic security authBasic = [ "crowdsec" "whitelist-geoblock" "authentik" ]; }; # Common service URL builders urls = { # Local container service container = containerName: port: "http://\${config.containers.${containerName}.localAddress}:${toString port}"; # Local host service localhost = port: "http://127.0.0.1:${toString port}"; # Network service network = ip: port: "http://${ip}:${toString port}"; # Server IP service (using your server IP pattern) server = port: "http://\${serverIp}:${toString port}"; }; # Pre-configured reverse proxy templates templates = { # Standard web application webapp = { name, subdomain, port, ... }@args: mkReverseProxy ({ url = urls.localhost port; middlewares = middlewares.basic; } // args); # Authenticated web application authWebapp = { name, subdomain, port, ... }@args: mkReverseProxy ({ url = urls.localhost port; middlewares = middlewares.authBasic; } // args); # Container-based service containerService = { name, subdomain, containerName, port, ... }@args: mkReverseProxy ({ url = urls.container containerName port; middlewares = middlewares.basic; } // args); # Internal-only service internalService = { name, subdomain, port, ... }@args: mkReverseProxy ({ url = urls.localhost port; middlewares = middlewares.internal; } // args); }; }