Refactor caddy module, add cloudflare to caddy, remove scalpel antipatterns
diff --git a/modules/caddy.nix b/modules/caddy.nix
index c152989..51efde5 100644
--- a/modules/caddy.nix
+++ b/modules/caddy.nix
@@ -1,4 +1,4 @@
-{ config, pkgs, lib, ... }: {
+{ base, config, pkgs, lib, ... }: lib.recursiveUpdate {
   services.caddy.enable = true;
   services.caddy.configFile = lib.pipe ./caddy/caddyfile.nix [
     import
@@ -9,4 +9,34 @@
   services.caddy.package = pkgs.callPackage ../packages/caddy.nix { };
   services.caddy.user = "root";
   systemd.services.caddy.serviceConfig.ProtectHome = lib.mkForce false;
-}
+
+  sops.secrets.cloudflare_token = {
+    mode = "0600";
+    owner = config.users.users.root.name;
+    group = config.users.users.nobody.group;
+    sopsFile = ../secrets/caddy.json;
+    format = "json";
+  };
+} (
+  let
+    isDerived = base != null;
+  in
+  if isDerived
+  then
+    let
+      caddy_json = base.config.services.caddy.configFile;
+    in
+    {
+      scalpel.trafos."caddy.json" = {
+        source = toString caddy_json;
+        matchers."cloudflare_token".secret =
+          config.sops.secrets.cloudflare_token.path;
+        owner = config.users.users.root.name;
+        group = config.users.users.nobody.group;
+        mode = "0400";
+      };
+
+      services.caddy.configFile = lib.mkForce config.scalpel.trafos."caddy.json".destination;
+    }
+  else { }
+)
diff --git a/modules/caddy/caddyfile.nix b/modules/caddy/caddyfile.nix
index a7deb60..8ebf226 100644
--- a/modules/caddy/caddyfile.nix
+++ b/modules/caddy/caddyfile.nix
@@ -75,250 +75,255 @@
 in
 { pkgs, lib }: {
   apps = {
-    http = {
-      servers = {
-        srv0 = {
-          listen = [ ":443" ];
-          routes = [
-            (HTTPReverseProxyRoute [ "signup.hopescaramels.com" ] [ "192.168.0.4:3035" ])
-            (HTTPReverseProxyRoute [ "homebridge.coded.codes" ] [ "localhost:8581" ])
-            {
-              handle = [
-                {
-                  handler = "subroute";
-                  routes = [
-                    {
-                      handle = [
-                        {
-                          error = "You can't access admin routes from outside the server. Please use SSH tunneling, cURL on the host or similar";
-                          handler = "error";
-                          status_code = "403";
-                        }
-                      ];
-                      match = [{ path = [ "/_dendrite/admin/*" "/_synapse/admin/*" ]; }];
-                      terminal = true;
-                    }
-                    {
-                      handle = [
-                        {
-                          handler = "reverse_proxy";
-                          transport = { protocol = "http"; };
-                          upstreams = [{ dial = "localhost:4527"; }];
-                        }
-                      ];
-                    }
-                  ];
-                }
-              ];
-              match = [{ host = [ "matrix-backend.coded.codes" ]; }];
-              terminal = true;
-            }
-            (HTTPReverseProxyRoute
-              [
-                "mail.coded.codes"
-                "mail.clicks.codes"
-                "mail.hopescaramels.com"
-              ]
-              [ "localhost:1080" ]
-            )
-            (HTTPReverseProxyRoute [ "logs.clicks.codes" ] [ "localhost:9052" ])
-            (HTTPRedirectRoute
-              [
-                "hopescaramels.com"
-                "www.hopescaramels.com"
-              ]
-              "https://etsy.com/shop/HopesCaramels"
-            )
-            # (HTTPReverseProxyRoute [ "omv.coded.codes" ] [ "localhost:6773" ])
-            # (HTTPReverseProxyRoute [ "jellyfin.coded.codes" ] [ "localhost:8096" ])
-            (HTTPReverseProxyRoute [ "codedpc.coded.codes" ] [ "192.168.0.2:3389" ])
-            (HTTPReverseProxyRoute [ "testing.coded.codes" ] [ "192.168.0.2:3030" ])
-            (HTTPReverseProxyRoute [ "kavita.clicks.codes" ] [ "localhost:5000" ])
-            {
-              handle = [
-                {
-                  handler = "subroute";
-                  routes = [
-                    {
-                      handle = [
-                        {
-                          handler = "subroute";
-                          routes = [
-                            {
-                              handle = [
-                                {
-                                  handler = "rewrite";
-                                  strip_path_prefix = "/nucleus";
-                                }
-                              ];
-                            }
-                            {
-                              handle = [
-                                {
-                                  handler = "reverse_proxy";
-                                  upstreams = [{ dial = "127.0.0.1:10000"; }];
-                                }
-                              ];
-                            }
-                          ];
-                        }
-                      ];
-                      match = [{ path = [ "/nucleus/*" ]; }];
-                    }
-                    {
-                      handle = [
-                        {
-                          handler = "error";
-                          error = "This API route does not exist";
-                          status_code = 404;
-                        }
-                      ];
-                    }
-                  ];
-                }
-              ];
-              match = [{ host = [ "api.clicks.codes" ]; }];
-              terminal = true;
-            }
-            {
-              handle = [
-                {
-                  handler = "subroute";
-                  routes = [
-                    {
-                      handle = [
-                        {
-                          handler = "subroute";
-                          routes = [
-                            {
-                              handle = [
-                                {
-                                  handler = "rewrite";
-                                  strip_path_prefix = "/nucleus";
-                                }
-                              ];
-                            }
-                            {
-                              handle = [
-                                {
-                                  handler = "reverse_proxy";
-                                  upstreams = [{ dial = "192.168.0.2:10000"; }];
-                                }
-                              ];
-                            }
-                          ];
-                        }
-                      ];
-                      match = [{ path = [ "/nucleus/*" ]; }];
-                    }
-                    {
-                      handle = [
-                        {
-                          handler = "error";
-                          error = "This API route does not exist";
-                          status_code = 404;
-                        }
-                      ];
-                    }
-                  ];
-                }
-              ];
-              match = [{ host = [ "api.coded.codes" ]; }];
-              terminal = true;
-            }
-            (HTTPRedirectRoute
-              [
-                "www.clicks.codes"
-              ]
-              "https://clicks.codes{http.request.uri}"
-            )
-            (HTTPReverseProxyRoute [ "clicks.codes" ] [ "127.0.0.1:3000" ])
-            {
-              handle = [
-                {
-                  handler = "subroute";
-                  routes = [
-                    {
-                      handle = [
-                        {
-                          handler = "static_response";
-                          status_code = 200;
-                          body = builtins.readFile ./coded.codes/.well-known/matrix;
-                          headers = { Access-Control-Allow-Origin = [ "*" ]; };
-                        }
-                      ];
-                      match = [{
-                        path = [
-                          "/.well-known/matrix/server"
-                          "/.well-known/matrix/client"
-                        ];
-                      }];
-                      terminal = true;
-                    }
-                    {
-                      handle = [
-                        {
-                          handler = "static_response";
-                          headers = { Location = [ "https://clicks.codes{http.request.uri}" ]; };
-                          status_code = 302;
-                        }
-                      ];
-                    }
-                  ];
-                }
-              ];
-              match = [{ host = [ "coded.codes" ]; }];
-              terminal = true;
-            }
-            (HTTPFileServerRoute [ "matrix.coded.codes" ] (
-              pkgs.element-web.override {
-                conf = {
-                  default_server_config = lib.pipe ./coded.codes/.well-known/matrix [
-                    builtins.readFile
-                    builtins.fromJSON
-                  ];
-                };
+    http.servers = {
+      srv0 = {
+        listen = [ ":443" ];
+        routes = [
+          (HTTPReverseProxyRoute [ "signup.hopescaramels.com" ] [ "192.168.0.4:3035" ])
+          (HTTPReverseProxyRoute [ "homebridge.coded.codes" ] [ "localhost:8581" ])
+          {
+            handle = [
+              {
+                handler = "subroute";
+                routes = [
+                  {
+                    handle = [
+                      {
+                        error = "You can't access admin routes from outside the server. Please use SSH tunneling, cURL on the host or similar";
+                        handler = "error";
+                        status_code = "403";
+                      }
+                    ];
+                    match = [{ path = [ "/_dendrite/admin/*" "/_synapse/admin/*" ]; }];
+                    terminal = true;
+                  }
+                  {
+                    handle = [
+                      {
+                        handler = "reverse_proxy";
+                        transport = { protocol = "http"; };
+                        upstreams = [{ dial = "localhost:4527"; }];
+                      }
+                    ];
+                  }
+                ];
               }
-            ))
-          ];
-        };
-        srv1 = {
-          listen = [ ":80" ];
-          routes = [
-            (HTTPReverseProxyRoute
-              [
-                "mail.clicks.codes"
-                "mail.coded.codes"
-                "mail.hopescaramels.com"
-                "autoconfig.coded.codes"
-                "autoconfig.clicks.codes"
-                "autoconfig.hopescaramels.com"
-                "imap.coded.codes"
-                "imap.clicks.codes"
-                "imap.hopescaramels.com"
-                "pop.coded.codes"
-                "pop.clicks.codes"
-                "pop.hopescaramels.com"
-                "smtp.coded.codes"
-                "smtp.clicks.codes"
-                "smtp.hopescaramels.com"
-              ]
-              [ "localhost:1080" ]
-            )
-          ];
-        };
+            ];
+            match = [{ host = [ "matrix-backend.coded.codes" ]; }];
+            terminal = true;
+          }
+          (HTTPReverseProxyRoute
+            [
+              "mail.coded.codes"
+              "mail.clicks.codes"
+              "mail.hopescaramels.com"
+            ]
+            [ "localhost:1080" ]
+          )
+          (HTTPReverseProxyRoute [ "logs.clicks.codes" ] [ "localhost:9052" ])
+          (HTTPRedirectRoute
+            [
+              "hopescaramels.com"
+              "www.hopescaramels.com"
+            ]
+            "https://etsy.com/shop/HopesCaramels"
+          )
+          # (HTTPReverseProxyRoute [ "omv.coded.codes" ] [ "localhost:6773" ])
+          # (HTTPReverseProxyRoute [ "jellyfin.coded.codes" ] [ "localhost:8096" ])
+          (HTTPReverseProxyRoute [ "codedpc.coded.codes" ] [ "192.168.0.2:3389" ])
+          (HTTPReverseProxyRoute [ "testing.coded.codes" ] [ "192.168.0.2:3030" ])
+          (HTTPReverseProxyRoute [ "kavita.coded.codes" ] [ "localhost:5000" ])
+          {
+            handle = [
+              {
+                handler = "subroute";
+                routes = [
+                  {
+                    handle = [
+                      {
+                        handler = "subroute";
+                        routes = [
+                          {
+                            handle = [
+                              {
+                                handler = "rewrite";
+                                strip_path_prefix = "/nucleus";
+                              }
+                            ];
+                          }
+                          {
+                            handle = [
+                              {
+                                handler = "reverse_proxy";
+                                upstreams = [{ dial = "127.0.0.1:10000"; }];
+                              }
+                            ];
+                          }
+                        ];
+                      }
+                    ];
+                    match = [{ path = [ "/nucleus/*" ]; }];
+                  }
+                  {
+                    handle = [
+                      {
+                        handler = "error";
+                        error = "This API route does not exist";
+                        status_code = 404;
+                      }
+                    ];
+                  }
+                ];
+              }
+            ];
+            match = [{ host = [ "api.clicks.codes" ]; }];
+            terminal = true;
+          }
+          {
+            handle = [
+              {
+                handler = "subroute";
+                routes = [
+                  {
+                    handle = [
+                      {
+                        handler = "subroute";
+                        routes = [
+                          {
+                            handle = [
+                              {
+                                handler = "rewrite";
+                                strip_path_prefix = "/nucleus";
+                              }
+                            ];
+                          }
+                          {
+                            handle = [
+                              {
+                                handler = "reverse_proxy";
+                                upstreams = [{ dial = "192.168.0.2:10000"; }];
+                              }
+                            ];
+                          }
+                        ];
+                      }
+                    ];
+                    match = [{ path = [ "/nucleus/*" ]; }];
+                  }
+                  {
+                    handle = [
+                      {
+                        handler = "error";
+                        error = "This API route does not exist";
+                        status_code = 404;
+                      }
+                    ];
+                  }
+                ];
+              }
+            ];
+            match = [{ host = [ "api.coded.codes" ]; }];
+            terminal = true;
+          }
+          (HTTPRedirectRoute
+            [
+              "www.clicks.codes"
+            ]
+            "https://clicks.codes{http.request.uri}"
+          )
+          (HTTPReverseProxyRoute [ "clicks.codes" ] [ "127.0.0.1:3000" ])
+          {
+            handle = [
+              {
+                handler = "subroute";
+                routes = [
+                  {
+                    handle = [
+                      {
+                        handler = "static_response";
+                        status_code = 200;
+                        body = builtins.readFile ./coded.codes/.well-known/matrix;
+                        headers = { Access-Control-Allow-Origin = [ "*" ]; };
+                      }
+                    ];
+                    match = [{
+                      path = [
+                        "/.well-known/matrix/server"
+                        "/.well-known/matrix/client"
+                      ];
+                    }];
+                    terminal = true;
+                  }
+                  {
+                    handle = [
+                      {
+                        handler = "static_response";
+                        headers = { Location = [ "https://clicks.codes{http.request.uri}" ]; };
+                        status_code = 302;
+                      }
+                    ];
+                  }
+                ];
+              }
+            ];
+            match = [{ host = [ "coded.codes" ]; }];
+            terminal = true;
+          }
+          (HTTPFileServerRoute [ "matrix.coded.codes" ] (
+            pkgs.element-web.override {
+              conf = {
+                default_server_config = lib.pipe ./coded.codes/.well-known/matrix [
+                  builtins.readFile
+                  builtins.fromJSON
+                ];
+              };
+            }
+          ))
+        ];
+      };
+      srv1 = {
+        listen = [ ":80" ];
+        routes = [
+          (HTTPReverseProxyRoute
+            [
+              "mail.clicks.codes"
+              "mail.coded.codes"
+              "mail.hopescaramels.com"
+              "autoconfig.coded.codes"
+              "autoconfig.clicks.codes"
+              "autoconfig.hopescaramels.com"
+              "imap.coded.codes"
+              "imap.clicks.codes"
+              "imap.hopescaramels.com"
+              "pop.coded.codes"
+              "pop.clicks.codes"
+              "pop.hopescaramels.com"
+              "smtp.coded.codes"
+              "smtp.clicks.codes"
+              "smtp.hopescaramels.com"
+            ]
+            [ "localhost:1080" ]
+          )
+        ];
       };
     };
-    layer4 = {
-      servers = {
-        imap-143 = (TCPReverseProxyRoute [ 143 ] [ "localhost:1143" ]);
-        imap-993 = (TCPReverseProxyRoute [ 993 ] [ "localhost:1993" ]);
-        pop-110 = (TCPReverseProxyRoute [ 110 ] [ "localhost:1110" ]);
-        pop-995 = (TCPReverseProxyRoute [ 995 ] [ "localhost:1995" ]);
-        smtp-25 = (TCPReverseProxyRoute [ 25 ] [ "localhost:1025" ]);
-        smtp-465 = (TCPReverseProxyRoute [ 465 ] [ "localhost:1465" ]);
-        smtp-587 = (TCPReverseProxyRoute [ 587 ] [ "localhost:1587" ]);
-      };
+    layer4.servers = {
+      imap-143 = (TCPReverseProxyRoute [ 143 ] [ "localhost:1143" ]);
+      imap-993 = (TCPReverseProxyRoute [ 993 ] [ "localhost:1993" ]);
+      pop-110 = (TCPReverseProxyRoute [ 110 ] [ "localhost:1110" ]);
+      pop-995 = (TCPReverseProxyRoute [ 995 ] [ "localhost:1995" ]);
+      smtp-25 = (TCPReverseProxyRoute [ 25 ] [ "localhost:1025" ]);
+      smtp-465 = (TCPReverseProxyRoute [ 465 ] [ "localhost:1465" ]);
+      smtp-587 = (TCPReverseProxyRoute [ 587 ] [ "localhost:1587" ]);
     };
+    tls.automation.policies = [{
+      issuers = [{
+        module = "acme";
+        challenges.dns.provider = {
+          name = "cloudflare";
+          api_token = "!!cloudflare_token!!";
+        };
+      }];
+    }];
   };
 }
diff --git a/modules/matrix.nix b/modules/matrix.nix
index b83e3f4..4be396e 100644
--- a/modules/matrix.nix
+++ b/modules/matrix.nix
@@ -1,4 +1,5 @@
 { base, config, lib, pkgs, ... }:
+lib.recursiveUpdate
 {
   services.matrix-synapse = {
     enable = true;
@@ -46,7 +47,7 @@
       path = config.services.matrix-synapse.settings.signing_key_path;
     };
   };
-} // (
+} (
   let
     isDerived = base != null;
   in