summary refs log tree commit diff
path: root/fleet/modules/acme.nix
diff options
context:
space:
mode:
authorV <v@unfathomable.blue>2021-06-09 15:43:16 +0200
committerV <v@unfathomable.blue>2021-08-17 03:09:34 +0200
commitec0965e2672899d25a5a3a8c072de3ea734076a2 (patch)
treeddf53e6cc5ae47fa1a925f7a7d6414ba03718a84 /fleet/modules/acme.nix
parentdb7c54f92f386a94db8af7a12626d2657b4dd640 (diff)
fleet: init
Co-authored-by: edef <edef@unfathomable.blue>
Change-Id: I36d2c4cca542ed91630b1b832f3c7a7b97b33c65
Diffstat (limited to 'fleet/modules/acme.nix')
-rw-r--r--fleet/modules/acme.nix55
1 files changed, 55 insertions, 0 deletions
diff --git a/fleet/modules/acme.nix b/fleet/modules/acme.nix
new file mode 100644
index 0000000..f06ac4e
--- /dev/null
+++ b/fleet/modules/acme.nix
@@ -0,0 +1,55 @@
+# SPDX-FileCopyrightText: V <v@unfathomable.blue>
+# SPDX-License-Identifier: OSL-3.0
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  webroot = "/var/lib/acme/challenges";
+in {
+  options = {
+    # We want to set webroot on every single certificate, but trying
+    # to do this by using genAttrs on the certificate attribute names
+    # produces infinite recursion. To get around this, we're instead
+    # setting webroot from within the certificate submodule itself.
+    #
+    # The fact that this is even possible is because submodules are
+    # just like normal modules, insofar that they can have both an
+    # 'options' and a 'config' attribute, both of which are scoped
+    # to the submodule itself. Additionally, normal merging logic
+    # is applied to module options, meaning we can just define the
+    # certificates option again and that'll be handled correctly.
+    #
+    # TODO(V): Add a global security.acme.webroot option to the upstream module
+    security.acme.certs = mkOption {
+      type = types.attrsOf (types.submodule {
+        inherit webroot;
+      });
+    };
+  };
+
+  config = {
+    security.acme = {
+      acceptTerms = true;
+      email = "acme@unfathomable.blue";
+    };
+
+    services.caddy.config = ''
+      ${concatStringsSep ", " (unique (mapAttrsToList (_: cert: "http://${cert.domain}") config.security.acme.certs))} {
+        import all
+
+        route {
+          # TODO(V): make use of the 'file' matcher, so this is guaranteed to never 404?
+          file_server /.well-known/acme-challenge/* {
+            root ${webroot}
+          }
+
+          # Manually handling http:// disables Caddy's automatic HTTPS
+          # redirects for the domain, so let's do that ourselves
+          redir https://{host}{uri} 308
+        }
+      }
+    '';
+  };
+}