Loading nixos/modules/security/acme/default.nix +1 −1 Original line number Diff line number Diff line Loading @@ -217,7 +217,7 @@ let protocolOpts = if useDns then ( [ "--dns" data.dnsProvider ] ++ lib.optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ] ++ lib.optionals (!data.dnsPropagationCheck) [ "--dns.propagation-disable-ans" ] ++ lib.optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ] ) else if data.s3Bucket != null then [ "--http" "--http.s3-bucket" data.s3Bucket ] else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ] Loading nixos/modules/security/acme/mk-cert-ownership-assertion.nix +20 −3 Original line number Diff line number Diff line { cert, group, groups, user }: { assertion = cert.group == group || builtins.any (u: u == user) groups.${cert.group}.members; message = "Group for certificate ${cert.domain} must be ${group}, or user ${user} must be a member of group ${cert.group}"; lib: { cert, groups, services }: let catSep = builtins.concatStringsSep; svcGroups = svc: (lib.optional (svc.serviceConfig ? Group) svc.serviceConfig.Group) ++ (svc.serviceConfig.SupplementaryGroups or [ ]); in { assertion = builtins.all (svc: svc.serviceConfig.User or "root" == "root" || builtins.elem svc.serviceConfig.User groups.${cert.group}.members || builtins.elem cert.group (svcGroups svc) ) services; message = "Certificate ${cert.domain} (group=${cert.group}) must be readable by service(s) ${ catSep ", " (map (svc: "${svc.name} (user=${svc.serviceConfig.User} groups=${catSep " " (svcGroups svc)})") services) }"; } nixos/modules/services/web-servers/apache-httpd/default.nix +14 −10 Original line number Diff line number Diff line Loading @@ -33,7 +33,9 @@ let certName = if hostOpts.useACMEHost != null then hostOpts.useACMEHost else hostOpts.hostName; }) (filter (hostOpts: hostOpts.enableACME || hostOpts.useACMEHost != null) vhosts); dependentCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts); vhostCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts); dependentCertNames = filter (cert: certs.${cert}.dnsProvider == null) vhostCertNames; # those that might depend on the HTTP server independentCertNames = filter (cert: certs.${cert}.dnsProvider != null) vhostCertNames; # those that don't depend on the HTTP server mkListenInfo = hostOpts: if hostOpts.listen != [] then Loading Loading @@ -371,7 +373,7 @@ let echo "$options" >> $out ''; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix lib; in Loading Loading @@ -641,10 +643,10 @@ in ''; } ] ++ map (name: mkCertOwnershipAssertion { inherit (cfg) group user; cert = config.security.acme.certs.${name}; groups = config.users.groups; }) dependentCertNames; services = [ config.systemd.services.httpd ] ++ lib.optional (vhostCertNames != []) config.systemd.services.httpd-config-reload; }) vhostCertNames; warnings = mapAttrsToList (name: hostOpts: '' Loading Loading @@ -747,8 +749,10 @@ in systemd.services.httpd = { description = "Apache HTTPD"; wantedBy = [ "multi-user.target" ]; wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) dependentCertNames); after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") dependentCertNames; wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) vhostCertNames); after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") vhostCertNames ++ map (certName: "acme-${certName}.service") independentCertNames; # avoid loading self-signed key w/ real cert, or vice-versa before = map (certName: "acme-${certName}.service") dependentCertNames; restartTriggers = [ cfg.configFile ]; Loading Loading @@ -789,9 +793,9 @@ in # which allows the acme-finished-$cert.target to signify the successful updating # of certs end-to-end. systemd.services.httpd-config-reload = let sslServices = map (certName: "acme-${certName}.service") dependentCertNames; sslTargets = map (certName: "acme-finished-${certName}.target") dependentCertNames; in mkIf (sslServices != []) { sslServices = map (certName: "acme-${certName}.service") vhostCertNames; sslTargets = map (certName: "acme-finished-${certName}.target") vhostCertNames; in mkIf (vhostCertNames != []) { wantedBy = sslServices ++ [ "multi-user.target" ]; # Before the finished targets, after the renew services. # This service might be needed for HTTP-01 challenges, but we only want to confirm Loading @@ -801,7 +805,7 @@ in restartTriggers = [ cfg.configFile ]; # Block reloading if not all certs exist yet. # Happens when config changes add new vhosts/certs. unitConfig.ConditionPathExists = map (certName: certs.${certName}.directory + "/fullchain.pem") dependentCertNames; unitConfig.ConditionPathExists = map (certName: certs.${certName}.directory + "/fullchain.pem") vhostCertNames; serviceConfig = { Type = "oneshot"; TimeoutSec = 60; Loading nixos/modules/services/web-servers/caddy/default.nix +14 −11 Original line number Diff line number Diff line Loading @@ -5,8 +5,12 @@ with lib; let cfg = config.services.caddy; certs = config.security.acme.certs; virtualHosts = attrValues cfg.virtualHosts; acmeVHosts = filter (hostOpts: hostOpts.useACMEHost != null) virtualHosts; acmeEnabledVhosts = filter (hostOpts: hostOpts.useACMEHost != null) virtualHosts; vhostCertNames = unique (map (hostOpts: hostOpts.useACMEHost) acmeEnabledVhosts); dependentCertNames = filter (cert: certs.${cert}.dnsProvider == null) vhostCertNames; # those that might depend on the HTTP server independentCertNames = filter (cert: certs.${cert}.dnsProvider != null) vhostCertNames; # those that don't depend on the HTTP server mkVHostConf = hostOpts: let Loading Loading @@ -51,9 +55,7 @@ let configPath = "/etc/${etcConfigFile}"; acmeHosts = unique (catAttrs "useACMEHost" acmeVHosts); mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix lib; in { imports = [ Loading Loading @@ -329,10 +331,10 @@ in message = "To specify an adapter other than 'caddyfile' please provide your own configuration via `services.caddy.configFile`"; } ] ++ map (name: mkCertOwnershipAssertion { inherit (cfg) group user; cert = config.security.acme.certs.${name}; groups = config.users.groups; }) acmeHosts; services = [ config.systemd.services.caddy ]; }) vhostCertNames; services.caddy.globalConfig = '' ${optionalString (cfg.email != null) "email ${cfg.email}"} Loading @@ -348,9 +350,10 @@ in systemd.packages = [ cfg.package ]; systemd.services.caddy = { wants = map (hostOpts: "acme-finished-${hostOpts.useACMEHost}.target") acmeVHosts; after = map (hostOpts: "acme-selfsigned-${hostOpts.useACMEHost}.service") acmeVHosts; before = map (hostOpts: "acme-${hostOpts.useACMEHost}.service") acmeVHosts; wants = map (certName: "acme-finished-${certName}.target") vhostCertNames; after = map (certName: "acme-selfsigned-${certName}.service") vhostCertNames ++ map (certName: "acme-${certName}.service") independentCertNames; # avoid loading self-signed key w/ real cert, or vice-versa before = map (certName: "acme-${certName}.service") dependentCertNames; wantedBy = [ "multi-user.target" ]; startLimitIntervalSec = 14400; Loading Loading @@ -397,10 +400,10 @@ in security.acme.certs = let certCfg = map (useACMEHost: nameValuePair useACMEHost { certCfg = map (certName: nameValuePair certName { group = mkDefault cfg.group; reloadServices = [ "caddy.service" ]; }) acmeHosts; }) vhostCertNames; in listToAttrs certCfg; Loading nixos/modules/services/web-servers/nginx/default.nix +14 −10 Original line number Diff line number Diff line Loading @@ -7,7 +7,9 @@ let inherit (config.security.acme) certs; vhostsConfigs = mapAttrsToList (vhostName: vhostConfig: vhostConfig) virtualHosts; acmeEnabledVhosts = filter (vhostConfig: vhostConfig.enableACME || vhostConfig.useACMEHost != null) vhostsConfigs; dependentCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts); vhostCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts); dependentCertNames = filter (cert: certs.${cert}.dnsProvider == null) vhostCertNames; # those that might depend on the HTTP server independentCertNames = filter (cert: certs.${cert}.dnsProvider != null) vhostCertNames; # those that don't depend on the HTTP server virtualHosts = mapAttrs (vhostName: vhostConfig: let serverName = if vhostConfig.serverName != null Loading Loading @@ -471,7 +473,7 @@ let '') authDef) ); mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix lib; oldHTTP2 = (versionOlder cfg.package.version "1.25.1" && !(cfg.package.pname == "angie" || cfg.package.pname == "angieQuic")); in Loading Loading @@ -1209,10 +1211,10 @@ in ''; } ] ++ map (name: mkCertOwnershipAssertion { inherit (cfg) group user; cert = config.security.acme.certs.${name}; groups = config.users.groups; }) dependentCertNames; services = [ config.systemd.services.nginx ] ++ lib.optional (cfg.enableReload || vhostCertNames != []) config.systemd.services.nginx-config-reload; }) vhostCertNames; services.nginx.additionalModules = optional cfg.recommendedBrotliSettings pkgs.nginxModules.brotli ++ lib.optional cfg.recommendedZstdSettings pkgs.nginxModules.zstd; Loading @@ -1236,8 +1238,10 @@ in systemd.services.nginx = { description = "Nginx Web Server"; wantedBy = [ "multi-user.target" ]; wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) dependentCertNames); after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") dependentCertNames; wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) vhostCertNames); after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") vhostCertNames ++ map (certName: "acme-${certName}.service") independentCertNames; # avoid loading self-signed key w/ real cert, or vice-versa # Nginx needs to be started in order to be able to request certificates # (it's hosting the acme challenge after all) # This fixes https://github.com/NixOS/nixpkgs/issues/81842 Loading Loading @@ -1316,9 +1320,9 @@ in # which allows the acme-finished-$cert.target to signify the successful updating # of certs end-to-end. systemd.services.nginx-config-reload = let sslServices = map (certName: "acme-${certName}.service") dependentCertNames; sslTargets = map (certName: "acme-finished-${certName}.target") dependentCertNames; in mkIf (cfg.enableReload || sslServices != []) { sslServices = map (certName: "acme-${certName}.service") vhostCertNames; sslTargets = map (certName: "acme-finished-${certName}.target") vhostCertNames; in mkIf (cfg.enableReload || vhostCertNames != []) { wants = optionals cfg.enableReload [ "nginx.service" ]; wantedBy = sslServices ++ [ "multi-user.target" ]; # Before the finished targets, after the renew services. Loading @@ -1329,7 +1333,7 @@ in restartTriggers = optionals cfg.enableReload [ configFile ]; # Block reloading if not all certs exist yet. # Happens when config changes add new vhosts/certs. unitConfig.ConditionPathExists = optionals (sslServices != []) (map (certName: certs.${certName}.directory + "/fullchain.pem") dependentCertNames); unitConfig.ConditionPathExists = optionals (sslServices != []) (map (certName: certs.${certName}.directory + "/fullchain.pem") vhostCertNames); serviceConfig = { Type = "oneshot"; TimeoutSec = 60; Loading Loading
nixos/modules/security/acme/default.nix +1 −1 Original line number Diff line number Diff line Loading @@ -217,7 +217,7 @@ let protocolOpts = if useDns then ( [ "--dns" data.dnsProvider ] ++ lib.optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ] ++ lib.optionals (!data.dnsPropagationCheck) [ "--dns.propagation-disable-ans" ] ++ lib.optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ] ) else if data.s3Bucket != null then [ "--http" "--http.s3-bucket" data.s3Bucket ] else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ] Loading
nixos/modules/security/acme/mk-cert-ownership-assertion.nix +20 −3 Original line number Diff line number Diff line { cert, group, groups, user }: { assertion = cert.group == group || builtins.any (u: u == user) groups.${cert.group}.members; message = "Group for certificate ${cert.domain} must be ${group}, or user ${user} must be a member of group ${cert.group}"; lib: { cert, groups, services }: let catSep = builtins.concatStringsSep; svcGroups = svc: (lib.optional (svc.serviceConfig ? Group) svc.serviceConfig.Group) ++ (svc.serviceConfig.SupplementaryGroups or [ ]); in { assertion = builtins.all (svc: svc.serviceConfig.User or "root" == "root" || builtins.elem svc.serviceConfig.User groups.${cert.group}.members || builtins.elem cert.group (svcGroups svc) ) services; message = "Certificate ${cert.domain} (group=${cert.group}) must be readable by service(s) ${ catSep ", " (map (svc: "${svc.name} (user=${svc.serviceConfig.User} groups=${catSep " " (svcGroups svc)})") services) }"; }
nixos/modules/services/web-servers/apache-httpd/default.nix +14 −10 Original line number Diff line number Diff line Loading @@ -33,7 +33,9 @@ let certName = if hostOpts.useACMEHost != null then hostOpts.useACMEHost else hostOpts.hostName; }) (filter (hostOpts: hostOpts.enableACME || hostOpts.useACMEHost != null) vhosts); dependentCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts); vhostCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts); dependentCertNames = filter (cert: certs.${cert}.dnsProvider == null) vhostCertNames; # those that might depend on the HTTP server independentCertNames = filter (cert: certs.${cert}.dnsProvider != null) vhostCertNames; # those that don't depend on the HTTP server mkListenInfo = hostOpts: if hostOpts.listen != [] then Loading Loading @@ -371,7 +373,7 @@ let echo "$options" >> $out ''; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix lib; in Loading Loading @@ -641,10 +643,10 @@ in ''; } ] ++ map (name: mkCertOwnershipAssertion { inherit (cfg) group user; cert = config.security.acme.certs.${name}; groups = config.users.groups; }) dependentCertNames; services = [ config.systemd.services.httpd ] ++ lib.optional (vhostCertNames != []) config.systemd.services.httpd-config-reload; }) vhostCertNames; warnings = mapAttrsToList (name: hostOpts: '' Loading Loading @@ -747,8 +749,10 @@ in systemd.services.httpd = { description = "Apache HTTPD"; wantedBy = [ "multi-user.target" ]; wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) dependentCertNames); after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") dependentCertNames; wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) vhostCertNames); after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") vhostCertNames ++ map (certName: "acme-${certName}.service") independentCertNames; # avoid loading self-signed key w/ real cert, or vice-versa before = map (certName: "acme-${certName}.service") dependentCertNames; restartTriggers = [ cfg.configFile ]; Loading Loading @@ -789,9 +793,9 @@ in # which allows the acme-finished-$cert.target to signify the successful updating # of certs end-to-end. systemd.services.httpd-config-reload = let sslServices = map (certName: "acme-${certName}.service") dependentCertNames; sslTargets = map (certName: "acme-finished-${certName}.target") dependentCertNames; in mkIf (sslServices != []) { sslServices = map (certName: "acme-${certName}.service") vhostCertNames; sslTargets = map (certName: "acme-finished-${certName}.target") vhostCertNames; in mkIf (vhostCertNames != []) { wantedBy = sslServices ++ [ "multi-user.target" ]; # Before the finished targets, after the renew services. # This service might be needed for HTTP-01 challenges, but we only want to confirm Loading @@ -801,7 +805,7 @@ in restartTriggers = [ cfg.configFile ]; # Block reloading if not all certs exist yet. # Happens when config changes add new vhosts/certs. unitConfig.ConditionPathExists = map (certName: certs.${certName}.directory + "/fullchain.pem") dependentCertNames; unitConfig.ConditionPathExists = map (certName: certs.${certName}.directory + "/fullchain.pem") vhostCertNames; serviceConfig = { Type = "oneshot"; TimeoutSec = 60; Loading
nixos/modules/services/web-servers/caddy/default.nix +14 −11 Original line number Diff line number Diff line Loading @@ -5,8 +5,12 @@ with lib; let cfg = config.services.caddy; certs = config.security.acme.certs; virtualHosts = attrValues cfg.virtualHosts; acmeVHosts = filter (hostOpts: hostOpts.useACMEHost != null) virtualHosts; acmeEnabledVhosts = filter (hostOpts: hostOpts.useACMEHost != null) virtualHosts; vhostCertNames = unique (map (hostOpts: hostOpts.useACMEHost) acmeEnabledVhosts); dependentCertNames = filter (cert: certs.${cert}.dnsProvider == null) vhostCertNames; # those that might depend on the HTTP server independentCertNames = filter (cert: certs.${cert}.dnsProvider != null) vhostCertNames; # those that don't depend on the HTTP server mkVHostConf = hostOpts: let Loading Loading @@ -51,9 +55,7 @@ let configPath = "/etc/${etcConfigFile}"; acmeHosts = unique (catAttrs "useACMEHost" acmeVHosts); mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix lib; in { imports = [ Loading Loading @@ -329,10 +331,10 @@ in message = "To specify an adapter other than 'caddyfile' please provide your own configuration via `services.caddy.configFile`"; } ] ++ map (name: mkCertOwnershipAssertion { inherit (cfg) group user; cert = config.security.acme.certs.${name}; groups = config.users.groups; }) acmeHosts; services = [ config.systemd.services.caddy ]; }) vhostCertNames; services.caddy.globalConfig = '' ${optionalString (cfg.email != null) "email ${cfg.email}"} Loading @@ -348,9 +350,10 @@ in systemd.packages = [ cfg.package ]; systemd.services.caddy = { wants = map (hostOpts: "acme-finished-${hostOpts.useACMEHost}.target") acmeVHosts; after = map (hostOpts: "acme-selfsigned-${hostOpts.useACMEHost}.service") acmeVHosts; before = map (hostOpts: "acme-${hostOpts.useACMEHost}.service") acmeVHosts; wants = map (certName: "acme-finished-${certName}.target") vhostCertNames; after = map (certName: "acme-selfsigned-${certName}.service") vhostCertNames ++ map (certName: "acme-${certName}.service") independentCertNames; # avoid loading self-signed key w/ real cert, or vice-versa before = map (certName: "acme-${certName}.service") dependentCertNames; wantedBy = [ "multi-user.target" ]; startLimitIntervalSec = 14400; Loading Loading @@ -397,10 +400,10 @@ in security.acme.certs = let certCfg = map (useACMEHost: nameValuePair useACMEHost { certCfg = map (certName: nameValuePair certName { group = mkDefault cfg.group; reloadServices = [ "caddy.service" ]; }) acmeHosts; }) vhostCertNames; in listToAttrs certCfg; Loading
nixos/modules/services/web-servers/nginx/default.nix +14 −10 Original line number Diff line number Diff line Loading @@ -7,7 +7,9 @@ let inherit (config.security.acme) certs; vhostsConfigs = mapAttrsToList (vhostName: vhostConfig: vhostConfig) virtualHosts; acmeEnabledVhosts = filter (vhostConfig: vhostConfig.enableACME || vhostConfig.useACMEHost != null) vhostsConfigs; dependentCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts); vhostCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts); dependentCertNames = filter (cert: certs.${cert}.dnsProvider == null) vhostCertNames; # those that might depend on the HTTP server independentCertNames = filter (cert: certs.${cert}.dnsProvider != null) vhostCertNames; # those that don't depend on the HTTP server virtualHosts = mapAttrs (vhostName: vhostConfig: let serverName = if vhostConfig.serverName != null Loading Loading @@ -471,7 +473,7 @@ let '') authDef) ); mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix lib; oldHTTP2 = (versionOlder cfg.package.version "1.25.1" && !(cfg.package.pname == "angie" || cfg.package.pname == "angieQuic")); in Loading Loading @@ -1209,10 +1211,10 @@ in ''; } ] ++ map (name: mkCertOwnershipAssertion { inherit (cfg) group user; cert = config.security.acme.certs.${name}; groups = config.users.groups; }) dependentCertNames; services = [ config.systemd.services.nginx ] ++ lib.optional (cfg.enableReload || vhostCertNames != []) config.systemd.services.nginx-config-reload; }) vhostCertNames; services.nginx.additionalModules = optional cfg.recommendedBrotliSettings pkgs.nginxModules.brotli ++ lib.optional cfg.recommendedZstdSettings pkgs.nginxModules.zstd; Loading @@ -1236,8 +1238,10 @@ in systemd.services.nginx = { description = "Nginx Web Server"; wantedBy = [ "multi-user.target" ]; wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) dependentCertNames); after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") dependentCertNames; wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) vhostCertNames); after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") vhostCertNames ++ map (certName: "acme-${certName}.service") independentCertNames; # avoid loading self-signed key w/ real cert, or vice-versa # Nginx needs to be started in order to be able to request certificates # (it's hosting the acme challenge after all) # This fixes https://github.com/NixOS/nixpkgs/issues/81842 Loading Loading @@ -1316,9 +1320,9 @@ in # which allows the acme-finished-$cert.target to signify the successful updating # of certs end-to-end. systemd.services.nginx-config-reload = let sslServices = map (certName: "acme-${certName}.service") dependentCertNames; sslTargets = map (certName: "acme-finished-${certName}.target") dependentCertNames; in mkIf (cfg.enableReload || sslServices != []) { sslServices = map (certName: "acme-${certName}.service") vhostCertNames; sslTargets = map (certName: "acme-finished-${certName}.target") vhostCertNames; in mkIf (cfg.enableReload || vhostCertNames != []) { wants = optionals cfg.enableReload [ "nginx.service" ]; wantedBy = sslServices ++ [ "multi-user.target" ]; # Before the finished targets, after the renew services. Loading @@ -1329,7 +1333,7 @@ in restartTriggers = optionals cfg.enableReload [ configFile ]; # Block reloading if not all certs exist yet. # Happens when config changes add new vhosts/certs. unitConfig.ConditionPathExists = optionals (sslServices != []) (map (certName: certs.${certName}.directory + "/fullchain.pem") dependentCertNames); unitConfig.ConditionPathExists = optionals (sslServices != []) (map (certName: certs.${certName}.directory + "/fullchain.pem") vhostCertNames); serviceConfig = { Type = "oneshot"; TimeoutSec = 60; Loading