diff --git a/configuration/services/conduit.nix b/configuration/services/conduit.nix
index cae2510..3fcadeb 100644
--- a/configuration/services/conduit.nix
+++ b/configuration/services/conduit.nix
@@ -212,9 +212,9 @@ in {
     ];
 
     forceSSL = true;
+    enableHSTS = true;
     extraConfig = ''
       merge_slashes off;
-      access_log /var/log/nginx/${domain}/access.log upstream_time;
     '';
 
     locations = {
diff --git a/configuration/services/foundryvtt.nix b/configuration/services/foundryvtt.nix
index 069f336..51b0212 100644
--- a/configuration/services/foundryvtt.nix
+++ b/configuration/services/foundryvtt.nix
@@ -25,10 +25,7 @@ in {
   in {
     forceSSL = true;
     enableACME = true;
-    extraConfig = ''
-      add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-      access_log /var/log/nginx/${domain}/access.log upstream_time;
-    '';
+    enableHSTS = true;
 
     locations."/" = {
       proxyWebsockets = true;
diff --git a/configuration/services/gitea.nix b/configuration/services/gitea.nix
index 41b8583..ffd21dc 100644
--- a/configuration/services/gitea.nix
+++ b/configuration/services/gitea.nix
@@ -42,10 +42,7 @@ in {
   in {
     forceSSL = true;
     enableACME = true;
-    extraConfig = ''
-      add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-      access_log /var/log/nginx/${domain}/access.log upstream_time;
-    '';
+    enableHSTS = true;
 
     locations."/".proxyPass = "http://${httpAddress}:${toString httpPort}";
     locations."/metrics" = {
diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix
index 8538dc7..75b9777 100644
--- a/configuration/services/metrics/grafana.nix
+++ b/configuration/services/metrics/grafana.nix
@@ -39,10 +39,7 @@ in {
   services.nginx.virtualHosts."${domain}" = {
     forceSSL = true;
     enableACME = true;
-    extraConfig = ''
-      add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-      access_log /var/log/nginx/${domain}/access.log upstream_time;
-    '';
+    enableHSTS = true;
     locations."/".proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
   };
 }
diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 3ba967a..73e075e 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -46,9 +46,7 @@ in {
   services.nginx.virtualHosts."${hostName}" = {
     forceSSL = true;
     enableACME = true;
-    extraConfig = ''
-      access_log /var/log/nginx/${hostName}/access.log upstream_time;
-    '';
+    # The upstream module already adds HSTS
   };
 
   # Block repeated failed login attempts
diff --git a/configuration/services/webserver.nix b/configuration/services/webserver.nix
index 085b1f7..defcae1 100644
--- a/configuration/services/webserver.nix
+++ b/configuration/services/webserver.nix
@@ -17,10 +17,7 @@ in {
 
     forceSSL = true;
     enableACME = true;
-    extraConfig = ''
-      add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-      access_log /var/log/nginx/${domain}/access.log upstream_time;
-    '';
+    enableHSTS = true;
 
     locations."/".proxyPass = "http://${addr}:${toString port}";
   };
diff --git a/modules/default.nix b/modules/default.nix
index de1c7c2..9341a5a 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -1,23 +1,5 @@
 {
-  pkgs,
-  config,
-  lib,
-  ...
-}: {
-  options.services.nginx.domain = lib.mkOption {
-    type = lib.types.str;
-    description = "The base domain name to append to virtual domain names";
-  };
-
-  config = {
-    # Don't attempt to run acme if the domain name is not tlater.net
-    systemd.services = let
-      confirm = ''[[ "tlater.net" = ${config.services.nginx.domain} ]]'';
-    in
-      lib.mapAttrs' (cert: _:
-        lib.nameValuePair "acme-${cert}" {
-          serviceConfig.ExecCondition = ''${pkgs.runtimeShell} -c '${confirm}' '';
-        })
-      config.security.acme.certs;
-  };
+  imports = [
+    ./nginxExtensions.nix
+  ];
 }
diff --git a/modules/nginxExtensions.nix b/modules/nginxExtensions.nix
new file mode 100644
index 0000000..9fe489a
--- /dev/null
+++ b/modules/nginxExtensions.nix
@@ -0,0 +1,59 @@
+{
+  config,
+  pkgs,
+  lib,
+  ...
+}: {
+  options = {
+    services.nginx.domain = lib.mkOption {
+      type = lib.types.str;
+      description = "The base domain name to append to virtual domain names";
+    };
+
+    services.nginx.virtualHosts = let
+      extraVirtualHostOptions = {
+        name,
+        config,
+        ...
+      }: {
+        options = {
+          enableHSTS = lib.mkEnableOption "Enable HSTS";
+
+          addAccessLog = lib.mkOption {
+            type = lib.types.bool;
+            default = true;
+            description = ''
+              Add special logging to `/var/log/nginx/''${serverName}`
+            '';
+          };
+        };
+
+        config = {
+          extraConfig = lib.concatStringsSep "\n" [
+            (lib.optionalString config.enableHSTS ''
+              add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
+            '')
+            (lib.optionalString config.addAccessLog ''
+              access_log /var/log/nginx/${name}/access.log upstream_time;
+            '')
+          ];
+        };
+      };
+    in
+      lib.mkOption {
+        type = lib.types.attrsOf (lib.types.submodule extraVirtualHostOptions);
+      };
+  };
+
+  config = {
+    # Don't attempt to run acme if the domain name is not tlater.net
+    systemd.services = let
+      confirm = ''[[ "tlater.net" = ${config.services.nginx.domain} ]]'';
+    in
+      lib.mapAttrs' (cert: _:
+        lib.nameValuePair "acme-${cert}" {
+          serviceConfig.ExecCondition = ''${pkgs.runtimeShell} -c '${confirm}' '';
+        })
+      config.security.acme.certs;
+  };
+}