diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 8d63a03dd05..45e554a2bc5 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -780,6 +780,7 @@
./services/web-apps/icingaweb2/module-monitoring.nix
./services/web-apps/limesurvey.nix
./services/web-apps/mattermost.nix
+ ./services/web-apps/mediawiki.nix
./services/web-apps/miniflux.nix
./services/web-apps/nextcloud.nix
./services/web-apps/nexus.nix
diff --git a/nixos/modules/services/web-apps/mediawiki.nix b/nixos/modules/services/web-apps/mediawiki.nix
new file mode 100644
index 00000000000..5bd5977e592
--- /dev/null
+++ b/nixos/modules/services/web-apps/mediawiki.nix
@@ -0,0 +1,473 @@
+{ config, pkgs, lib, ... }:
+
+let
+
+ inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption;
+ inherit (lib) concatStringsSep literalExample mapAttrsToList optional optionals optionalString types;
+
+ cfg = config.services.mediawiki;
+ fpm = config.services.phpfpm.pools.mediawiki;
+ user = "mediawiki";
+ group = config.services.httpd.group;
+ cacheDir = "/var/cache/mediawiki";
+ stateDir = "/var/lib/mediawiki";
+
+ pkg = pkgs.stdenv.mkDerivation rec {
+ pname = "mediawiki-full";
+ version = src.version;
+ src = cfg.package;
+
+ installPhase = ''
+ mkdir -p $out
+ cp -r * $out/
+
+ rm -rf $out/share/mediawiki/skins/*
+ rm -rf $out/share/mediawiki/extensions/*
+
+ ${concatStringsSep "\n" (mapAttrsToList (k: v: ''
+ ln -s ${v} $out/share/mediawiki/skins/${k}
+ '') cfg.skins)}
+
+ ${concatStringsSep "\n" (mapAttrsToList (k: v: ''
+ ln -s ${v} $out/share/mediawiki/extensions/${k}
+ '') cfg.extensions)}
+ '';
+ };
+
+ mediawikiScripts = pkgs.runCommand "mediawiki-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 ${pkgs.php}/bin/php $out/bin/mediawiki-$(basename $i .php) \
+ --set MEDIAWIKI_CONFIG ${mediawikiConfig} \
+ --add-flags ${pkg}/share/mediawiki/maintenance/$i
+ done
+ '';
+
+ mediawikiConfig = pkgs.writeText "LocalSettings.php" ''
+ database.user.
+ '';
+ };
+
+ tablePrefix = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ If you only have access to a single database and wish to install more than
+ one version of MediaWiki, or have other applications that also use the
+ database, you can give the table names a unique prefix to stop any naming
+ conflicts or confusion.
+ See .
+ '';
+ };
+
+ socket = mkOption {
+ type = types.nullOr types.path;
+ default = if cfg.database.createLocally then "/run/mysqld/mysqld.sock" else null;
+ defaultText = "/run/mysqld/mysqld.sock";
+ description = "Path to the unix socket file to use for authentication.";
+ };
+
+ createLocally = mkOption {
+ type = types.bool;
+ default = cfg.database.type == "mysql";
+ defaultText = "true";
+ description = ''
+ Create the database and database user locally.
+ This currently only applies if database type "mysql" is selected.
+ '';
+ };
+ };
+
+ virtualHost = mkOption {
+ type = types.submodule ({
+ options = import ../web-servers/apache-httpd/per-server-options.nix {
+ inherit lib;
+ forMainServer = false;
+ };
+ });
+ example = literalExample ''
+ {
+ hostName = "mediawiki.example.org";
+ enableSSL = true;
+ adminAddr = "webmaster@example.org";
+ sslServerCert = "/var/lib/acme/mediawiki.example.org/full.pem";
+ sslServerKey = "/var/lib/acme/mediawiki.example.org/key.pem";
+ }
+ '';
+ description = ''
+ Apache configuration can be done by adapting .
+ See for further information.
+ '';
+ };
+
+ poolConfig = mkOption {
+ type = types.lines;
+ default = ''
+ pm = dynamic
+ pm.max_children = 32
+ pm.start_servers = 2
+ pm.min_spare_servers = 2
+ pm.max_spare_servers = 4
+ pm.max_requests = 500
+ '';
+ description = ''
+ Options for MediaWiki's PHP pool. See the documentation on php-fpm.conf
+ for details on configuration directives.
+ '';
+ };
+
+ extraConfig = mkOption {
+ type = types.lines;
+ description = ''
+ Any additional text to be appended to MediaWiki's
+ LocalSettings.php configuration file. For configuration
+ settings, see .
+ '';
+ default = "";
+ example = ''
+ $wgEnableEmail = false;
+ '';
+ };
+
+ };
+ };
+
+ # implementation
+ config = mkIf cfg.enable {
+
+ assertions = [
+ { assertion = cfg.database.createLocally -> cfg.database.type == "mysql";
+ message = "services.mediawiki.createLocally is currently only supported for database type 'mysql'";
+ }
+ { assertion = cfg.database.createLocally -> cfg.database.user == user;
+ message = "services.mediawiki.database.user must be set to ${user} if services.mediawiki.database.createLocally is set true";
+ }
+ { assertion = cfg.database.createLocally -> cfg.database.socket != null;
+ message = "services.mediawiki.database.socket must be set if services.mediawiki.database.createLocally is set to true";
+ }
+ { assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
+ message = "a password cannot be specified if services.mediawiki.database.createLocally is set to true";
+ }
+ ];
+
+ services.mediawiki.skins = {
+ MonoBook = "${cfg.package}/share/mediawiki/skins/MonoBook";
+ Timeless = "${cfg.package}/share/mediawiki/skins/Timeless";
+ Vector = "${cfg.package}/share/mediawiki/skins/Vector";
+ };
+
+ services.mysql = mkIf cfg.database.createLocally {
+ enable = true;
+ package = mkDefault pkgs.mariadb;
+ ensureDatabases = [ cfg.database.name ];
+ ensureUsers = [
+ { name = cfg.database.user;
+ ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
+ }
+ ];
+ };
+
+ services.phpfpm.pools.mediawiki = {
+ listen = "/run/phpfpm/mediawiki.sock";
+ extraConfig = ''
+ listen.owner = ${config.services.httpd.user}
+ listen.group = ${config.services.httpd.group}
+ user = ${user}
+ group = ${group}
+
+ env[MEDIAWIKI_CONFIG] = ${mediawikiConfig}
+
+ ${cfg.poolConfig}
+ '';
+ };
+
+ services.httpd = {
+ enable = true;
+ adminAddr = mkDefault cfg.virtualHost.adminAddr;
+ extraModules = [ "proxy_fcgi" ];
+ virtualHosts = [ (mkMerge [
+ cfg.virtualHost {
+ documentRoot = mkForce "${pkg}/share/mediawiki";
+ extraConfig = ''
+
+
+
+ SetHandler "proxy:unix:${fpm.listen}|fcgi://localhost/"
+
+
+
+ Require all granted
+ DirectoryIndex index.php
+ AllowOverride All
+
+ '' + optionalString (cfg.uploadsDir != null) ''
+ Alias "/images" "${cfg.uploadsDir}"
+
+ Require all granted
+
+ '';
+ }
+ ]) ];
+ };
+
+ systemd.tmpfiles.rules = [
+ "d '${stateDir}' 0750 ${user} ${group} - -"
+ "d '${cacheDir}' 0750 ${user} ${group} - -"
+ ] ++ optionals (cfg.uploadsDir != null) [
+ "d '${cfg.uploadsDir}' 0750 ${user} ${group} - -"
+ "Z '${cfg.uploadsDir}' 0750 ${user} ${group} - -"
+ ];
+
+ systemd.services.mediawiki-init = {
+ wantedBy = [ "multi-user.target" ];
+ before = [ "phpfpm-mediawiki.service" ];
+ after = optional cfg.database.createLocally "mysql.service";
+ script = ''
+ if ! test -e "${stateDir}/secret.key"; then
+ tr -dc A-Za-z0-9 /dev/null | head -c 64 > ${stateDir}/secret.key
+ fi
+
+ echo "exit( wfGetDB( DB_MASTER )->tableExists( 'user' ) ? 1 : 0 );" | \
+ ${pkgs.php}/bin/php ${pkg}/share/mediawiki/maintenance/eval.php --conf ${mediawikiConfig} && \
+ ${pkgs.php}/bin/php ${pkg}/share/mediawiki/maintenance/install.php \
+ --confpath /tmp \
+ --scriptpath / \
+ --dbserver ${cfg.database.host}${optionalString (cfg.database.socket != null) ":${cfg.database.socket}"} \
+ --dbport ${toString cfg.database.port} \
+ --dbname ${cfg.database.name} \
+ ${optionalString (cfg.database.tablePrefix != null) "--dbprefix ${cfg.database.tablePrefix}"} \
+ --dbuser ${cfg.database.user} \
+ ${optionalString (cfg.database.passwordFile != null) "--dbpassfile ${cfg.database.passwordFile}"} \
+ --passfile ${cfg.passwordFile} \
+ ${cfg.name} \
+ admin
+
+ ${pkgs.php}/bin/php ${pkg}/share/mediawiki/maintenance/update.php --conf ${mediawikiConfig} --quick
+ '';
+
+ serviceConfig = {
+ Type = "oneshot";
+ User = user;
+ Group = group;
+ PrivateTmp = true;
+ };
+ };
+
+ systemd.services.httpd.after = optional (cfg.database.createLocally && cfg.database.type == "mysql") "mysql.service";
+
+ users.users.${user}.group = group;
+
+ environment.systemPackages = [ mediawikiScripts ];
+ };
+}
diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
deleted file mode 100644
index 6234478014c..00000000000
--- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
+++ /dev/null
@@ -1,349 +0,0 @@
-{ 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"
- ''
-
- '';
-
- # 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}
-
-
- ${allGranted}
- Options -Indexes
-
- ''}
-
- ${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]
- ''}
-
-
- ${allGranted}
- DirectoryIndex index.php
-
-
- ${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 .
- '';
- };
-
- };
-
- 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/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index bc5f18d22bc..03b5d8c9854 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -146,6 +146,7 @@ in
mailcatcher = handleTest ./mailcatcher.nix {};
mathics = handleTest ./mathics.nix {};
matrix-synapse = handleTest ./matrix-synapse.nix {};
+ mediawiki = handleTest ./mediawiki.nix {};
memcached = handleTest ./memcached.nix {};
mesos = handleTest ./mesos.nix {};
miniflux = handleTest ./miniflux.nix {};
diff --git a/nixos/tests/mediawiki.nix b/nixos/tests/mediawiki.nix
new file mode 100644
index 00000000000..6293e8a2f46
--- /dev/null
+++ b/nixos/tests/mediawiki.nix
@@ -0,0 +1,19 @@
+import ./make-test.nix ({ pkgs, lib, ... }: {
+ name = "mediawiki";
+ meta.maintainers = [ lib.maintainers.aanderse ];
+
+ machine =
+ { ... }:
+ { services.mediawiki.enable = true;
+ services.mediawiki.virtualHost.hostName = "localhost";
+ services.mediawiki.virtualHost.adminAddr = "root@example.com";
+ services.mediawiki.passwordFile = pkgs.writeText "password" "correcthorsebatterystaple";
+ };
+
+ testScript = ''
+ startAll;
+
+ $machine->waitForUnit('phpfpm-mediawiki.service');
+ $machine->succeed('curl -L http://localhost/') =~ /MediaWiki has been installed/ or die;
+ '';
+})