summary refs log tree commit diff
path: root/nixos/modules/services/web-servers/caddy.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/web-servers/caddy.nix')
-rw-r--r--nixos/modules/services/web-servers/caddy.nix124
1 files changed, 92 insertions, 32 deletions
diff --git a/nixos/modules/services/web-servers/caddy.nix b/nixos/modules/services/web-servers/caddy.nix
index 0e6e10a5f47..955b9756406 100644
--- a/nixos/modules/services/web-servers/caddy.nix
+++ b/nixos/modules/services/web-servers/caddy.nix
@@ -5,7 +5,45 @@ with lib;
 let
   cfg = config.services.caddy;
   configFile = pkgs.writeText "Caddyfile" cfg.config;
+
+  tlsConfig = {
+    apps.tls.automation.policies = [{
+      issuer = {
+        inherit (cfg) ca email;
+        module = "acme";
+      };
+    }];
+  };
+
+  adaptedConfig = pkgs.runCommand "caddy-config-adapted.json" { } ''
+    ${cfg.package}/bin/caddy adapt \
+      --config ${configFile} --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 =
+    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
+  '';
 in {
+  imports = [
+    (mkRemovedOptionModule [ "services" "caddy" "agree" ] "this option is no longer necessary for Caddy 2")
+  ];
+
   options.services.caddy = {
     enable = mkEnableOption "Caddy web server";
 
@@ -13,15 +51,38 @@ in {
       default = "";
       example = ''
         example.com {
-        gzip
-        minify
-        log syslog
-
-        root /srv/http
+          encode gzip
+          log
+          root /srv/http
         }
       '';
       type = types.lines;
-      description = "Verbatim Caddyfile to use";
+      description = ''
+        Verbatim Caddyfile to use.
+        Caddy v2 supports multiple config formats via adapters (see <option>services.caddy.adapter</option>).
+      '';
+    };
+
+    user = mkOption {
+      default = "caddy";
+      type = types.str;
+      description = "User account under which caddy runs.";
+    };
+
+    group = mkOption {
+      default = "caddy";
+      type = types.str;
+      description = "Group account under which caddy runs.";
+    };
+
+    adapter = mkOption {
+      default = "caddyfile";
+      example = "nginx";
+      type = types.str;
+      description = ''
+        Name of the config adapter to use.
+        See https://caddyserver.com/docs/config-adapters for the full list.
+      '';
     };
 
     ca = mkOption {
@@ -37,12 +98,6 @@ in {
       description = "Email address (for Let's Encrypt certificate)";
     };
 
-    agree = mkOption {
-      default = false;
-      type = types.bool;
-      description = "Agree to Let's Encrypt Subscriber Agreement";
-    };
-
     dataDir = mkOption {
       default = "/var/lib/caddy";
       type = types.path;
@@ -50,39 +105,39 @@ in {
         The data directory, for storing certificates. Before 17.09, this
         would create a .caddy directory. With 17.09 the contents of the
         .caddy directory are in the specified data directory instead.
+
+        Caddy v2 replaced CADDYPATH with XDG directories.
+        See https://caddyserver.com/docs/conventions#file-locations.
       '';
     };
 
     package = mkOption {
       default = pkgs.caddy;
       defaultText = "pkgs.caddy";
+      example = "pkgs.caddy";
       type = types.package;
-      description = "Caddy package to use.";
+      description = ''
+        Caddy package to use.
+      '';
     };
   };
 
   config = mkIf cfg.enable {
     systemd.services.caddy = {
       description = "Caddy web server";
-      # upstream unit: https://github.com/caddyserver/caddy/blob/master/dist/init/linux-systemd/caddy.service
+      # upstream unit: https://github.com/caddyserver/dist/blob/master/init/caddy.service
       after = [ "network-online.target" ];
       wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service
       wantedBy = [ "multi-user.target" ];
-      environment = mkIf (versionAtLeast config.system.stateVersion "17.09")
-        { CADDYPATH = cfg.dataDir; };
+      startLimitIntervalSec = 14400;
+      startLimitBurst = 10;
       serviceConfig = {
-        ExecStart = ''
-          ${cfg.package}/bin/caddy -log stdout -log-timestamps=false \
-            -root=/var/tmp -conf=${configFile} \
-            -ca=${cfg.ca} -email=${cfg.email} ${optionalString cfg.agree "-agree"}
-        '';
-        ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
+        ExecStart = "${cfg.package}/bin/caddy run --config ${configJSON}";
+        ExecReload = "${cfg.package}/bin/caddy reload --config ${configJSON}";
         Type = "simple";
-        User = "caddy";
-        Group = "caddy";
+        User = cfg.user;
+        Group = cfg.group;
         Restart = "on-abnormal";
-        StartLimitIntervalSec = 14400;
-        StartLimitBurst = 10;
         AmbientCapabilities = "cap_net_bind_service";
         CapabilityBoundingSet = "cap_net_bind_service";
         NoNewPrivileges = true;
@@ -99,13 +154,18 @@ in {
       };
     };
 
-    users.users.caddy = {
-      group = "caddy";
-      uid = config.ids.uids.caddy;
-      home = cfg.dataDir;
-      createHome = true;
+    users.users = optionalAttrs (cfg.user == "caddy") {
+      caddy = {
+        group = cfg.group;
+        uid = config.ids.uids.caddy;
+        home = cfg.dataDir;
+        createHome = true;
+      };
+    };
+
+    users.groups = optionalAttrs (cfg.group == "caddy") {
+      caddy.gid = config.ids.gids.caddy;
     };
 
-    users.groups.caddy.gid = config.ids.uids.caddy;
   };
 }