]> git.immae.eu Git - perso/Immae/Config/Nix.git/blobdiff - modules/websites/default.nix
Upgrade syden peertube to flake
[perso/Immae/Config/Nix.git] / modules / websites / default.nix
index 767a7b2324a1bf45acec546b23c5544e974f76a5..0a78c134ae56211dd4bf82c20f7dd91e7a6c0b4f 100644 (file)
@@ -1,4 +1,4 @@
-{ lib, config, ... }: with lib;
+{ lib, config, pkgs, ... }: with lib;
 let
   cfg = config.services.websites;
 in
@@ -38,7 +38,7 @@ in
             description = "Name of the httpd instance to assign this type to";
           };
           ips = mkOption {
-            type = listOf string;
+            type = listOf str;
             default = [];
             description = "ips to listen to";
           };
@@ -59,7 +59,7 @@ in
               options = {
                 enable = mkEnableOption "Add default no-ssl vhost for this instance";
                 host = mkOption {
-                  type = string;
+                  type = str;
                   description = "The hostname to use for this vhost";
                 };
                 root = mkOption {
@@ -68,7 +68,7 @@ in
                   description = "The root folder to serve";
                 };
                 indexFile = mkOption {
-                  type = string;
+                  type = str;
                   default = "index.html";
                   description = "The index file to show.";
                 };
@@ -79,9 +79,17 @@ in
             description = "The fallback vhost that will be defined as first vhost in Apache";
             type = submodule {
               options = {
-                certName = mkOption { type = string; };
-                hosts    = mkOption { type = listOf string; };
+                certName = mkOption { type = str; };
+                hosts    = mkOption { type = listOf str; };
                 root     = mkOption { type = nullOr path; };
+                forceSSL = mkOption {
+                  type = bool;
+                  default = true;
+                  description = ''
+                    Automatically create a corresponding non-ssl vhost
+                    that will only redirect to the ssl version
+                  '';
+                };
                 extraConfig = mkOption { type = listOf lines; default = []; };
               };
             };
@@ -91,7 +99,7 @@ in
             description = "List of no ssl vhosts to define for Apache";
             type = attrsOf (submodule {
               options = {
-                hosts    = mkOption { type = listOf string; };
+                hosts    = mkOption { type = listOf str; };
                 root     = mkOption { type = nullOr path; };
                 extraConfig = mkOption { type = listOf lines; default = []; };
               };
@@ -102,25 +110,33 @@ in
             description = "List of vhosts to define for Apache";
             type = attrsOf (submodule {
               options = {
-                certName = mkOption { type = string; };
+                certName = mkOption { type = str; };
                 addToCerts = mkOption {
                   type = bool;
                   default = false;
                   description = "Use these to certificates. Is ignored (considered true) if certMainHost is not null";
                 };
                 certMainHost = mkOption {
-                  type = nullOr string;
+                  type = nullOr str;
                   description = "Use that host as 'main host' for acme certs";
                   default = null;
                 };
-                hosts    = mkOption { type = listOf string; };
+                hosts    = mkOption { type = listOf str; };
                 root     = mkOption { type = nullOr path; };
+                forceSSL = mkOption {
+                  type = bool;
+                  default = true;
+                  description = ''
+                    Automatically create a corresponding non-ssl vhost
+                    that will only redirect to the ssl version
+                  '';
+                };
                 extraConfig = mkOption { type = listOf lines; default = []; };
               };
             });
           };
           watchPaths = mkOption {
-            type = listOf string;
+            type = listOf str;
             default = [];
             description = ''
               Paths to watch that should trigger a reload of httpd
@@ -143,26 +159,9 @@ in
   };
 
   config.services.httpd = let
-    redirectVhost = ips: { # Should go last, catchall http -> https redirect
-      listen = map (ip: { inherit ip; port = 80; }) ips;
-      hostName = "redirectSSL";
-      serverAliases = [ "*" ];
-      enableSSL = false;
-      logFormat = "combinedVhost";
-      documentRoot = "/var/lib/acme/acme-challenge";
-      extraConfig = ''
-        RewriteEngine on
-        RewriteCond "%{REQUEST_URI}"   "!^/\.well-known"
-        RewriteRule ^(.+)              https://%{HTTP_HOST}$1  [R=301]
-        # To redirect in specific "VirtualHost *:80", do
-        #   RedirectMatch 301 ^/((?!\.well-known.*$).*)$ https://host/$1
-        # rather than rewrite
-      '';
-    };
     nosslVhost = ips: cfg: {
       listen = map (ip: { inherit ip; port = 80; }) ips;
       hostName = cfg.host;
-      enableSSL = false;
       logFormat = "combinedVhost";
       documentRoot = cfg.root;
       extraConfig = ''
@@ -177,19 +176,18 @@ in
         '';
     };
     toVhost = ips: vhostConf: {
-      enableSSL = true;
-      sslServerCert = "${config.security.acme2.certs."${vhostConf.certName}".directory}/cert.pem";
-      sslServerKey = "${config.security.acme2.certs."${vhostConf.certName}".directory}/key.pem";
-      sslServerChain = "${config.security.acme2.certs."${vhostConf.certName}".directory}/chain.pem";
+      forceSSL = vhostConf.forceSSL or true;
+      useACMEHost = vhostConf.certName;
       logFormat = "combinedVhost";
-      listen = map (ip: { inherit ip; port = 443; }) ips;
+      listen = if vhostConf.forceSSL
+        then lists.flatten (map (ip: [{ inherit ip; port = 443; ssl = true; } { inherit ip; port = 80; }]) ips)
+        else map (ip: { inherit ip; port = 443; ssl = true; }) ips;
       hostName = builtins.head vhostConf.hosts;
       serverAliases = builtins.tail vhostConf.hosts or [];
       documentRoot = vhostConf.root;
       extraConfig = builtins.concatStringsSep "\n" vhostConf.extraConfig;
     };
     toVhostNoSSL = ips: vhostConf: {
-      enableSSL = false;
       logFormat = "combinedVhost";
       listen = map (ip: { inherit ip; port = 80; }) ips;
       hostName = builtins.head vhostConf.hosts;
@@ -200,11 +198,10 @@ in
   in attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
     icfg.httpdName (mkIf icfg.enable {
       enable = true;
-      listen = map (ip: { inherit ip; port = 443; }) icfg.ips;
-      stateDir = "/run/httpd_${name}";
       logPerVirtualHost = true;
       multiProcessingModule = "worker";
       # https://ssl-config.mozilla.org/#server=apache&version=2.4.41&config=intermediate&openssl=1.0.2t&guideline=5.4
+      # test with https://www.ssllabs.com/ssltest/analyze.html?d=www.immae.eu&s=176.9.151.154&latest
       sslProtocols = "all -SSLv3 -TLSv1 -TLSv1.1";
       sslCiphers = builtins.concatStringsSep ":" [
         "ECDHE-ECDSA-AES128-GCM-SHA256" "ECDHE-RSA-AES128-GCM-SHA256"
@@ -216,11 +213,13 @@ in
       logFormat = "combinedVhost";
       extraModules = lists.unique icfg.modules;
       extraConfig = builtins.concatStringsSep "\n" icfg.extraConfig;
-      virtualHosts = [ (toVhost icfg.ips icfg.fallbackVhost) ]
-        ++ optionals (icfg.nosslVhost.enable) [ (nosslVhost icfg.ips icfg.nosslVhost) ]
-        ++ (attrsets.mapAttrsToList (n: v: toVhostNoSSL icfg.ips v) icfg.vhostNoSSLConfs)
-        ++ (attrsets.mapAttrsToList (n: v: toVhost icfg.ips v) icfg.vhostConfs)
-        ++ [ (redirectVhost icfg.ips) ];
+
+      virtualHosts = with attrsets; {
+        ___fallbackVhost = toVhost icfg.ips icfg.fallbackVhost;
+      } // (optionalAttrs icfg.nosslVhost.enable {
+        nosslVhost = nosslVhost icfg.ips icfg.nosslVhost;
+      }) // (mapAttrs' (n: v: nameValuePair ("nossl_" + n) (toVhostNoSSL icfg.ips v)) icfg.vhostNoSSLConfs)
+      // (mapAttrs' (n: v: nameValuePair ("ssl_" + n) (toVhost icfg.ips v)) icfg.vhostConfs);
     })
   ) cfg.env;
 
@@ -231,7 +230,7 @@ in
     }
   ) cfg.env;
 
-  config.security.acme2.certs = let
+  config.security.acme.certs = let
     typesToManage = attrsets.filterAttrs (k: v: v.enable) cfg.env;
     flatVhosts = lists.flatten (attrsets.mapAttrsToList (k: v:
       attrValues v.vhostConfs
@@ -276,4 +275,42 @@ in
         (name: path: "ln -s ${path} $out/${cfg.webappDirsName}/${name}") cfg.webappDirs)
     }
   '';
+
+  config.systemd.services = let
+    package = httpdName: config.services.httpd.${httpdName}.package.out;
+    cfgFile = httpdName: config.services.httpd.${httpdName}.configFile;
+    serviceChange = attrsets.mapAttrs' (name: icfg:
+      attrsets.nameValuePair
+      "httpd${icfg.httpdName}" {
+        stopIfChanged = false;
+        serviceConfig.ExecStart =
+          lib.mkForce "@${package icfg.httpdName}/bin/httpd httpd -f /etc/httpd/httpd_${icfg.httpdName}.conf";
+        serviceConfig.ExecStop =
+          lib.mkForce "${package icfg.httpdName}/bin/httpd -f /etc/httpd/httpd_${icfg.httpdName}.conf -k graceful-stop";
+        serviceConfig.ExecReload =
+          lib.mkForce "${package icfg.httpdName}/bin/httpd -f /etc/httpd/httpd_${icfg.httpdName}.conf -k graceful";
+      }
+      ) cfg.env;
+    serviceReload = attrsets.mapAttrs' (name: icfg:
+      attrsets.nameValuePair
+      "httpd${icfg.httpdName}-config-reload" {
+        wants = [ "httpd${icfg.httpdName}.service" ];
+        wantedBy = [ "multi-user.target" ];
+        restartTriggers = [ (cfgFile icfg.httpdName) ];
+        # commented, because can cause extra delays during activate for this config:
+        #      services.nginx.virtualHosts."_".locations."/".proxyPass = "http://blabla:3000";
+        # stopIfChanged = false;
+        serviceConfig.Type = "oneshot";
+        serviceConfig.TimeoutSec = 60;
+        script = ''
+          if ${pkgs.systemd}/bin/systemctl -q is-active httpd${icfg.httpdName}.service ; then
+            ${package icfg.httpdName}/bin/httpd -f /etc/httpd/httpd_${icfg.httpdName}.conf -t && \
+              ${pkgs.systemd}/bin/systemctl reload httpd${icfg.httpdName}.service
+          fi
+        '';
+        serviceConfig.RemainAfterExit = true;
+      }
+      ) cfg.env;
+  in
+    serviceChange // serviceReload;
 }