at master 25 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7 8let 9 10 inherit (lib) 11 mkDefault 12 mkEnableOption 13 mkPackageOption 14 mkForce 15 mkIf 16 mkMerge 17 mkOption 18 ; 19 inherit (lib) 20 concatStringsSep 21 literalExpression 22 mapAttrsToList 23 optional 24 optionals 25 optionalString 26 types 27 ; 28 29 cfg = config.services.mediawiki; 30 fpm = config.services.phpfpm.pools.mediawiki; 31 user = "mediawiki"; 32 group = 33 if cfg.webserver == "apache" then 34 config.services.httpd.group 35 else if cfg.webserver == "nginx" then 36 config.services.nginx.group 37 else 38 "mediawiki"; 39 40 cacheDir = "/var/cache/mediawiki"; 41 stateDir = "/var/lib/mediawiki"; 42 43 # https://www.mediawiki.org/wiki/Compatibility 44 php = pkgs.php82; 45 46 pkg = pkgs.stdenv.mkDerivation rec { 47 pname = "mediawiki-full"; 48 inherit (src) version; 49 src = cfg.package; 50 51 installPhase = '' 52 mkdir -p $out 53 cp -r * $out/ 54 55 # try removing directories before symlinking to allow overwriting any builtin extension or skin 56 ${concatStringsSep "\n" ( 57 mapAttrsToList (k: v: '' 58 rm -rf $out/share/mediawiki/skins/${k} 59 ln -s ${v} $out/share/mediawiki/skins/${k} 60 '') cfg.skins 61 )} 62 63 ${concatStringsSep "\n" ( 64 mapAttrsToList (k: v: '' 65 rm -rf $out/share/mediawiki/extensions/${k} 66 ln -s ${ 67 if v != null then v else "$src/share/mediawiki/extensions/${k}" 68 } $out/share/mediawiki/extensions/${k} 69 '') cfg.extensions 70 )} 71 ''; 72 }; 73 74 mediawikiScripts = 75 pkgs.runCommand "mediawiki-scripts" 76 { 77 nativeBuildInputs = [ pkgs.makeWrapper ]; 78 preferLocalBuild = true; 79 } 80 '' 81 mkdir -p $out/bin 82 makeWrapper ${php}/bin/php $out/bin/mediawiki-maintenance \ 83 --set MEDIAWIKI_CONFIG ${mediawikiConfig} \ 84 --add-flags ${pkg}/share/mediawiki/maintenance/run.php 85 86 for i in changePassword createAndPromote deleteUserEmail resetUserEmail userOptions edit nukePage update importDump run; do 87 script="$out/bin/mediawiki-$i" 88 cat <<'EOF' >"$script" 89 #!${pkgs.runtimeShell} 90 become=(exec) 91 if [[ "$(id -u)" != ${user} ]]; then 92 become=(exec /run/wrappers/bin/sudo -u ${user} --) 93 fi 94 "${"$"}{become[@]}" ${placeholder "out"}/bin/mediawiki-maintenance \ 95 EOF 96 if [[ "$i" != "run" ]]; then 97 echo " ${pkg}/share/mediawiki/maintenance/$i.php \"\$@\"" >>"$script" 98 else 99 echo " ${pkg}/share/mediawiki/maintenance/\$1.php \"\''${@:2}\"" >>"$script" 100 fi 101 chmod +x "$script" 102 done 103 ''; 104 105 dbAddr = 106 if cfg.database.socket == null then 107 "${cfg.database.host}:${toString cfg.database.port}" 108 else if cfg.database.type == "mysql" then 109 "${cfg.database.host}:${cfg.database.socket}" 110 else if cfg.database.type == "postgres" then 111 "${cfg.database.socket}" 112 else 113 throw "Unsupported database type: ${cfg.database.type} for socket: ${cfg.database.socket}"; 114 115 mediawikiConfig = pkgs.writeTextFile { 116 name = "LocalSettings.php"; 117 checkPhase = '' 118 ${php}/bin/php --syntax-check "$target" 119 ''; 120 text = '' 121 <?php 122 # Protect against web entry 123 if ( !defined( 'MEDIAWIKI' ) ) { 124 exit; 125 } 126 127 $wgSitename = "${cfg.name}"; 128 $wgMetaNamespace = false; 129 130 ## The URL base path to the directory containing the wiki; 131 ## defaults for all runtime URL paths are based off of this. 132 ## For more information on customizing the URLs 133 ## (like /w/index.php/Page_title to /wiki/Page_title) please see: 134 ## https://www.mediawiki.org/wiki/Manual:Short_URL 135 $wgScriptPath = "${lib.optionalString (cfg.webserver == "nginx") "/w"}"; 136 137 ## The protocol and server name to use in fully-qualified URLs 138 $wgServer = "${cfg.url}"; 139 140 ## The URL path to static resources (images, scripts, etc.) 141 $wgResourceBasePath = $wgScriptPath; 142 143 ${lib.optionalString (cfg.webserver == "nginx") '' 144 $wgArticlePath = "/wiki/$1"; 145 $wgUsePathInfo = true; 146 ''} 147 148 ## The URL path to the logo. Make sure you change this from the default, 149 ## or else you'll overwrite your logo when you upgrade! 150 $wgLogo = "$wgResourceBasePath/resources/assets/wiki.png"; 151 152 ## UPO means: this is also a user preference option 153 154 $wgEnableEmail = true; 155 $wgEnableUserEmail = true; # UPO 156 157 $wgPasswordSender = "${cfg.passwordSender}"; 158 159 $wgEnotifUserTalk = false; # UPO 160 $wgEnotifWatchlist = false; # UPO 161 $wgEmailAuthentication = true; 162 163 ## Database settings 164 $wgDBtype = "${cfg.database.type}"; 165 $wgDBserver = "${dbAddr}"; 166 $wgDBport = "${toString cfg.database.port}"; 167 $wgDBname = "${cfg.database.name}"; 168 $wgDBuser = "${cfg.database.user}"; 169 ${optionalString ( 170 cfg.database.passwordFile != null 171 ) "$wgDBpassword = file_get_contents(\"${cfg.database.passwordFile}\");"} 172 173 ${optionalString (cfg.database.type == "mysql" && cfg.database.tablePrefix != null) '' 174 # MySQL specific settings 175 $wgDBprefix = "${cfg.database.tablePrefix}"; 176 ''} 177 178 ${optionalString (cfg.database.type == "mysql") '' 179 # MySQL table options to use during installation or update 180 $wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary"; 181 ''} 182 183 ## Shared memory settings 184 $wgMainCacheType = CACHE_NONE; 185 $wgMemCachedServers = []; 186 187 ${optionalString (cfg.uploadsDir != null) '' 188 $wgEnableUploads = true; 189 $wgUploadDirectory = "${cfg.uploadsDir}"; 190 ''} 191 192 $wgUseImageMagick = true; 193 $wgImageMagickConvertCommand = "${pkgs.imagemagick}/bin/convert"; 194 195 # InstantCommons allows wiki to use images from https://commons.wikimedia.org 196 $wgUseInstantCommons = false; 197 198 # Periodically send a pingback to https://www.mediawiki.org/ with basic data 199 # about this MediaWiki instance. The Wikimedia Foundation shares this data 200 # with MediaWiki developers to help guide future development efforts. 201 $wgPingback = true; 202 203 ## If you use ImageMagick (or any other shell command) on a 204 ## Linux server, this will need to be set to the name of an 205 ## available UTF-8 locale 206 $wgShellLocale = "C.UTF-8"; 207 208 ## Set $wgCacheDirectory to a writable directory on the web server 209 ## to make your wiki go slightly faster. The directory should not 210 ## be publicly accessible from the web. 211 $wgCacheDirectory = "${cacheDir}"; 212 213 # Site language code, should be one of the list in ./languages/data/Names.php 214 $wgLanguageCode = "en"; 215 216 $wgSecretKey = file_get_contents("${stateDir}/secret.key"); 217 218 # Changing this will log out all existing sessions. 219 $wgAuthenticationTokenVersion = ""; 220 221 ## For attaching licensing metadata to pages, and displaying an 222 ## appropriate copyright notice / icon. GNU Free Documentation 223 ## License and Creative Commons licenses are supported so far. 224 $wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright 225 $wgRightsUrl = ""; 226 $wgRightsText = ""; 227 $wgRightsIcon = ""; 228 229 # Path to the GNU diff3 utility. Used for conflict resolution. 230 $wgDiff = "${pkgs.diffutils}/bin/diff"; 231 $wgDiff3 = "${pkgs.diffutils}/bin/diff3"; 232 233 # Enabled skins. 234 ${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadSkin('${k}');") cfg.skins)} 235 236 # Enabled extensions. 237 ${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadExtension('${k}');") cfg.extensions)} 238 239 240 # End of automatically generated settings. 241 # Add more configuration options below. 242 243 ${cfg.extraConfig} 244 ''; 245 }; 246 247 withTrailingSlash = str: if lib.hasSuffix "/" str then str else "${str}/"; 248in 249{ 250 # interface 251 options = { 252 services.mediawiki = { 253 254 enable = mkEnableOption "MediaWiki"; 255 256 package = mkPackageOption pkgs "mediawiki" { }; 257 258 finalPackage = mkOption { 259 type = types.package; 260 readOnly = true; 261 default = pkg; 262 defaultText = literalExpression "pkg"; 263 description = '' 264 The final package used by the module. This is the package that will have extensions and skins installed. 265 ''; 266 }; 267 268 name = mkOption { 269 type = types.str; 270 default = "MediaWiki"; 271 example = "Foobar Wiki"; 272 description = "Name of the wiki."; 273 }; 274 275 url = mkOption { 276 type = types.str; 277 default = 278 if cfg.webserver == "apache" then 279 "${ 280 if 281 cfg.httpd.virtualHost.addSSL || cfg.httpd.virtualHost.forceSSL || cfg.httpd.virtualHost.onlySSL 282 then 283 "https" 284 else 285 "http" 286 }://${cfg.httpd.virtualHost.hostName}" 287 else if cfg.webserver == "nginx" then 288 let 289 hasSSL = host: host.forceSSL || host.addSSL; 290 in 291 "${ 292 if hasSSL config.services.nginx.virtualHosts.${cfg.nginx.hostName} then "https" else "http" 293 }://${cfg.nginx.hostName}" 294 else 295 "http://localhost"; 296 defaultText = '' 297 if "mediawiki uses ssl" then "{"https" else "http"}://''${cfg.hostName}" else "http://localhost"; 298 ''; 299 example = "https://wiki.example.org"; 300 description = "URL of the wiki."; 301 }; 302 303 uploadsDir = mkOption { 304 type = types.nullOr types.path; 305 default = "${stateDir}/uploads"; 306 description = '' 307 This directory is used for uploads of pictures. The directory passed here is automatically 308 created and permissions adjusted as required. 309 ''; 310 }; 311 312 passwordFile = mkOption { 313 type = types.path; 314 description = '' 315 A file containing the initial password for the administrator account "admin". 316 ''; 317 example = "/run/keys/mediawiki-password"; 318 }; 319 320 passwordSender = mkOption { 321 type = types.str; 322 default = 323 if cfg.webserver == "apache" then 324 if cfg.httpd.virtualHost.adminAddr != null then 325 cfg.httpd.virtualHost.adminAddr 326 else 327 config.services.httpd.adminAddr 328 else 329 "root@localhost"; 330 defaultText = literalExpression '' 331 if cfg.webserver == "apache" then 332 if cfg.httpd.virtualHost.adminAddr != null then 333 cfg.httpd.virtualHost.adminAddr 334 else 335 config.services.httpd.adminAddr else "root@localhost" 336 ''; 337 description = "Contact address for password reset."; 338 }; 339 340 skins = mkOption { 341 default = { }; 342 type = types.attrsOf types.path; 343 description = '' 344 Attribute set of paths whose content is copied to the {file}`skins` 345 subdirectory of the MediaWiki installation in addition to the default skins. 346 ''; 347 }; 348 349 extensions = mkOption { 350 default = { }; 351 type = types.attrsOf (types.nullOr types.path); 352 description = '' 353 Attribute set of paths whose content is copied to the {file}`extensions` 354 subdirectory of the MediaWiki installation and enabled in configuration. 355 356 Use `null` instead of path to enable extensions that are part of MediaWiki. 357 ''; 358 example = literalExpression '' 359 { 360 Matomo = pkgs.fetchzip { 361 url = "https://github.com/DaSchTour/matomo-mediawiki-extension/archive/v4.0.1.tar.gz"; 362 sha256 = "0g5rd3zp0avwlmqagc59cg9bbkn3r7wx7p6yr80s644mj6dlvs1b"; 363 }; 364 ParserFunctions = null; 365 } 366 ''; 367 }; 368 369 webserver = mkOption { 370 type = types.enum [ 371 "apache" 372 "none" 373 "nginx" 374 ]; 375 default = "apache"; 376 description = "Webserver to use."; 377 }; 378 379 database = { 380 type = mkOption { 381 type = types.enum [ 382 "mysql" 383 "postgres" 384 "mssql" 385 "oracle" 386 ]; 387 default = "mysql"; 388 description = "Database engine to use. MySQL/MariaDB is the database of choice by MediaWiki developers."; 389 }; 390 391 host = mkOption { 392 type = types.str; 393 default = "localhost"; 394 description = "Database host address."; 395 }; 396 397 port = mkOption { 398 type = types.port; 399 default = if cfg.database.type == "mysql" then 3306 else 5432; 400 defaultText = literalExpression "3306"; 401 description = "Database host port."; 402 }; 403 404 name = mkOption { 405 type = types.str; 406 default = "mediawiki"; 407 description = "Database name."; 408 }; 409 410 user = mkOption { 411 type = types.str; 412 default = "mediawiki"; 413 description = "Database user."; 414 }; 415 416 passwordFile = mkOption { 417 type = types.nullOr types.path; 418 default = null; 419 example = "/run/keys/mediawiki-dbpassword"; 420 description = '' 421 A file containing the password corresponding to 422 {option}`database.user`. 423 ''; 424 }; 425 426 tablePrefix = mkOption { 427 type = types.nullOr types.str; 428 default = null; 429 description = '' 430 If you only have access to a single database and wish to install more than 431 one version of MediaWiki, or have other applications that also use the 432 database, you can give the table names a unique prefix to stop any naming 433 conflicts or confusion. 434 See <https://www.mediawiki.org/wiki/Manual:$wgDBprefix>. 435 ''; 436 }; 437 438 socket = mkOption { 439 type = types.nullOr types.path; 440 default = 441 if (cfg.database.type == "mysql" && cfg.database.createLocally) then 442 "/run/mysqld/mysqld.sock" 443 else if (cfg.database.type == "postgres" && cfg.database.createLocally) then 444 "/run/postgresql" 445 else 446 null; 447 defaultText = literalExpression "/run/mysqld/mysqld.sock"; 448 description = "Path to the unix socket file to use for authentication."; 449 }; 450 451 createLocally = mkOption { 452 type = types.bool; 453 default = cfg.database.type == "mysql" || cfg.database.type == "postgres"; 454 defaultText = literalExpression "true"; 455 description = '' 456 Create the database and database user locally. 457 This currently only applies if database type "mysql" is selected. 458 ''; 459 }; 460 }; 461 462 nginx.hostName = mkOption { 463 type = types.str; 464 example = literalExpression ''wiki.example.com''; 465 default = "localhost"; 466 description = '' 467 The hostname to use for the nginx virtual host. 468 This is used to generate the nginx configuration. 469 ''; 470 }; 471 472 httpd.virtualHost = mkOption { 473 type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix); 474 example = literalExpression '' 475 { 476 hostName = "mediawiki.example.org"; 477 adminAddr = "webmaster@example.org"; 478 forceSSL = true; 479 enableACME = true; 480 } 481 ''; 482 description = '' 483 Apache configuration can be done by adapting {option}`services.httpd.virtualHosts`. 484 See [](#opt-services.httpd.virtualHosts) for further information. 485 ''; 486 }; 487 488 poolConfig = mkOption { 489 type = 490 with types; 491 attrsOf (oneOf [ 492 str 493 int 494 bool 495 ]); 496 default = { 497 "pm" = "dynamic"; 498 "pm.max_children" = 32; 499 "pm.start_servers" = 2; 500 "pm.min_spare_servers" = 2; 501 "pm.max_spare_servers" = 4; 502 "pm.max_requests" = 500; 503 }; 504 description = '' 505 Options for the MediaWiki PHP pool. See the documentation on `php-fpm.conf` 506 for details on configuration directives. 507 ''; 508 }; 509 510 extraConfig = mkOption { 511 type = types.lines; 512 description = '' 513 Any additional text to be appended to MediaWiki's 514 LocalSettings.php configuration file. For configuration 515 settings, see <https://www.mediawiki.org/wiki/Manual:Configuration_settings>. 516 ''; 517 default = ""; 518 example = '' 519 $wgEnableEmail = false; 520 ''; 521 }; 522 523 }; 524 }; 525 526 imports = [ 527 (lib.mkRenamedOptionModule 528 [ "services" "mediawiki" "virtualHost" ] 529 [ "services" "mediawiki" "httpd" "virtualHost" ] 530 ) 531 ]; 532 533 # implementation 534 config = mkIf cfg.enable { 535 536 assertions = [ 537 { 538 assertion = 539 cfg.database.createLocally -> (cfg.database.type == "mysql" || cfg.database.type == "postgres"); 540 message = "services.mediawiki.createLocally is currently only supported for database type 'mysql' and 'postgres'"; 541 } 542 { 543 assertion = 544 cfg.database.createLocally -> cfg.database.user == user && cfg.database.name == cfg.database.user; 545 message = "services.mediawiki.database.user must be set to ${user} if services.mediawiki.database.createLocally is set true"; 546 } 547 { 548 assertion = cfg.database.createLocally -> cfg.database.socket != null; 549 message = "services.mediawiki.database.socket must be set if services.mediawiki.database.createLocally is set to true"; 550 } 551 { 552 assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; 553 message = "a password cannot be specified if services.mediawiki.database.createLocally is set to true"; 554 } 555 ]; 556 557 services.mediawiki.skins = { 558 MonoBook = "${cfg.package}/share/mediawiki/skins/MonoBook"; 559 Timeless = "${cfg.package}/share/mediawiki/skins/Timeless"; 560 Vector = "${cfg.package}/share/mediawiki/skins/Vector"; 561 }; 562 563 services.mysql = mkIf (cfg.database.type == "mysql" && cfg.database.createLocally) { 564 enable = true; 565 package = mkDefault pkgs.mariadb; 566 ensureDatabases = [ cfg.database.name ]; 567 ensureUsers = [ 568 { 569 name = cfg.database.user; 570 ensurePermissions = { 571 "${cfg.database.name}.*" = "ALL PRIVILEGES"; 572 }; 573 } 574 ]; 575 }; 576 577 services.postgresql = mkIf (cfg.database.type == "postgres" && cfg.database.createLocally) { 578 enable = true; 579 ensureDatabases = [ cfg.database.name ]; 580 ensureUsers = [ 581 { 582 name = cfg.database.user; 583 ensureDBOwnership = true; 584 } 585 ]; 586 }; 587 588 services.phpfpm.pools.mediawiki = { 589 inherit user group; 590 phpEnv.MEDIAWIKI_CONFIG = "${mediawikiConfig}"; 591 phpPackage = php; 592 settings = 593 ( 594 if (cfg.webserver == "apache") then 595 { 596 "listen.owner" = config.services.httpd.user; 597 "listen.group" = config.services.httpd.group; 598 } 599 else if (cfg.webserver == "nginx") then 600 { 601 "listen.owner" = config.services.nginx.user; 602 "listen.group" = config.services.nginx.group; 603 } 604 else 605 { 606 "listen.owner" = user; 607 "listen.group" = group; 608 } 609 ) 610 // cfg.poolConfig; 611 }; 612 613 services.httpd = lib.mkIf (cfg.webserver == "apache") { 614 enable = true; 615 extraModules = [ "proxy_fcgi" ]; 616 virtualHosts.${cfg.httpd.virtualHost.hostName} = mkMerge [ 617 cfg.httpd.virtualHost 618 { 619 documentRoot = mkForce "${pkg}/share/mediawiki"; 620 extraConfig = '' 621 <Directory "${pkg}/share/mediawiki"> 622 <FilesMatch "\.php$"> 623 <If "-f %{REQUEST_FILENAME}"> 624 SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/" 625 </If> 626 </FilesMatch> 627 628 Require all granted 629 DirectoryIndex index.php 630 AllowOverride All 631 </Directory> 632 '' 633 + optionalString (cfg.uploadsDir != null) '' 634 Alias "/images" "${cfg.uploadsDir}" 635 <Directory "${cfg.uploadsDir}"> 636 Require all granted 637 </Directory> 638 ''; 639 } 640 ]; 641 }; 642 # inspired by https://www.mediawiki.org/wiki/Manual:Short_URL/Nginx 643 services.nginx = lib.mkIf (cfg.webserver == "nginx") { 644 enable = true; 645 virtualHosts.${config.services.mediawiki.nginx.hostName} = { 646 root = "${pkg}/share/mediawiki"; 647 locations = { 648 "~ ^/w/(index|load|api|thumb|opensearch_desc|rest|img_auth)\\.php$".extraConfig = '' 649 rewrite ^/w/(.*) /$1 break; 650 include ${config.services.nginx.package}/conf/fastcgi.conf; 651 fastcgi_index index.php; 652 fastcgi_pass unix:${config.services.phpfpm.pools.mediawiki.socket}; 653 ''; 654 "/w/images/".alias = withTrailingSlash cfg.uploadsDir; 655 # Deny access to deleted images folder 656 "/w/images/deleted".extraConfig = '' 657 deny all; 658 ''; 659 # MediaWiki assets (usually images) 660 "~ ^/w/resources/(assets|lib|src)".extraConfig = '' 661 rewrite ^/w(/.*) $1 break; 662 add_header Cache-Control "public"; 663 expires 7d; 664 ''; 665 # Assets, scripts and styles from skins and extensions 666 "~ ^/w/(skins|extensions)/.+\\.(css|js|gif|jpg|jpeg|png|svg|wasm|ttf|woff|woff2)$".extraConfig = '' 667 rewrite ^/w(/.*) $1 break; 668 add_header Cache-Control "public"; 669 expires 7d; 670 ''; 671 672 # Handling for Mediawiki REST API, see [[mw:API:REST_API]] 673 "/w/rest.php/".tryFiles = "$uri $uri/ /w/rest.php?$query_string"; 674 675 # Handling for the article path (pretty URLs) 676 "/wiki/".extraConfig = '' 677 rewrite ^/wiki/(?<pagename>.*)$ /w/index.php; 678 ''; 679 680 # Explicit access to the root website, redirect to main page (adapt as needed) 681 "= /".extraConfig = '' 682 return 301 /wiki/; 683 ''; 684 685 # Every other entry point will be disallowed. 686 # Add specific rules for other entry points/images as needed above this 687 "/".extraConfig = '' 688 return 404; 689 ''; 690 }; 691 }; 692 }; 693 694 systemd.tmpfiles.rules = [ 695 "d '${stateDir}' 0750 ${user} ${group} - -" 696 "d '${cacheDir}' 0750 ${user} ${group} - -" 697 ] 698 ++ optionals (cfg.uploadsDir != null) [ 699 "d '${cfg.uploadsDir}' 0750 ${user} ${group} - -" 700 "Z '${cfg.uploadsDir}' 0750 ${user} ${group} - -" 701 ]; 702 703 systemd.services.mediawiki-init = { 704 wantedBy = [ "multi-user.target" ]; 705 before = [ "phpfpm-mediawiki.service" ]; 706 after = 707 optional (cfg.database.type == "mysql" && cfg.database.createLocally) "mysql.service" 708 ++ optional (cfg.database.type == "postgres" && cfg.database.createLocally) "postgresql.target"; 709 script = '' 710 if ! test -e "${stateDir}/secret.key"; then 711 tr -dc A-Za-z0-9 </dev/urandom 2>/dev/null | head -c 64 > ${stateDir}/secret.key 712 fi 713 714 echo "exit( \$this->getPrimaryDB()->tableExists( 'user' ) ? 1 : 0 );" | \ 715 ${php}/bin/php ${pkg}/share/mediawiki/maintenance/run.php eval --conf ${mediawikiConfig} && \ 716 ${php}/bin/php ${pkg}/share/mediawiki/maintenance/install.php \ 717 --confpath /tmp \ 718 --scriptpath / \ 719 --dbserver ${lib.escapeShellArg dbAddr} \ 720 --dbport ${toString cfg.database.port} \ 721 --dbname ${lib.escapeShellArg cfg.database.name} \ 722 ${ 723 optionalString ( 724 cfg.database.tablePrefix != null 725 ) "--dbprefix ${lib.escapeShellArg cfg.database.tablePrefix}" 726 } \ 727 --dbuser ${lib.escapeShellArg cfg.database.user} \ 728 ${ 729 optionalString ( 730 cfg.database.passwordFile != null 731 ) "--dbpassfile ${lib.escapeShellArg cfg.database.passwordFile}" 732 } \ 733 --passfile ${lib.escapeShellArg cfg.passwordFile} \ 734 --dbtype ${cfg.database.type} \ 735 ${lib.escapeShellArg cfg.name} \ 736 admin 737 738 ${php}/bin/php ${pkg}/share/mediawiki/maintenance/update.php --conf ${mediawikiConfig} --quick --skip-external-dependencies 739 ''; 740 741 serviceConfig = { 742 Type = "oneshot"; 743 User = user; 744 Group = group; 745 PrivateTmp = true; 746 }; 747 }; 748 749 systemd.services.httpd.after = 750 optional ( 751 cfg.webserver == "apache" && cfg.database.createLocally && cfg.database.type == "mysql" 752 ) "mysql.service" 753 ++ optional ( 754 cfg.webserver == "apache" && cfg.database.createLocally && cfg.database.type == "postgres" 755 ) "postgresql.target"; 756 757 users.users.${user} = { 758 inherit group; 759 isSystemUser = true; 760 }; 761 users.groups.${group} = { }; 762 763 environment.systemPackages = [ mediawikiScripts ]; 764 }; 765}