let cfg = config.services.caddy; <del> vhostToConfig = vhostName: vhostAttrs: '' ${vhostName} ${builtins.concatStringsSep " " vhostAttrs.serverAliases} { ${vhostAttrs.extraConfig} } ''; configFile = pkgs.writeText "Caddyfile" (builtins.concatStringsSep "n" ([ cfg.config ] ++ (mapAttrsToList vhostToConfig cfg.virtualHosts))); formattedConfig = pkgs.runCommand "formattedCaddyFile" { } '' ${cfg.package}/bin/caddy fmt ${configFile} > $out ''; tlsConfig = { apps.tls.automation.policies = [{ issuers = [{ inherit (cfg) ca email; module = "acme"; }]; }]; }; adaptedConfig = pkgs.runCommand "caddy-config-adapted.json" { } '' ${cfg.package}/bin/caddy adapt  --config ${formattedConfig} --adapter ${cfg.adapter} > $out ''; tlsJSON = pkgs.writeText "tls.json" (builtins.toJSON tlsConfig); # merge the TLS config options we expose with the ones originating in the Caddyfile configJSON = if cfg.ca != null then let tlsConfigMerge = '' {"apps": {"tls": {"automation": {"policies": (if .[0].apps.tls.automation.policies == .[1]?.apps.tls.automation.policies then .[0].apps.tls.automation.policies else (.[0].apps.tls.automation.policies + .[1]?.apps.tls.automation.policies) end) } } } }''; in pkgs.runCommand "caddy-config.json" { } '' ${pkgs.jq}/bin/jq -s '.[0] * ${tlsConfigMerge}' ${adaptedConfig} ${tlsJSON} > $out </del> <ins> virtualHosts = attrValues cfg.virtualHosts; acmeVHosts = filter (hostOpts: hostOpts.useACMEHost != null) virtualHosts; mkVHostConf = hostOpts: let sslCertDir = config.security.acme.certs.${hostOpts.useACMEHost}.directory; in </ins> '' <del> else adaptedConfig; </del> <ins> ${hostOpts.hostName} ${concatStringsSep " " hostOpts.serverAliases} { bind ${concatStringsSep " " hostOpts.listenAddresses} ${optionalString (hostOpts.useACMEHost != null) "tls ${sslCertDir}/cert.pem ${sslCertDir}/key.pem"} log { ${hostOpts.logFormat} } ${hostOpts.extraConfig} } ''; configFile = let Caddyfile = pkgs.writeText "Caddyfile" '' { ${optionalString (cfg.email != null) "email ${cfg.email}"} ${optionalString (cfg.acmeCA != null) "acme_ca ${cfg.acmeCA}"} log { ${cfg.logFormat} } } ${cfg.extraConfig} ''; Caddyfile-formatted = pkgs.runCommand "Caddyfile-formatted" { nativeBuildInputs = [ cfg.package ]; } '' ${cfg.package}/bin/caddy fmt ${Caddyfile} > $out ''; in if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform then Caddyfile-formatted else Caddyfile; </ins> in { imports = [ (mkRemovedOptionModule [ "services" "caddy" "agree" ] "this option is no longer necessary for Caddy 2") <ins> (mkRenamedOptionModule [ "services" "caddy" "ca" ] [ "services" "caddy" "acmeCA" ]) (mkRenamedOptionModule [ "services" "caddy" "config" ] [ "services" "caddy" "extraConfig" ]) </ins> ]; <ins> # interface </ins> options.services.caddy = { enable = mkEnableOption "Caddy web server"; <del> config = mkOption { default = ""; example = '' example.com { encode gzip log root /srv/http } </del> <ins> user = mkOption { default = "caddy"; type = types.str; description = '' User account under which caddy runs. <note><para> If left as the default value this user will automatically be created on system activation, otherwise you are responsible for ensuring the user exists before the Caddy service starts. </para></note> </ins> ''; <del> type = types.lines; </del> <ins> }; group = mkOption { default = "caddy"; type = types.str; </ins> description = '' <del> Verbatim Caddyfile to use. Caddy v2 supports multiple config formats via adapters (see <option>services.caddy.adapter</option>). </del> <ins> Group account under which caddy runs. <note><para> If left as the default value this user will automatically be created on system activation, otherwise you are responsible for ensuring the user exists before the Caddy service starts. </para></note> </ins> ''; }; <del> virtualHosts = mkOption { type = types.attrsOf (types.submodule (import ./vhost-options.nix { inherit config lib; })); default = { }; example = literalExpression '' { "hydra.example.com" = { serverAliases = [ "www.hydra.example.com" ]; extraConfig = '''''' encode gzip log root /srv/http ''''''; }; }; </del> <ins> package = mkOption { default = pkgs.caddy; defaultText = literalExpression "pkgs.caddy"; type = types.package; description = '' Caddy package to use. </ins> ''; <del> description = "Declarative vhost config"; </del> }; <ins> dataDir = mkOption { type = types.path; default = "/var/lib/caddy"; description = '' The data directory for caddy. </ins> <del> user = mkOption { default = "caddy"; type = types.str; description = "User account under which caddy runs."; </del> <ins> <note> <para> If left as the default value this directory will automatically be created before the Caddy server starts, otherwise you are responsible for ensuring the directory exists with appropriate ownership and permissions. </para> <para> Caddy v2 replaced <literal>CADDYPATH</literal> with XDG directories. See <link xlink:href="https://caddyserver.com/docs/conventions#file-locations"/>. </para> </note> ''; </ins> }; <del> group = mkOption { default = "caddy"; type = types.str; description = "Group account under which caddy runs."; </del> <ins> logDir = mkOption { type = types.path; default = "/var/log/caddy"; description = '' Directory for storing Caddy access logs. <note><para> If left as the default value this directory will automatically be created before the Caddy server starts, otherwise the sysadmin is responsible for ensuring the directory exists with appropriate ownership and permissions. </para></note> ''; }; logFormat = mkOption { type = types.lines; default = '' level ERROR ''; example = literalExpression '' mkForce "level INFO"; ''; description = '' Configuration for the default logger. See <link xlink:href="https://caddyserver.com/docs/caddyfile/options#log"/> for details. ''; }; configFile = mkOption { type = types.path; default = configFile; defaultText = "A Caddyfile automatically generated by values from services.caddy.*"; example = literalExpression '' pkgs.writeText "Caddyfile" ''' example.com root * /var/www/wordpress php_fastcgi unix//run/php/php-version-fpm.sock file_server '''; ''; description = '' Override the configuration file used by Caddy. By default, NixOS generates one automatically. ''; </ins> }; adapter = mkOption {