diff options
Diffstat (limited to 'nixpkgs/nixos/modules/services/web-servers/apache-httpd')
11 files changed, 2279 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix new file mode 100644 index 000000000000..8f00f81b078c --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -0,0 +1,750 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + mainCfg = config.services.httpd; + + 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 ${mainCfg.sslProtocols} + SSLCipherSuite ${mainCfg.sslCiphers} + 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" { preferLocalBuild = true; } "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-${cfg.hostName}.log + CustomLog ${mainCfg.logDir}/access-${cfg.hostName}.log ${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 + + TraceEnable off + + ${if enableSSL then sslConf else ""} + + # Fascist default - deny access to everything. + <Directory /> + Options FollowSymLinks + AllowOverride None + ${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} + + # 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)); + preferLocalBuild = true; + } + '' + cat ${php}/etc/php.ini > $out + echo "$options" >> $out + ''; + +in + + +{ + + ###### interface + + options = { + + services.httpd = { + + 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"; + }; + + sslCiphers = mkOption { + type = types.str; + default = "HIGH:!aNULL:!MD5:!EXP"; + description = "Cipher Suite available for negotiation in SSL proxy handshake."; + }; + + sslProtocols = mkOption { + type = types.str; + default = "All -SSLv2 -SSLv3 -TLSv1"; + example = "All -SSLv2 -SSLv3"; + description = "Allowed SSL/TLS protocol versions."; + }; + } + + # 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.httpd.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.httpd.phpOptions = + '' + ; Needed for PHP's mail() function. + sendmail_path = sendmail -t -i + + ; Don't advertise PHP + expose_php = off + '' + optionalString (!isNull config.time.timeZone) '' + + ; Apparently PHP doesn't use $TZ. + date.timezone = "${config.time.timeZone}" + ''; + + systemd.services.httpd = + { 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 ] + ++ optional enablePHP pkgs.system-sendmail # Needed for PHP's mail() function. + ++ 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"; + }; + + }; +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/foswiki.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/foswiki.nix new file mode 100644 index 000000000000..8c1ac8935a47 --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/foswiki.nix @@ -0,0 +1,78 @@ +{ config, pkgs, lib, serverInfo, ... }: +let + inherit (pkgs) foswiki; + inherit (serverInfo.serverConfig) user group; + inherit (config) vardir; +in +{ + options.vardir = lib.mkOption { + type = lib.types.path; + default = "/var/www/foswiki"; + description = "The directory where variable foswiki data will be stored and served from."; + }; + + # TODO: this will probably need to be better customizable + extraConfig = + let httpd-conf = pkgs.runCommand "foswiki-httpd.conf" + { preferLocalBuild = true; } + '' + substitute '${foswiki}/foswiki_httpd_conf.txt' "$out" \ + --replace /var/www/foswiki/ "${vardir}/" + ''; + in + '' + RewriteEngine on + RewriteRule /foswiki/(.*) ${vardir}/$1 + + <Directory "${vardir}"> + Require all granted + </Directory> + + Include ${httpd-conf} + <Directory "${vardir}/pub"> + Options FollowSymlinks + </Directory> + ''; + + /** This handles initial setup and updates. + It will probably need some tweaking, maybe per-site. */ + startupScript = pkgs.writeScript "foswiki_startup.sh" ( + let storeLink = "${vardir}/package"; in + '' + [ -e '${storeLink}' ] || needs_setup=1 + mkdir -p '${vardir}' + cd '${vardir}' + ln -sf -T '${foswiki}' '${storeLink}' + + if [ -n "$needs_setup" ]; then # do initial setup + mkdir -p bin lib + # setup most of data/ as copies only + cp -r '${foswiki}'/data '${vardir}/' + rm -r '${vardir}'/data/{System,mime.types} + ln -sr -t '${vardir}/data/' '${storeLink}'/data/{System,mime.types} + + ln -sr '${storeLink}/locale' . + + mkdir pub + ln -sr '${storeLink}/pub/System' pub/ + + mkdir templates + ln -sr '${storeLink}'/templates/* templates/ + + ln -sr '${storeLink}/tools' . + + mkdir -p '${vardir}'/working/{logs,tmp} + ln -sr '${storeLink}/working/README' working/ # used to check dir validity + + chown -R '${user}:${group}' . + chmod +w -R . + fi + + # bin/* and lib/* shall always be overwritten, in case files are added + ln -srf '${storeLink}'/bin/* '${vardir}/bin/' + ln -srf '${storeLink}'/lib/* '${vardir}/lib/' + '' + /* Symlinking bin/ one-by-one ensures that ${vardir}/lib/LocalSite.cfg + is used instead of ${foswiki}/... */ + ); +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/limesurvey.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/limesurvey.nix new file mode 100644 index 000000000000..5c387700a5d5 --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/limesurvey.nix @@ -0,0 +1,196 @@ +{ config, lib, pkgs, serverInfo, ... }: + +with lib; + +let + + httpd = serverInfo.serverConfig.package; + + version24 = !versionOlder httpd.version "2.4"; + + allGranted = if version24 then '' + Require all granted + '' else '' + Order allow,deny + Allow from all + ''; + + limesurveyConfig = pkgs.writeText "config.php" '' + <?php + $config = array(); + $config['name'] = "${config.siteName}"; + $config['runtimePath'] = "${config.dataDir}/tmp/runtime"; + $config['components'] = array(); + $config['components']['db'] = array(); + $config['components']['db']['connectionString'] = '${config.dbType}:host=${config.dbHost};port=${toString config.dbPort};user=${config.dbUser};password=${config.dbPassword};dbname=${config.dbName};'; + $config['components']['db']['username'] = '${config.dbUser}'; + $config['components']['db']['password'] = '${config.dbPassword}'; + $config['components']['db']['charset'] = 'utf-8'; + $config['components']['db']['tablePrefix'] = "prefix_"; + $config['components']['assetManager'] = array(); + $config['components']['assetManager']['basePath'] = '${config.dataDir}/tmp/assets'; + $config['config'] = array(); + $config['config']['debug'] = 1; + $config['config']['tempdir'] = "${config.dataDir}/tmp"; + $config['config']['tempdir'] = "${config.dataDir}/tmp"; + $config['config']['uploaddir'] = "${config.dataDir}/upload"; + $config['config']['force_ssl'] = '${if config.forceSSL then "on" else ""}'; + $config['config']['defaultlang'] = '${config.defaultLang}'; + return $config; + ?> + ''; + + limesurveyRoot = "${pkgs.limesurvey}/share/limesurvey/"; + +in rec { + + extraConfig = '' + Alias ${config.urlPrefix}/tmp ${config.dataDir}/tmp + + <Directory ${config.dataDir}/tmp> + ${allGranted} + Options -Indexes +FollowSymlinks + </Directory> + + Alias ${config.urlPrefix}/upload ${config.dataDir}/upload + + <Directory ${config.dataDir}/upload> + ${allGranted} + Options -Indexes + </Directory> + + ${if config.urlPrefix != "" then '' + Alias ${config.urlPrefix} ${limesurveyRoot} + '' else '' + RewriteEngine On + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d + ''} + + <Directory ${limesurveyRoot}> + DirectoryIndex index.php + </Directory> + ''; + + globalEnvVars = [ + { name = "LIMESURVEY_CONFIG"; value = limesurveyConfig; } + ]; + + documentRoot = if config.urlPrefix == "" then limesurveyRoot else null; + + enablePHP = true; + + options = { + + id = mkOption { + default = "main"; + description = '' + A unique identifier necessary to keep multiple Limesurvey server + instances on the same machine apart. This is used to + disambiguate the administrative scripts, which get names like + mediawiki-$id-change-password. + ''; + }; + + urlPrefix = mkOption { + default = ""; + description = "Url prefix for site."; + type = types.str; + }; + + dbType = mkOption { + default = "pgsql"; + description = "Type of database for limesurvey, for now, only pgsql."; + type = types.enum ["pgsql"]; + }; + + dbName = mkOption { + default = "limesurvey"; + description = "Name of the database that holds the limesurvey data."; + type = types.str; + }; + + dbHost = mkOption { + default = "localhost"; + description = "Limesurvey database host."; + type = types.str; + }; + + dbPort = mkOption { + default = 5432; + description = "Limesurvey database port."; + type = types.int; + }; + + dbUser = mkOption { + default = "limesurvey"; + description = "Limesurvey database user."; + type = types.str; + }; + + dbPassword = mkOption { + example = "foobar"; + description = "Limesurvey database password."; + type = types.str; + }; + + adminUser = mkOption { + description = "Limesurvey admin username."; + default = "admin"; + type = types.str; + }; + + adminPassword = mkOption { + description = "Default limesurvey admin password."; + default = "admin"; + type = types.str; + }; + + adminEmail = mkOption { + description = "Limesurvey admin email."; + default = "admin@admin.com"; + type = types.str; + }; + + forceSSL = mkOption { + default = false; + description = "Force use of HTTPS connection."; + type = types.bool; + }; + + siteName = mkOption { + default = "LimeSurvey"; + description = "LimeSurvey name of the site."; + type = types.str; + }; + + defaultLang = mkOption { + default = "en"; + description = "LimeSurvey default language."; + type = types.str; + }; + + dataDir = mkOption { + default = "/var/lib/limesurvey"; + description = "LimeSurvey data directory."; + type = types.path; + }; + }; + + startupScript = pkgs.writeScript "limesurvey_startup.sh" '' + if [ ! -f ${config.dataDir}/.created ]; then + mkdir -p ${config.dataDir}/{tmp/runtime,tmp/assets,tmp/upload,upload} + chmod -R ug+rw ${config.dataDir} + chmod -R o-rwx ${config.dataDir} + chown -R wwwrun:wwwrun ${config.dataDir} + + ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole "${config.dbUser}" || true + ${pkgs.postgresql}/bin/createdb "${config.dbName}" -O "${config.dbUser}" || true + ${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/psql -U postgres -d postgres -c "alter user ${config.dbUser} with password '${config.dbPassword}';" || true + + ${pkgs.limesurvey}/bin/limesurvey-console install '${config.adminUser}' '${config.adminPassword}' '${config.adminUser}' '${config.adminEmail}' + + touch ${config.dataDir}/.created + fi + ''; +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix new file mode 100644 index 000000000000..6234478014ce --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix @@ -0,0 +1,349 @@ +{ config, lib, pkgs, serverInfo, php, ... }: + +with lib; + +let + + httpd = serverInfo.serverConfig.package; + + version24 = !versionOlder httpd.version "2.4"; + + allGranted = if version24 then '' + Require all granted + '' else '' + Order allow,deny + Allow from all + ''; + + mediawikiConfig = pkgs.writeText "LocalSettings.php" + '' + <?php + # Copied verbatim from the default (generated) LocalSettings.php. + if( defined( 'MW_INSTALL_PATH' ) ) { + $IP = MW_INSTALL_PATH; + } else { + $IP = dirname( __FILE__ ); + } + + $path = array( $IP, "$IP/includes", "$IP/languages" ); + set_include_path( implode( PATH_SEPARATOR, $path ) . PATH_SEPARATOR . get_include_path() ); + + require_once( "$IP/includes/DefaultSettings.php" ); + + if ( $wgCommandLineMode ) { + if ( isset( $_SERVER ) && array_key_exists( 'REQUEST_METHOD', $_SERVER ) ) { + die( "This script must be run from the command line\n" ); + } + } + + $wgScriptPath = "${config.urlPrefix}"; + + # We probably need to set $wgSecretKey and $wgCacheEpoch. + + # Paths to external programs. + $wgDiff3 = "${pkgs.diffutils}/bin/diff3"; + $wgDiff = "${pkgs.diffutils}/bin/diff"; + $wgImageMagickConvertCommand = "${pkgs.imagemagick.out}/bin/convert"; + + #$wgDebugLogFile = "/tmp/mediawiki_debug_log.txt"; + + # Database configuration. + $wgDBtype = "${config.dbType}"; + $wgDBserver = "${config.dbServer}"; + $wgDBuser = "${config.dbUser}"; + $wgDBpassword = "${config.dbPassword}"; + $wgDBname = "${config.dbName}"; + + # E-mail. + $wgEmergencyContact = "${config.emergencyContact}"; + $wgPasswordSender = "${config.passwordSender}"; + + $wgSitename = "${config.siteName}"; + + ${optionalString (config.logo != "") '' + $wgLogo = "${config.logo}"; + ''} + + ${optionalString (config.articleUrlPrefix != "") '' + $wgArticlePath = "${config.articleUrlPrefix}/$1"; + ''} + + ${optionalString config.enableUploads '' + $wgEnableUploads = true; + $wgUploadDirectory = "${config.uploadDir}"; + ''} + + ${optionalString (config.defaultSkin != "") '' + $wgDefaultSkin = "${config.defaultSkin}"; + ''} + + ${config.extraConfig} + ?> + ''; + + # Unpack Mediawiki and put the config file in its root directory. + mediawikiRoot = pkgs.stdenv.mkDerivation rec { + name= "mediawiki-1.31.1"; + + src = pkgs.fetchurl { + url = "https://releases.wikimedia.org/mediawiki/1.31/${name}.tar.gz"; + sha256 = "13x48clij21cmysjkpnx68vggchrdasqp7b290j87xlfgjhdhnnf"; + }; + + skins = config.skins; + extensions = config.extensions; + + buildPhase = + '' + for skin in $skins; do + cp -prvd $skin/* skins/ + done + for extension in $extensions; do + cp -prvd $extension/* extensions/ + done + ''; # */ + + installPhase = + '' + mkdir -p $out + cp -r * $out + cp ${mediawikiConfig} $out/LocalSettings.php + sed -i \ + -e 's|/bin/bash|${pkgs.bash}/bin/bash|g' \ + -e 's|/usr/bin/timeout|${pkgs.coreutils}/bin/timeout|g' \ + $out/includes/shell/limit.sh \ + $out/includes/GlobalFunctions.php + ''; + }; + + mediawikiScripts = pkgs.runCommand "mediawiki-${config.id}-scripts" { + buildInputs = [ pkgs.makeWrapper ]; + preferLocalBuild = true; + } '' + mkdir -p $out/bin + for i in changePassword.php createAndPromote.php userOptions.php edit.php nukePage.php update.php; do + makeWrapper ${php}/bin/php $out/bin/mediawiki-${config.id}-$(basename $i .php) \ + --add-flags ${mediawikiRoot}/maintenance/$i + done + ''; + +in + +{ + + extraConfig = + '' + ${optionalString config.enableUploads '' + Alias ${config.urlPrefix}/images ${config.uploadDir} + + <Directory ${config.uploadDir}> + ${allGranted} + Options -Indexes + </Directory> + ''} + + ${if config.urlPrefix != "" then "Alias ${config.urlPrefix} ${mediawikiRoot}" else '' + RewriteEngine On + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d + ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedDirs} + ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedFiles} + RewriteRule ${if config.enableUploads + then "!^/images" + else "^.*\$" + } %{DOCUMENT_ROOT}/${if config.articleUrlPrefix == "" + then "" + else "${config.articleUrlPrefix}/" + }index.php [L] + ''} + + <Directory ${mediawikiRoot}> + ${allGranted} + DirectoryIndex index.php + </Directory> + + ${optionalString (config.articleUrlPrefix != "") '' + Alias ${config.articleUrlPrefix} ${mediawikiRoot}/index.php + ''} + ''; + + documentRoot = if config.urlPrefix == "" then mediawikiRoot else null; + + enablePHP = true; + + options = { + + id = mkOption { + default = "main"; + description = '' + A unique identifier necessary to keep multiple MediaWiki server + instances on the same machine apart. This is used to + disambiguate the administrative scripts, which get names like + mediawiki-$id-change-password. + ''; + }; + + dbType = mkOption { + default = "postgres"; + example = "mysql"; + description = "Database type."; + }; + + dbName = mkOption { + default = "mediawiki"; + description = "Name of the database that holds the MediaWiki data."; + }; + + dbServer = mkOption { + default = ""; # use a Unix domain socket + example = "10.0.2.2"; + description = '' + The location of the database server. Leave empty to use a + database server running on the same machine through a Unix + domain socket. + ''; + }; + + dbUser = mkOption { + default = "mediawiki"; + description = "The user name for accessing the database."; + }; + + dbPassword = mkOption { + default = ""; + example = "foobar"; + description = '' + The password of the database user. Warning: this is stored in + cleartext in the Nix store! + ''; + }; + + emergencyContact = mkOption { + default = serverInfo.serverConfig.adminAddr; + example = "admin@example.com"; + description = '' + Emergency contact e-mail address. Defaults to the Apache + admin address. + ''; + }; + + passwordSender = mkOption { + default = serverInfo.serverConfig.adminAddr; + example = "password@example.com"; + description = '' + E-mail address from which password confirmations originate. + Defaults to the Apache admin address. + ''; + }; + + siteName = mkOption { + default = "MediaWiki"; + example = "Foobar Wiki"; + description = "Name of the wiki"; + }; + + logo = mkOption { + default = ""; + example = "/images/logo.png"; + description = "The URL of the site's logo (which should be a 135x135px image)."; + }; + + urlPrefix = mkOption { + default = "/w"; + description = '' + The URL prefix under which the Mediawiki service appears. + ''; + }; + + articleUrlPrefix = mkOption { + default = "/wiki"; + example = ""; + description = '' + The URL prefix under which article pages appear, + e.g. http://server/wiki/Page. Leave empty to use the main URL + prefix, e.g. http://server/w/index.php?title=Page. + ''; + }; + + enableUploads = mkOption { + default = false; + description = "Whether to enable file uploads."; + }; + + uploadDir = mkOption { + default = throw "You must specify `uploadDir'."; + example = "/data/mediawiki-upload"; + description = "The directory that stores uploaded files."; + }; + + defaultSkin = mkOption { + default = ""; + example = "nostalgia"; + description = "Set this value to change the default skin used by MediaWiki."; + }; + + skins = mkOption { + default = []; + type = types.listOf types.path; + description = + '' + List of paths whose content is copied to the ‘skins’ + subdirectory of the MediaWiki installation. + ''; + }; + + extensions = mkOption { + default = []; + type = types.listOf types.path; + description = + '' + List of paths whose content is copied to the 'extensions' + subdirectory of the MediaWiki installation. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + example = + '' + $wgEnableEmail = false; + ''; + description = '' + Any additional text to be appended to MediaWiki's + configuration file. This is a PHP script. For configuration + settings, see <link xlink:href='https://www.mediawiki.org/wiki/Manual:Configuration_settings'/>. + ''; + }; + + }; + + extraPath = [ mediawikiScripts ]; + + # !!! Need to specify that Apache has a dependency on PostgreSQL! + + startupScript = pkgs.writeScript "mediawiki_startup.sh" + # Initialise the database automagically if we're using a Postgres + # server on localhost. + (optionalString (config.dbType == "postgres" && config.dbServer == "") '' + if ! ${pkgs.postgresql}/bin/psql -l | grep -q ' ${config.dbName} ' ; then + ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole "${config.dbUser}" || true + ${pkgs.postgresql}/bin/createdb "${config.dbName}" -O "${config.dbUser}" + ( echo 'CREATE LANGUAGE plpgsql;' + cat ${mediawikiRoot}/maintenance/postgres/tables.sql + echo 'CREATE TEXT SEARCH CONFIGURATION public.default ( COPY = pg_catalog.english );' + echo COMMIT + ) | ${pkgs.postgresql}/bin/psql -U "${config.dbUser}" "${config.dbName}" + fi + ${php}/bin/php ${mediawikiRoot}/maintenance/update.php + ''); + + robotsEntries = optionalString (config.articleUrlPrefix != "") + '' + User-agent: * + Disallow: ${config.urlPrefix}/ + Disallow: ${config.articleUrlPrefix}/Special:Search + Disallow: ${config.articleUrlPrefix}/Special:Random + ''; + +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mercurial.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mercurial.nix new file mode 100644 index 000000000000..4b8ee2b17ea7 --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mercurial.nix @@ -0,0 +1,75 @@ +{ config, pkgs, lib, ... }: + +let + inherit (pkgs) mercurial; + inherit (lib) mkOption; + + urlPrefix = config.urlPrefix; + + cgi = pkgs.stdenv.mkDerivation { + name = "mercurial-cgi"; + buildCommand = '' + mkdir -p $out + cp -v ${mercurial}/share/cgi-bin/hgweb.cgi $out + sed -i "s|/path/to/repo/or/config|$out/hgweb.config|" $out/hgweb.cgi + echo " + [collections] + ${config.dataDir} = ${config.dataDir} + [web] + style = gitweb + allow_push = * + " > $out/hgweb.config + ''; + }; + +in { + + extraConfig = '' + RewriteEngine on + RewriteRule /(.*) ${cgi}/hgweb.cgi/$1 + + <Location "${urlPrefix}"> + AuthType Basic + AuthName "Mercurial repositories" + AuthUserFile ${config.dataDir}/hgusers + <LimitExcept GET> + Require valid-user + </LimitExcept> + </Location> + <Directory "${cgi}"> + Order allow,deny + Allow from all + AllowOverride All + Options ExecCGI + AddHandler cgi-script .cgi + PassEnv PYTHONPATH + </Directory> + ''; + + robotsEntries = '' + User-agent: * + Disallow: ${urlPrefix} + ''; + + extraServerPath = [ pkgs.python ]; + + globalEnvVars = [ { name = "PYTHONPATH"; value = "${mercurial}/lib/${pkgs.python.libPrefix}/site-packages"; } ]; + + options = { + urlPrefix = mkOption { + default = "/hg"; + description = " + The URL prefix under which the Mercurial service appears. + Use the empty string to have it appear in the server root. + "; + }; + + dataDir = mkOption { + example = "/data/mercurial"; + description = " + Path to the directory that holds the repositories. + "; + }; + }; + +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix new file mode 100644 index 000000000000..4bbd041b6e04 --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix @@ -0,0 +1,188 @@ +# This file defines the options that can be used both for the Apache +# main server configuration, and for the virtual hosts. (The latter +# has additional options that affect the web server as a whole, like +# the user/group to run under.) + +{ forMainServer, lib }: + +with lib; + +{ + + hostName = mkOption { + type = types.str; + default = "localhost"; + description = "Canonical hostname for the server."; + }; + + serverAliases = mkOption { + type = types.listOf types.str; + default = []; + example = ["www.example.org" "www.example.org:8080" "example.org"]; + description = '' + Additional names of virtual hosts served by this virtual host configuration. + ''; + }; + + port = mkOption { + type = types.int; + default = 0; + description = '' + Port for the server. Option will be removed, use <option>listen</option> instead. + ''; + }; + + listen = mkOption { + type = types.listOf (types.submodule ( + { + options = { + port = mkOption { + type = types.int; + description = "port to listen on"; + }; + ip = mkOption { + type = types.string; + default = "*"; + description = "Ip to listen on. 0.0.0.0 for ipv4 only, * for all."; + }; + }; + } )); + description = '' + List of { /* ip: "*"; */ port = 80;} to listen on + ''; + + default = []; + }; + + enableSSL = mkOption { + type = types.bool; + default = false; + description = "Whether to enable SSL (https) support."; + }; + + # Note: sslServerCert and sslServerKey can be left empty, but this + # only makes sense for virtual hosts (they will inherit from the + # main server). + + sslServerCert = mkOption { + type = types.nullOr types.path; + default = null; + example = "/var/host.cert"; + description = "Path to server SSL certificate."; + }; + + sslServerKey = mkOption { + type = types.path; + example = "/var/host.key"; + description = "Path to server SSL certificate key."; + }; + + sslServerChain = mkOption { + type = types.nullOr types.path; + default = null; + example = "/var/ca.pem"; + description = "Path to server SSL chain file."; + }; + + adminAddr = mkOption ({ + type = types.nullOr types.str; + example = "admin@example.org"; + description = "E-mail address of the server administrator."; + } // (if forMainServer then {} else {default = null;})); + + documentRoot = mkOption { + type = types.nullOr types.path; + default = null; + example = "/data/webserver/docs"; + description = '' + The path of Apache's document root directory. If left undefined, + an empty directory in the Nix store will be used as root. + ''; + }; + + servedDirs = mkOption { + type = types.listOf types.attrs; + default = []; + example = [ + { urlPath = "/nix"; + dir = "/home/eelco/Dev/nix-homepage"; + } + ]; + description = '' + This option provides a simple way to serve static directories. + ''; + }; + + servedFiles = mkOption { + type = types.listOf types.attrs; + default = []; + example = [ + { urlPath = "/foo/bar.png"; + file = "/home/eelco/some-file.png"; + } + ]; + description = '' + This option provides a simple way to serve individual, static files. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + example = '' + <Directory /home> + Options FollowSymlinks + AllowOverride All + </Directory> + ''; + description = '' + These lines go to httpd.conf verbatim. They will go after + directories and directory aliases defined by default. + ''; + }; + + extraSubservices = mkOption { + type = types.listOf types.unspecified; + default = []; + description = "Extra subservices to enable in the webserver."; + }; + + enableUserDir = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable serving <filename>~/public_html</filename> as + <literal>/~<replaceable>username</replaceable></literal>. + ''; + }; + + globalRedirect = mkOption { + type = types.nullOr types.str; + default = null; + example = http://newserver.example.org/; + description = '' + If set, all requests for this host are redirected permanently to + the given URL. + ''; + }; + + logFormat = mkOption { + type = types.str; + default = "common"; + example = "combined"; + description = '' + Log format for Apache's log files. Possible values are: combined, common, referer, agent. + ''; + }; + + robotsEntries = mkOption { + type = types.lines; + default = ""; + example = "Disallow: /foo/"; + description = '' + Specification of pages to be ignored by web crawlers. See <link + xlink:href='http://www.robotstxt.org/'/> for details. + ''; + }; + +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/phabricator.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/phabricator.nix new file mode 100644 index 000000000000..efd4a7b5f0fb --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/phabricator.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + phabricatorRoot = pkgs.phabricator; +in { + + enablePHP = true; + extraApacheModules = [ "mod_rewrite" ]; + DocumentRoot = "${phabricatorRoot}/phabricator/webroot"; + + options = { + git = mkOption { + default = true; + description = "Enable git repositories."; + }; + mercurial = mkOption { + default = true; + description = "Enable mercurial repositories."; + }; + subversion = mkOption { + default = true; + description = "Enable subversion repositories."; + }; + }; + + extraConfig = '' + DocumentRoot ${phabricatorRoot}/phabricator/webroot + + RewriteEngine on + RewriteRule ^/rsrc/(.*) - [L,QSA] + RewriteRule ^/favicon.ico - [L,QSA] + RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA] + ''; + + extraServerPath = [ + "${pkgs.which}" + "${pkgs.diffutils}" + ] ++ + (if config.mercurial then ["${pkgs.mercurial}"] else []) ++ + (if config.subversion then ["${pkgs.subversion.out}"] else []) ++ + (if config.git then ["${pkgs.git}"] else []); + + startupScript = pkgs.writeScript "activatePhabricator" '' + mkdir -p /var/repo + chown wwwrun /var/repo + ''; + +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix new file mode 100644 index 000000000000..a883bb2b3433 --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix @@ -0,0 +1,103 @@ +{ config, pkgs, serverInfo, lib, ... }: + +let + extraWorkersProperties = lib.optionalString (config ? extraWorkersProperties) config.extraWorkersProperties; + + workersProperties = pkgs.writeText "workers.properties" '' +# Define list of workers that will be used +# for mapping requests +# The configuration directives are valid +# for the mod_jk version 1.2.18 and later +# +worker.list=loadbalancer,status + +# Define Node1 +# modify the host as your host IP or DNS name. +worker.node1.port=8009 +worker.node1.host=localhost +worker.node1.type=ajp13 +worker.node1.lbfactor=1 + +# Load-balancing behaviour +worker.loadbalancer.type=lb +worker.loadbalancer.balance_workers=node1 + +# Status worker for managing load balancer +worker.status.type=status + +${extraWorkersProperties} + ''; +in +{ + + options = { + extraWorkersProperties = lib.mkOption { + default = ""; + description = "Additional configuration for the workers.properties file."; + }; + }; + + extraModules = [ + { name = "jk"; path = "${pkgs.tomcat_connectors}/modules/mod_jk.so"; } + ]; + + extraConfig = '' +# Where to find workers.properties +JkWorkersFile ${workersProperties} + +# Where to put jk logs +JkLogFile ${serverInfo.serverConfig.logDir}/mod_jk.log + +# Set the jk log level [debug/error/info] +JkLogLevel info + +# Select the log format +JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" + +# JkOptions indicates to send SSK KEY SIZE +# Note: Changed from +ForwardURICompat. +# See http://tomcat.apache.org/security-jk.html +JkOptions +ForwardKeySize +ForwardURICompatUnparsed -ForwardDirectories + +# JkRequestLogFormat +JkRequestLogFormat "%w %V %T" + +# Mount your applications +JkMount /__application__/* loadbalancer + +# You can use external file for mount points. +# It will be checked for updates each 60 seconds. +# The format of the file is: /url=worker +# /examples/*=loadbalancer +#JkMountFile uriworkermap.properties + +# Add shared memory. +# This directive is present with 1.2.10 and +# later versions of mod_jk, and is needed for +# for load balancing to work properly +# Note: Replaced JkShmFile logs/jk.shm due to SELinux issues. Refer to +# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=225452 +JkShmFile ${serverInfo.serverConfig.stateDir}/jk.shm + +# Static files in all Tomcat webapp context directories are served by apache +JkAutoAlias /var/tomcat/webapps + +# All requests go to worker by default +JkMount /* loadbalancer +# Serve some static files using httpd +#JkUnMount /*.html loadbalancer +#JkUnMount /*.jpg loadbalancer +#JkUnMount /*.gif loadbalancer +#JkUnMount /*.css loadbalancer +#JkUnMount /*.png loadbalancer +#JkUnMount /*.js loadbalancer + +# Add jkstatus for managing runtime data +<Location /jkstatus/> +JkMount status +Order deny,allow +Deny from all +Allow from 127.0.0.1 +</Location> + ''; +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/trac.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/trac.nix new file mode 100644 index 000000000000..28b411a64b6f --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/trac.nix @@ -0,0 +1,121 @@ +{ config, lib, pkgs, serverInfo, ... }: + +with lib; + +let + + # Build a Subversion instance with Apache modules and Swig/Python bindings. + subversion = pkgs.subversion.override { + bdbSupport = true; + httpServer = true; + pythonBindings = true; + apacheHttpd = httpd; + }; + + httpd = serverInfo.serverConfig.package; + + versionPre24 = versionOlder httpd.version "2.4"; + +in + +{ + + options = { + + projectsLocation = mkOption { + description = "URL path in which Trac projects can be accessed"; + default = "/projects"; + }; + + projects = mkOption { + description = "List of projects that should be provided by Trac. If they are not defined yet empty projects are created."; + default = []; + example = + [ { identifier = "myproject"; + name = "My Project"; + databaseURL="postgres://root:password@/tracdb"; + subversionRepository="/data/subversion/myproject"; + } + ]; + }; + + user = mkOption { + default = "wwwrun"; + description = "User account under which Trac runs."; + }; + + group = mkOption { + default = "wwwrun"; + description = "Group under which Trac runs."; + }; + + ldapAuthentication = { + enable = mkOption { + default = false; + description = "Enable the ldap authentication in trac"; + }; + + url = mkOption { + default = "ldap://127.0.0.1/dc=example,dc=co,dc=ke?uid?sub?(objectClass=inetOrgPerson)"; + description = "URL of the LDAP authentication"; + }; + + name = mkOption { + default = "Trac server"; + description = "AuthName"; + }; + }; + + }; + + extraModules = singleton + { name = "python"; path = "${pkgs.mod_python}/modules/mod_python.so"; }; + + extraConfig = '' + <Location ${config.projectsLocation}> + SetHandler mod_python + PythonHandler trac.web.modpython_frontend + PythonOption TracEnvParentDir /var/trac/projects + PythonOption TracUriRoot ${config.projectsLocation} + PythonOption PYTHON_EGG_CACHE /var/trac/egg-cache + </Location> + ${if config.ldapAuthentication.enable then '' + <LocationMatch "^${config.projectsLocation}[^/]+/login$"> + AuthType Basic + AuthName "${config.ldapAuthentication.name}" + AuthBasicProvider "ldap" + AuthLDAPURL "${config.ldapAuthentication.url}" + ${if versionPre24 then "authzldapauthoritative Off" else ""} + require valid-user + </LocationMatch> + '' else ""} + ''; + + globalEnvVars = singleton + { name = "PYTHONPATH"; + value = + makeSearchPathOutput "lib" "lib/${pkgs.python.libPrefix}/site-packages" + [ pkgs.mod_python + pkgs.pythonPackages.trac + pkgs.pythonPackages.setuptools + pkgs.pythonPackages.genshi + pkgs.pythonPackages.psycopg2 + subversion + ]; + }; + + startupScript = pkgs.writeScript "activateTrac" '' + mkdir -p /var/trac + chown ${config.user}:${config.group} /var/trac + + ${concatMapStrings (project: + '' + if [ ! -d /var/trac/${project.identifier} ] + then + export PYTHONPATH=${pkgs.pythonPackages.psycopg2}/lib/${pkgs.python.libPrefix}/site-packages + ${pkgs.pythonPackages.trac}/bin/trac-admin /var/trac/${project.identifier} initenv "${project.name}" "${project.databaseURL}" svn "${project.subversionRepository}" + fi + '' ) (config.projects)} + ''; + +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/wordpress.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/wordpress.nix new file mode 100644 index 000000000000..c68bfd25f6a8 --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/wordpress.nix @@ -0,0 +1,285 @@ +{ config, lib, pkgs, serverInfo, ... }: +# http://codex.wordpress.org/Hardening_WordPress + +with lib; + +let + # Our bare-bones wp-config.php file using the above settings + wordpressConfig = pkgs.writeText "wp-config.php" '' + <?php + define('DB_NAME', '${config.dbName}'); + define('DB_USER', '${config.dbUser}'); + define('DB_PASSWORD', file_get_contents('${config.dbPasswordFile}')); + define('DB_HOST', '${config.dbHost}'); + define('DB_CHARSET', 'utf8'); + $table_prefix = '${config.tablePrefix}'; + define('AUTOMATIC_UPDATER_DISABLED', true); + ${config.extraConfig} + if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); + require_once(ABSPATH . 'wp-settings.php'); + ''; + + # .htaccess to support pretty URLs + htaccess = pkgs.writeText "htaccess" '' + <IfModule mod_rewrite.c> + RewriteEngine On + RewriteBase / + RewriteRule ^index\.php$ - [L] + + # add a trailing slash to /wp-admin + RewriteRule ^wp-admin$ wp-admin/ [R=301,L] + + RewriteCond %{REQUEST_FILENAME} -f [OR] + RewriteCond %{REQUEST_FILENAME} -d + RewriteRule ^ - [L] + RewriteRule ^(wp-(content|admin|includes).*) $1 [L] + RewriteRule ^(.*\.php)$ $1 [L] + RewriteRule . index.php [L] + </IfModule> + + ${config.extraHtaccess} + ''; + + # WP translation can be found here: + # https://github.com/nixcloud/wordpress-translations + supportedLanguages = { + en_GB = { revision="d6c005372a5318fd758b710b77a800c86518be13"; sha256="0qbbsi87k47q4rgczxx541xz4z4f4fr49hw4lnaxkdsf5maz8p9p"; }; + de_DE = { revision="3c62955c27baaae98fd99feb35593d46562f4736"; sha256="1shndgd11dk836dakrjlg2arwv08vqx6j4xjh4jshvwmjab6ng6p"; }; + zh_ZN = { revision="12b9f811e8cae4b6ee41de343d35deb0a8fdda6d"; sha256="1339ggsxh0g6lab37jmfxicsax4h702rc3fsvv5azs7mcznvwh47"; }; + fr_FR = { revision="688c8b1543e3d38d9e8f57e0a6f2a2c3c8b588bd"; sha256="1j41iak0i6k7a4wzyav0yrllkdjjskvs45w53db8vfm8phq1n014"; }; + }; + + downloadLanguagePack = language: revision: sha256s: + pkgs.stdenv.mkDerivation rec { + name = "wp_${language}"; + src = pkgs.fetchFromGitHub { + owner = "nixcloud"; + repo = "wordpress-translations"; + rev = revision; + sha256 = sha256s; + }; + installPhase = "mkdir -p $out; cp -R * $out/"; + }; + + selectedLanguages = map (lang: downloadLanguagePack lang supportedLanguages.${lang}.revision supportedLanguages.${lang}.sha256) (config.languages); + + # The wordpress package itself + wordpressRoot = pkgs.stdenv.mkDerivation rec { + name = "wordpress"; + src = config.package; + installPhase = '' + mkdir -p $out + # copy all the wordpress files we downloaded + cp -R * $out/ + + # symlink the wordpress config + ln -s ${wordpressConfig} $out/wp-config.php + # symlink custom .htaccess + ln -s ${htaccess} $out/.htaccess + # symlink uploads directory + ln -s ${config.wordpressUploads} $out/wp-content/uploads + + # remove bundled plugins(s) coming with wordpress + rm -Rf $out/wp-content/plugins/* + # remove bundled themes(s) coming with wordpress + rm -Rf $out/wp-content/themes/* + + # copy additional theme(s) + ${concatMapStrings (theme: "cp -r ${theme} $out/wp-content/themes/${theme.name}\n") config.themes} + # copy additional plugin(s) + ${concatMapStrings (plugin: "cp -r ${plugin} $out/wp-content/plugins/${plugin.name}\n") (config.plugins) } + + # symlink additional translation(s) + mkdir -p $out/wp-content/languages + ${concatMapStrings (language: "ln -s ${language}/*.mo ${language}/*.po $out/wp-content/languages/\n") (selectedLanguages) } + ''; + }; + +in + +{ + + # And some httpd extraConfig to make things work nicely + extraConfig = '' + <Directory ${wordpressRoot}> + DirectoryIndex index.php + Allow from * + Options FollowSymLinks + AllowOverride All + </Directory> + ''; + + enablePHP = true; + + options = { + package = mkOption { + type = types.path; + default = pkgs.wordpress; + description = '' + Path to the wordpress sources. + Upgrading? We have a test! nix-build ./nixos/tests/wordpress.nix + ''; + }; + dbHost = mkOption { + default = "localhost"; + description = "The location of the database server."; + example = "localhost"; + }; + dbName = mkOption { + default = "wordpress"; + description = "Name of the database that holds the Wordpress data."; + example = "localhost"; + }; + dbUser = mkOption { + default = "wordpress"; + description = "The dbUser, read: the username, for the database."; + example = "wordpress"; + }; + dbPassword = mkOption { + default = "wordpress"; + description = '' + The mysql password to the respective dbUser. + + Warning: this password is stored in the world-readable Nix store. It's + recommended to use the $dbPasswordFile option since that gives you control over + the security of the password. $dbPasswordFile also takes precedence over $dbPassword. + ''; + example = "wordpress"; + }; + dbPasswordFile = mkOption { + type = types.str; + default = toString (pkgs.writeTextFile { + name = "wordpress-dbpassword"; + text = config.dbPassword; + }); + example = "/run/keys/wordpress-dbpassword"; + description = '' + Path to a file that contains the mysql password to the respective dbUser. + The file should be readable by the user: config.services.httpd.user. + + $dbPasswordFile takes precedence over the $dbPassword option. + + This defaults to a file in the world-readable Nix store that contains the value + of the $dbPassword option. It's recommended to override this with a path not in + the Nix store. Tip: use nixops key management: + <link xlink:href='https://nixos.org/nixops/manual/#idm140737318306400'/> + ''; + }; + tablePrefix = mkOption { + default = "wp_"; + description = '' + The $table_prefix is the value placed in the front of your database tables. Change the value if you want to use something other than wp_ for your database prefix. Typically this is changed if you are installing multiple WordPress blogs in the same database. See <link xlink:href='http://codex.wordpress.org/Editing_wp-config.php#table_prefix'/>. + ''; + }; + wordpressUploads = mkOption { + default = "/data/uploads"; + description = '' + This directory is used for uploads of pictures and must be accessible (read: owned) by the httpd running user. The directory passed here is automatically created and permissions are given to the httpd running user. + ''; + }; + plugins = mkOption { + default = []; + type = types.listOf types.path; + description = + '' + List of path(s) to respective plugin(s) which are symlinked from the 'plugins' directory. Note: These plugins need to be packaged before use, see example. + ''; + example = '' + # Wordpress plugin 'akismet' installation example + akismetPlugin = pkgs.stdenv.mkDerivation { + name = "akismet-plugin"; + # Download the theme from the wordpress site + src = pkgs.fetchurl { + url = https://downloads.wordpress.org/plugin/akismet.3.1.zip; + sha256 = "1i4k7qyzna08822ncaz5l00wwxkwcdg4j9h3z2g0ay23q640pclg"; + }; + # We need unzip to build this package + buildInputs = [ pkgs.unzip ]; + # Installing simply means copying all files to the output directory + installPhase = "mkdir -p $out; cp -R * $out/"; + }; + + And then pass this theme to the themes list like this: + plugins = [ akismetPlugin ]; + ''; + }; + themes = mkOption { + default = []; + type = types.listOf types.path; + description = + '' + List of path(s) to respective theme(s) which are symlinked from the 'theme' directory. Note: These themes need to be packaged before use, see example. + ''; + example = '' + # For shits and giggles, let's package the responsive theme + responsiveTheme = pkgs.stdenv.mkDerivation { + name = "responsive-theme"; + # Download the theme from the wordpress site + src = pkgs.fetchurl { + url = http://wordpress.org/themes/download/responsive.1.9.7.6.zip; + sha256 = "06i26xlc5kdnx903b1gfvnysx49fb4kh4pixn89qii3a30fgd8r8"; + }; + # We need unzip to build this package + buildInputs = [ pkgs.unzip ]; + # Installing simply means copying all files to the output directory + installPhase = "mkdir -p $out; cp -R * $out/"; + }; + + And then pass this theme to the themes list like this: + themes = [ responsiveTheme ]; + ''; + }; + languages = mkOption { + default = []; + description = "Installs wordpress language packs based on the list, see wordpress.nix for possible translations."; + example = "[ \"en_GB\" \"de_DE\" ];"; + }; + extraConfig = mkOption { + type = types.lines; + default = ""; + example = + '' + define( 'AUTOSAVE_INTERVAL', 60 ); // Seconds + ''; + description = '' + Any additional text to be appended to Wordpress's wp-config.php + configuration file. This is a PHP script. For configuration + settings, see <link xlink:href='http://codex.wordpress.org/Editing_wp-config.php'/>. + ''; + }; + extraHtaccess = mkOption { + default = ""; + example = + '' + php_value upload_max_filesize 20M + php_value post_max_size 20M + ''; + description = '' + Any additional text to be appended to Wordpress's .htaccess file. + ''; + }; + }; + + documentRoot = wordpressRoot; + + # FIXME adding the user has to be done manually for the time being + startupScript = pkgs.writeScript "init-wordpress.sh" '' + #!/bin/sh + mkdir -p ${config.wordpressUploads} + chown ${serverInfo.serverConfig.user} ${config.wordpressUploads} + + # we should use systemd dependencies here + if [ ! -d ${serverInfo.fullConfig.services.mysql.dataDir}/${config.dbName} ]; then + echo "Need to create the database '${config.dbName}' and grant permissions to user named '${config.dbUser}'." + # Wait until MySQL is up + while [ ! -e ${serverInfo.fullConfig.services.mysql.pidDir}/mysqld.pid ]; do + sleep 1 + done + ${pkgs.mysql}/bin/mysql -e 'CREATE DATABASE ${config.dbName};' + ${pkgs.mysql}/bin/mysql -e "GRANT ALL ON ${config.dbName}.* TO ${config.dbUser}@localhost IDENTIFIED BY \"$(cat ${config.dbPasswordFile})\";" + else + echo "Good, no need to do anything database related." + fi + ''; +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/zabbix.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/zabbix.nix new file mode 100644 index 000000000000..cab16593bcbc --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/zabbix.nix @@ -0,0 +1,84 @@ +{ config, lib, pkgs, serverInfo, ... }: + +with lib; + +let + + # The Zabbix PHP frontend needs to be able to write its + # configuration settings (the connection info to the database) to + # the "conf" subdirectory. So symlink $out/conf to some directory + # outside of the Nix store where we want to keep this stateful info. + # Note that different instances of the frontend will therefore end + # up with their own copies of the PHP sources. !!! Alternatively, + # we could generate zabbix.conf.php declaratively. + zabbixPHP = pkgs.runCommand "${pkgs.zabbix.server.name}-php" {} + '' + cp -rs ${pkgs.zabbix.server}/share/zabbix/php "$out" + chmod -R u+w $out + ln -s "${if config.configFile == null + then "${config.stateDir}/zabbix.conf.php" + else config.configFile}" "$out/conf/zabbix.conf.php" + ''; + +in + +{ + + enablePHP = true; + + phpOptions = + '' + post_max_size = 32M + max_execution_time = 300 + max_input_time = 300 + ''; + + extraConfig = '' + Alias ${config.urlPrefix}/ ${zabbixPHP}/ + + <Directory ${zabbixPHP}> + DirectoryIndex index.php + Order deny,allow + Allow from * + </Directory> + ''; + + startupScript = pkgs.writeScript "zabbix-startup-hook" '' + mkdir -p ${config.stateDir} + chown -R ${serverInfo.serverConfig.user} ${config.stateDir} + ''; + + # The frontend needs "ps" to find out whether zabbix_server is running. + extraServerPath = [ pkgs.procps ]; + + options = { + + urlPrefix = mkOption { + default = "/zabbix"; + description = " + The URL prefix under which the Zabbix service appears. + Use the empty string to have it appear in the server root. + "; + }; + + configFile = mkOption { + default = null; + type = types.nullOr types.path; + description = '' + The configuration file (zabbix.conf.php) which contains the database + connection settings. If not set, the configuration settings will created + by the web installer. + ''; + }; + + stateDir = mkOption { + default = "/var/lib/zabbix/frontend"; + description = " + Directory where the dynamically generated configuration data + of the PHP frontend will be stored. + "; + }; + + }; + +} |