{self}: { config, lib, pkgs, ... }: let cfg = config.services.azess; inherit (lib) mkEnableOption mkIf mkOption types; defaultPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default; gunicornArgs = [ "--workers" (toString cfg.workers) "--bind" "${cfg.host}:${toString cfg.port}" ] ++ cfg.extraArgs; in { options.services.azess = { enable = mkEnableOption "AZess Flask/Gunicorn web application"; package = mkOption { type = types.package; default = defaultPackage; defaultText = "self.packages.\${pkgs.stdenv.hostPlatform.system}.default"; description = "AZess package to run."; }; host = mkOption { type = types.str; default = "127.0.0.1"; description = "Host/IP address Gunicorn binds to."; }; port = mkOption { type = types.port; default = 8000; description = "TCP port Gunicorn binds to."; }; workers = mkOption { type = types.ints.positive; default = 4; description = "Number of Gunicorn worker processes."; }; openFirewall = mkOption { type = types.bool; default = false; description = "Open the configured TCP port in the local firewall."; }; extraArgs = mkOption { type = types.listOf types.str; default = []; description = "Additional arguments passed to Gunicorn before app:app."; }; }; config = mkIf cfg.enable { users.groups.azess = {}; users.users.azess = { isSystemUser = true; group = "azess"; description = "AZess service user"; }; systemd.services.azess = { description = "AZess Active Directory user setup application"; wantedBy = ["multi-user.target"]; after = ["network.target"]; environment = { XDG_CACHE_HOME = "/var/cache/azess"; }; serviceConfig = { ExecStart = "${lib.getExe cfg.package} ${lib.escapeShellArgs gunicornArgs}"; Restart = "on-failure"; RestartSec = "5s"; User = "azess"; Group = "azess"; CacheDirectory = "azess"; RuntimeDirectory = "azess"; NoNewPrivileges = true; PrivateTmp = true; ProtectHome = true; ProtectSystem = "strict"; RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"]; }; }; networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [cfg.port]; }; }