]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Add httpdTools service
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Fri, 18 Jan 2019 06:20:46 +0000 (07:20 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Fri, 18 Jan 2019 06:20:46 +0000 (07:20 +0100)
This adds httpTools service, similar to integration and prod services,
and removes the unneeded allGranted statement to /nix/store

virtual/modules/certificates.nix
virtual/modules/websites/apache/httpd_inte.nix
virtual/modules/websites/apache/httpd_prod.nix
virtual/modules/websites/apache/httpd_tools.nix [new file with mode: 0644]
virtual/modules/websites/commons/adminer.nix
virtual/modules/websites/default.nix

index 78665a7488ad5bacabe1a7fa38603c37f89508c0..09484e6ae7893798195140edf6b713a55872433a 100644 (file)
@@ -6,7 +6,7 @@
         webroot = "/var/lib/acme/acme-challenge";
         email = "ismael@bouya.org";
         postRun = ''
-          systemctl reload httpd.service httpdInte.service httpdProd.service
+          systemctl reload httpdTools.service httpdInte.service httpdProd.service
         '';
         plugins = [ "cert.pem" "chain.pem" "fullchain.pem" "full.pem" "key.pem" "account_key.json" ];
       };
index 83d8ab8ddb8277d4c942e8976c1853cbfe3612d5..0417281c0bb1e4d9181056cc3799b0dd14cf99b8 100644 (file)
@@ -385,13 +385,6 @@ let
         ${allDenied}
     </Directory>
 
-    # But do allow access to files in the store so that we don't have
-    # to generate <Directory> clauses for every generated file that we
-    # want to serve.
-    <Directory /nix/store>
-        ${allGranted}
-    </Directory>
-
     # Generate directives for the main server.
     ${perServerConf true mainCfg}
 
index 576a3051abbeeaa1617de0829635035fa5fd141b..5aee602cebe6f7359088d8b29cc6a2a5a11b7efb 100644 (file)
@@ -385,13 +385,6 @@ let
         ${allDenied}
     </Directory>
 
-    # But do allow access to files in the store so that we don't have
-    # to generate <Directory> clauses for every generated file that we
-    # want to serve.
-    <Directory /nix/store>
-        ${allGranted}
-    </Directory>
-
     # Generate directives for the main server.
     ${perServerConf true mainCfg}
 
diff --git a/virtual/modules/websites/apache/httpd_tools.nix b/virtual/modules/websites/apache/httpd_tools.nix
new file mode 100644 (file)
index 0000000..c0b779b
--- /dev/null
@@ -0,0 +1,727 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  mainCfg = config.services.httpdTools;
+
+  httpd = mainCfg.package.out;
+
+  version24 = !versionOlder httpd.version "2.4";
+
+  httpdConf = mainCfg.configFile;
+
+  php = mainCfg.phpPackage.override { apacheHttpd = httpd.dev; /* otherwise it only gets .out */ };
+
+  phpMajorVersion = head (splitString "." php.version);
+
+  mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = httpd; };
+
+  defaultListen = cfg: if cfg.enableSSL
+    then [{ip = "*"; port = 443;}]
+    else [{ip = "*"; port = 80;}];
+
+  getListen = cfg:
+    let list = (lib.optional (cfg.port != 0) {ip = "*"; port = cfg.port;}) ++ cfg.listen;
+    in if list == []
+        then defaultListen cfg
+        else list;
+
+  listenToString = l: "${l.ip}:${toString l.port}";
+
+  extraModules = attrByPath ["extraModules"] [] mainCfg;
+  extraForeignModules = filter isAttrs extraModules;
+  extraApacheModules = filter isString extraModules;
+
+
+  makeServerInfo = cfg: {
+    # Canonical name must not include a trailing slash.
+    canonicalNames =
+      let defaultPort = (head (defaultListen cfg)).port; in
+      map (port:
+        (if cfg.enableSSL then "https" else "http") + "://" +
+        cfg.hostName +
+        (if port != defaultPort then ":${toString port}" else "")
+        ) (map (x: x.port) (getListen cfg));
+
+    # Admin address: inherit from the main server if not specified for
+    # a virtual host.
+    adminAddr = if cfg.adminAddr != null then cfg.adminAddr else mainCfg.adminAddr;
+
+    vhostConfig = cfg;
+    serverConfig = mainCfg;
+    fullConfig = config; # machine config
+  };
+
+
+  allHosts = [mainCfg] ++ mainCfg.virtualHosts;
+
+
+  callSubservices = serverInfo: defs:
+    let f = svc:
+      let
+        svcFunction =
+          if svc ? function then svc.function
+          # instead of using serviceType="mediawiki"; you can copy mediawiki.nix to any location outside nixpkgs, modify it at will, and use serviceExpression=./mediawiki.nix;
+          else if svc ? serviceExpression then import (toString svc.serviceExpression)
+          else import (toString "${toString ./.}/${if svc ? serviceType then svc.serviceType else svc.serviceName}.nix");
+        config = (evalModules
+          { modules = [ { options = res.options; config = svc.config or svc; } ];
+            check = false;
+          }).config;
+        defaults = {
+          extraConfig = "";
+          extraModules = [];
+          extraModulesPre = [];
+          extraPath = [];
+          extraServerPath = [];
+          globalEnvVars = [];
+          robotsEntries = "";
+          startupScript = "";
+          enablePHP = false;
+          enablePerl = false;
+          phpOptions = "";
+          options = {};
+          documentRoot = null;
+        };
+        res = defaults // svcFunction { inherit config lib pkgs serverInfo php; };
+      in res;
+    in map f defs;
+
+
+  # !!! callSubservices is expensive
+  subservicesFor = cfg: callSubservices (makeServerInfo cfg) cfg.extraSubservices;
+
+  mainSubservices = subservicesFor mainCfg;
+
+  allSubservices = mainSubservices ++ concatMap subservicesFor mainCfg.virtualHosts;
+
+
+  enableSSL = any (vhost: vhost.enableSSL) allHosts;
+
+
+  # Names of modules from ${httpd}/modules that we want to load.
+  apacheModules =
+    [ # HTTP authentication mechanisms: basic and digest.
+      "auth_basic" "auth_digest"
+
+      # Authentication: is the user who he claims to be?
+      "authn_file" "authn_dbm" "authn_anon"
+      (if version24 then "authn_core" else "authn_alias")
+
+      # Authorization: is the user allowed access?
+      "authz_user" "authz_groupfile" "authz_host"
+
+      # Other modules.
+      "ext_filter" "include" "log_config" "env" "mime_magic"
+      "cern_meta" "expires" "headers" "usertrack" /* "unique_id" */ "setenvif"
+      "mime" "dav" "status" "autoindex" "asis" "info" "dav_fs"
+      "vhost_alias" "negotiation" "dir" "imagemap" "actions" "speling"
+      "userdir" "alias" "rewrite" "proxy" "proxy_http"
+    ]
+    ++ optionals version24 [
+      "mpm_${mainCfg.multiProcessingModule}"
+      "authz_core"
+      "unixd"
+      "cache" "cache_disk"
+      "slotmem_shm"
+      "socache_shmcb"
+      # For compatibility with old configurations, the new module mod_access_compat is provided.
+      "access_compat"
+    ]
+    ++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ])
+    ++ optional enableSSL "ssl"
+    ++ extraApacheModules;
+
+
+  allDenied = if version24 then ''
+    Require all denied
+  '' else ''
+    Order deny,allow
+    Deny from all
+  '';
+
+  allGranted = if version24 then ''
+    Require all granted
+  '' else ''
+    Order allow,deny
+    Allow from all
+  '';
+
+
+  loggingConf = (if mainCfg.logFormat != "none" then ''
+    ErrorLog ${mainCfg.logDir}/error_log
+
+    LogLevel notice
+
+    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+    LogFormat "%h %l %u %t \"%r\" %>s %b" common
+    LogFormat "%{Referer}i -> %U" referer
+    LogFormat "%{User-agent}i" agent
+
+    CustomLog ${mainCfg.logDir}/access_log ${mainCfg.logFormat}
+  '' else ''
+    ErrorLog /dev/null
+  '');
+
+
+  browserHacks = ''
+    BrowserMatch "Mozilla/2" nokeepalive
+    BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
+    BrowserMatch "RealPlayer 4\.0" force-response-1.0
+    BrowserMatch "Java/1\.0" force-response-1.0
+    BrowserMatch "JDK/1\.0" force-response-1.0
+    BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
+    BrowserMatch "^WebDrive" redirect-carefully
+    BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully
+    BrowserMatch "^gnome-vfs" redirect-carefully
+  '';
+
+
+  sslConf = ''
+    SSLSessionCache ${if version24 then "shmcb" else "shm"}:${mainCfg.stateDir}/ssl_scache(512000)
+
+    ${if version24 then "Mutex" else "SSLMutex"} posixsem
+
+    SSLRandomSeed startup builtin
+    SSLRandomSeed connect builtin
+
+    SSLProtocol All -SSLv2 -SSLv3
+    SSLCipherSuite HIGH:!aNULL:!MD5:!EXP
+    SSLHonorCipherOrder on
+  '';
+
+
+  mimeConf = ''
+    TypesConfig ${httpd}/conf/mime.types
+
+    AddType application/x-x509-ca-cert .crt
+    AddType application/x-pkcs7-crl    .crl
+    AddType application/x-httpd-php    .php .phtml
+
+    <IfModule mod_mime_magic.c>
+        MIMEMagicFile ${httpd}/conf/magic
+    </IfModule>
+  '';
+
+
+  perServerConf = isMainServer: cfg: let
+
+    serverInfo = makeServerInfo cfg;
+
+    subservices = callSubservices serverInfo cfg.extraSubservices;
+
+    maybeDocumentRoot = fold (svc: acc:
+      if acc == null then svc.documentRoot else assert svc.documentRoot == null; acc
+    ) null ([ cfg ] ++ subservices);
+
+    documentRoot = if maybeDocumentRoot != null then maybeDocumentRoot else
+      pkgs.runCommand "empty" {} "mkdir -p $out";
+
+    documentRootConf = ''
+      DocumentRoot "${documentRoot}"
+
+      <Directory "${documentRoot}">
+          Options Indexes FollowSymLinks
+          AllowOverride None
+          ${allGranted}
+      </Directory>
+    '';
+
+    robotsTxt =
+      concatStringsSep "\n" (filter (x: x != "") (
+        # If this is a vhost, the include the entries for the main server as well.
+        (if isMainServer then [] else [mainCfg.robotsEntries] ++ map (svc: svc.robotsEntries) mainSubservices)
+        ++ [cfg.robotsEntries]
+        ++ (map (svc: svc.robotsEntries) subservices)));
+
+  in ''
+    ${concatStringsSep "\n" (map (n: "ServerName ${n}") serverInfo.canonicalNames)}
+
+    ${concatMapStrings (alias: "ServerAlias ${alias}\n") cfg.serverAliases}
+
+    ${if cfg.sslServerCert != null then ''
+      SSLCertificateFile ${cfg.sslServerCert}
+      SSLCertificateKeyFile ${cfg.sslServerKey}
+      ${if cfg.sslServerChain != null then ''
+        SSLCertificateChainFile ${cfg.sslServerChain}
+      '' else ""}
+    '' else ""}
+
+    ${if cfg.enableSSL then ''
+      SSLEngine on
+    '' else if enableSSL then /* i.e., SSL is enabled for some host, but not this one */
+    ''
+      SSLEngine off
+    '' else ""}
+
+    ${if isMainServer || cfg.adminAddr != null then ''
+      ServerAdmin ${cfg.adminAddr}
+    '' else ""}
+
+    ${if !isMainServer && mainCfg.logPerVirtualHost then ''
+      ErrorLog ${mainCfg.logDir}/error_log-${cfg.hostName}
+      CustomLog ${mainCfg.logDir}/access_log-${cfg.hostName} ${cfg.logFormat}
+    '' else ""}
+
+    ${optionalString (robotsTxt != "") ''
+      Alias /robots.txt ${pkgs.writeText "robots.txt" robotsTxt}
+    ''}
+
+    ${if isMainServer || maybeDocumentRoot != null then documentRootConf else ""}
+
+    ${if cfg.enableUserDir then ''
+
+      UserDir public_html
+      UserDir disabled root
+
+      <Directory "/home/*/public_html">
+          AllowOverride FileInfo AuthConfig Limit Indexes
+          Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
+          <Limit GET POST OPTIONS>
+              ${allGranted}
+          </Limit>
+          <LimitExcept GET POST OPTIONS>
+              ${allDenied}
+          </LimitExcept>
+      </Directory>
+
+    '' else ""}
+
+    ${if cfg.globalRedirect != null && cfg.globalRedirect != "" then ''
+      RedirectPermanent / ${cfg.globalRedirect}
+    '' else ""}
+
+    ${
+      let makeFileConf = elem: ''
+            Alias ${elem.urlPath} ${elem.file}
+          '';
+      in concatMapStrings makeFileConf cfg.servedFiles
+    }
+
+    ${
+      let makeDirConf = elem: ''
+            Alias ${elem.urlPath} ${elem.dir}/
+            <Directory ${elem.dir}>
+                Options +Indexes
+                ${allGranted}
+                AllowOverride All
+            </Directory>
+          '';
+      in concatMapStrings makeDirConf cfg.servedDirs
+    }
+
+    ${concatMapStrings (svc: svc.extraConfig) subservices}
+
+    ${cfg.extraConfig}
+  '';
+
+
+  confFile = pkgs.writeText "httpd.conf" ''
+
+    ServerRoot ${httpd}
+
+    ${optionalString version24 ''
+      DefaultRuntimeDir ${mainCfg.stateDir}/runtime
+    ''}
+
+    PidFile ${mainCfg.stateDir}/httpd.pid
+
+    ${optionalString (mainCfg.multiProcessingModule != "prefork") ''
+      # mod_cgid requires this.
+      ScriptSock ${mainCfg.stateDir}/cgisock
+    ''}
+
+    <IfModule prefork.c>
+        MaxClients           ${toString mainCfg.maxClients}
+        MaxRequestsPerChild  ${toString mainCfg.maxRequestsPerChild}
+    </IfModule>
+
+    ${let
+        listen = concatMap getListen allHosts;
+        toStr = listen: "Listen ${listenToString listen}\n";
+        uniqueListen = uniqList {inputList = map toStr listen;};
+      in concatStrings uniqueListen
+    }
+
+    User ${mainCfg.user}
+    Group ${mainCfg.group}
+
+    ${let
+        load = {name, path}: "LoadModule ${name}_module ${path}\n";
+        allModules =
+          concatMap (svc: svc.extraModulesPre) allSubservices
+          ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules
+          ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; }
+          ++ optional enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; }
+          ++ optional enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; }
+          ++ concatMap (svc: svc.extraModules) allSubservices
+          ++ extraForeignModules;
+      in concatMapStrings load allModules
+    }
+
+    AddHandler type-map var
+
+    <Files ~ "^\.ht">
+        ${allDenied}
+    </Files>
+
+    ${mimeConf}
+    ${loggingConf}
+    ${browserHacks}
+
+    Include ${httpd}/conf/extra/httpd-default.conf
+    Include ${httpd}/conf/extra/httpd-autoindex.conf
+    Include ${httpd}/conf/extra/httpd-multilang-errordoc.conf
+    Include ${httpd}/conf/extra/httpd-languages.conf
+
+    ${if enableSSL then sslConf else ""}
+
+    # Fascist default - deny access to everything.
+    <Directory />
+        Options FollowSymLinks
+        AllowOverride None
+        ${allDenied}
+    </Directory>
+
+    # Generate directives for the main server.
+    ${perServerConf true mainCfg}
+
+    # Always enable virtual hosts; it doesn't seem to hurt.
+    ${let
+        listen = concatMap getListen allHosts;
+        uniqueListen = uniqList {inputList = listen;};
+        directives = concatMapStrings (listen: "NameVirtualHost ${listenToString listen}\n") uniqueListen;
+      in optionalString (!version24) directives
+    }
+
+    ${let
+        makeVirtualHost = vhost: ''
+          <VirtualHost ${concatStringsSep " " (map listenToString (getListen vhost))}>
+              ${perServerConf false vhost}
+          </VirtualHost>
+        '';
+      in concatMapStrings makeVirtualHost mainCfg.virtualHosts
+    }
+  '';
+
+
+  enablePHP = mainCfg.enablePHP || any (svc: svc.enablePHP) allSubservices;
+
+  enablePerl = mainCfg.enablePerl || any (svc: svc.enablePerl) allSubservices;
+
+
+  # Generate the PHP configuration file.  Should probably be factored
+  # out into a separate module.
+  phpIni = pkgs.runCommand "php.ini"
+    { options = concatStringsSep "\n"
+        ([ mainCfg.phpOptions ] ++ (map (svc: svc.phpOptions) allSubservices));
+    }
+    ''
+      cat ${php}/etc/php.ini > $out
+      echo "$options" >> $out
+    '';
+
+in
+
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.httpdTools = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the Apache HTTP Server.";
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.apacheHttpd;
+        defaultText = "pkgs.apacheHttpd";
+        description = ''
+          Overridable attribute of the Apache HTTP Server package to use.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        default = confFile;
+        defaultText = "confFile";
+        example = literalExample ''pkgs.writeText "httpd.conf" "# my custom config file ..."'';
+        description = ''
+          Override the configuration file used by Apache. By default,
+          NixOS generates one automatically.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Cnfiguration lines appended to the generated Apache
+          configuration file. Note that this mechanism may not work
+          when <option>configFile</option> is overridden.
+        '';
+      };
+
+      extraModules = mkOption {
+        type = types.listOf types.unspecified;
+        default = [];
+        example = literalExample ''[ "proxy_connect" { name = "php5"; path = "''${pkgs.php}/modules/libphp5.so"; } ]'';
+        description = ''
+          Additional Apache modules to be used.  These can be
+          specified as a string in the case of modules distributed
+          with Apache, or as an attribute set specifying the
+          <varname>name</varname> and <varname>path</varname> of the
+          module.
+        '';
+      };
+
+      logPerVirtualHost = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If enabled, each virtual host gets its own
+          <filename>access_log</filename> and
+          <filename>error_log</filename>, namely suffixed by the
+          <option>hostName</option> of the virtual host.
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "wwwrun";
+        description = ''
+          User account under which httpd runs.  The account is created
+          automatically if it doesn't exist.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "wwwrun";
+        description = ''
+          Group under which httpd runs.  The account is created
+          automatically if it doesn't exist.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/httpd";
+        description = ''
+          Directory for Apache's log files.  It is created automatically.
+        '';
+      };
+
+      stateDir = mkOption {
+        type = types.path;
+        default = "/run/httpd";
+        description = ''
+          Directory for Apache's transient runtime state (such as PID
+          files).  It is created automatically.  Note that the default,
+          <filename>/run/httpd</filename>, is deleted at boot time.
+        '';
+      };
+
+      virtualHosts = mkOption {
+        type = types.listOf (types.submodule (
+          { options = import ./per-server-options.nix {
+              inherit lib;
+              forMainServer = false;
+            };
+          }));
+        default = [];
+        example = [
+          { hostName = "foo";
+            documentRoot = "/data/webroot-foo";
+          }
+          { hostName = "bar";
+            documentRoot = "/data/webroot-bar";
+          }
+        ];
+        description = ''
+          Specification of the virtual hosts served by Apache.  Each
+          element should be an attribute set specifying the
+          configuration of the virtual host.  The available options
+          are the non-global options permissible for the main host.
+        '';
+      };
+
+      enableMellon = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the mod_auth_mellon module.";
+      };
+
+      enablePHP = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the PHP module.";
+      };
+
+      phpPackage = mkOption {
+        type = types.package;
+        default = pkgs.php;
+        defaultText = "pkgs.php";
+        description = ''
+          Overridable attribute of the PHP package to use.
+        '';
+      };
+
+      enablePerl = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the Perl module (mod_perl).";
+      };
+
+      phpOptions = mkOption {
+        type = types.lines;
+        default = "";
+        example =
+          ''
+            date.timezone = "CET"
+          '';
+        description =
+          "Options appended to the PHP configuration file <filename>php.ini</filename>.";
+      };
+
+      multiProcessingModule = mkOption {
+        type = types.str;
+        default = "prefork";
+        example = "worker";
+        description =
+          ''
+            Multi-processing module to be used by Apache.  Available
+            modules are <literal>prefork</literal> (the default;
+            handles each request in a separate child process),
+            <literal>worker</literal> (hybrid approach that starts a
+            number of child processes each running a number of
+            threads) and <literal>event</literal> (a recent variant of
+            <literal>worker</literal> that handles persistent
+            connections more efficiently).
+          '';
+      };
+
+      maxClients = mkOption {
+        type = types.int;
+        default = 150;
+        example = 8;
+        description = "Maximum number of httpd processes (prefork)";
+      };
+
+      maxRequestsPerChild = mkOption {
+        type = types.int;
+        default = 0;
+        example = 500;
+        description =
+          "Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited";
+      };
+    }
+
+    # Include the options shared between the main server and virtual hosts.
+    // (import ./per-server-options.nix {
+      inherit lib;
+      forMainServer = true;
+    });
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.httpdTools.enable {
+
+    assertions = [ { assertion = mainCfg.enableSSL == true
+                               -> mainCfg.sslServerCert != null
+                                    && mainCfg.sslServerKey != null;
+                     message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; }
+                 ];
+
+    warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port};}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts);
+
+    users.users = optionalAttrs (mainCfg.user == "wwwrun") (singleton
+      { name = "wwwrun";
+        group = mainCfg.group;
+        description = "Apache httpd user";
+        uid = config.ids.uids.wwwrun;
+      });
+
+    users.groups = optionalAttrs (mainCfg.group == "wwwrun") (singleton
+      { name = "wwwrun";
+        gid = config.ids.gids.wwwrun;
+      });
+
+    environment.systemPackages = [httpd] ++ concatMap (svc: svc.extraPath) allSubservices;
+
+    services.httpdTools.phpOptions =
+      ''
+        ; Needed for PHP's mail() function.
+        sendmail_path = sendmail -t -i
+      '' + optionalString (!isNull config.time.timeZone) ''
+
+        ; Apparently PHP doesn't use $TZ.
+        date.timezone = "${config.time.timeZone}"
+      '';
+
+    systemd.services.httpdTools =
+      { description = "Apache HTTPD";
+
+        wantedBy = [ "multi-user.target" ];
+        wants = [ "keys.target" ];
+        after = [ "network.target" "fs.target" "postgresql.service" "keys.target" ];
+
+        path =
+          [ httpd pkgs.coreutils pkgs.gnugrep ]
+          ++ # Needed for PHP's mail() function.  !!! Probably the
+             # ssmtp module should export the path to sendmail in
+             # some way.
+             optional config.networking.defaultMailServer.directDelivery pkgs.ssmtp
+          ++ concatMap (svc: svc.extraServerPath) allSubservices;
+
+        environment =
+          optionalAttrs enablePHP { PHPRC = phpIni; }
+          // optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH  = "${pkgs.xmlsec}/lib"; }
+          // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices));
+
+        preStart =
+          ''
+            mkdir -m 0750 -p ${mainCfg.stateDir}
+            [ $(id -u) != 0 ] || chown root.${mainCfg.group} ${mainCfg.stateDir}
+            ${optionalString version24 ''
+              mkdir -m 0750 -p "${mainCfg.stateDir}/runtime"
+              [ $(id -u) != 0 ] || chown root.${mainCfg.group} "${mainCfg.stateDir}/runtime"
+            ''}
+            mkdir -m 0700 -p ${mainCfg.logDir}
+
+            # Get rid of old semaphores.  These tend to accumulate across
+            # server restarts, eventually preventing it from restarting
+            # successfully.
+            for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${mainCfg.user} ' | cut -f2 -d ' '); do
+                ${pkgs.utillinux}/bin/ipcrm -s $i
+            done
+
+            # Run the startup hooks for the subservices.
+            for i in ${toString (map (svn: svn.startupScript) allSubservices)}; do
+                echo Running Apache startup hook $i...
+                $i
+            done
+          '';
+
+        serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf}";
+        serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop";
+        serviceConfig.ExecReload = "${httpd}/bin/httpd -f ${httpdConf} -k graceful";
+        serviceConfig.Type = "forking";
+        serviceConfig.PIDFile = "${mainCfg.stateDir}/httpd.pid";
+        serviceConfig.Restart = "always";
+        serviceConfig.RestartSec = "5s";
+      };
+
+  };
+}
index 7094e455d098d811ffc26eb0cb8417582a1c9ecb..891046f97719588a7343d355deec52429035b57d 100644 (file)
@@ -40,6 +40,7 @@ let
         Alias /adminer ${webRoot}
         <Directory ${webRoot}>
           DirectoryIndex index.php
+          Require all granted
           <FilesMatch "\.php$">
             SetHandler "proxy:unix:${phpFpm.socket}|fcgi://localhost"
           </FilesMatch>
index 0ea7029ad24377d29842530efbe92b3934814090..55ded8ac8e65c0208047980f6281b312a74b1691 100644 (file)
@@ -100,9 +100,12 @@ in
     ./tools/mastodon
     # built using:
     # sed -e "s/services\.httpd/services\.httpdProd/g" .nix-defexpr/channels/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
+    # Removed allGranted
     # And removed users / groups
     ./apache/httpd_prod.nix
     ./apache/httpd_inte.nix
+    # except for this one for users/groups
+    ./apache/httpd_tools.nix
     # Adapted from base phpfpm
     ./phpfpm
   ];
@@ -276,7 +279,7 @@ in
     services.myWebsites.integration.modules = pkgs.lib.lists.flatten (pkgs.lib.attrsets.mapAttrsToList (n: v: v.modules or []) cfg.apacheConfig);
     services.myWebsites.integration.extraConfig = (builtins.filter (x: x != null) (pkgs.lib.attrsets.mapAttrsToList (n: v: v.extraConfig or null) cfg.apacheConfig));
 
-    services.httpd = makeService "tools" config.services.myWebsites.tools;
+    services.httpdTools = makeService "tools" config.services.myWebsites.tools;
     services.myWebsites.tools.modules = pkgs.lib.lists.flatten (pkgs.lib.attrsets.mapAttrsToList (n: v: v.modules or []) cfg.apacheConfig);
     services.myWebsites.tools.extraConfig = (builtins.filter (x: x != null) (pkgs.lib.attrsets.mapAttrsToList (n: v: v.extraConfig or null) cfg.apacheConfig));
   };