{ config, pkgs, lib, ... }: { services.mediawiki.extraConfig = lib.mkAfter '' # ----- Invite-only accounts ----- $wgGroupPermissions['*']['createaccount'] = false; $wgGroupPermissions['bureaucrat']['createaccount'] = true; # ----- File cache for anonymous readers ----- $wgUseFileCache = true; $wgFileCacheDirectory = "/var/cache/mediawiki"; $wgShowIPinHeader = false; # ----- Rate limit exemption for logged-in users ----- $wgGroupPermissions['user']['noratelimit'] = true; # ----- Email ----- $wgEnableEmail = true; $wgEnableUserEmail = true; $wgEmergencyContact = "wiki@noisebridge.net"; $wgPasswordSender = "wiki@noisebridge.net"; # Mail sent via local Postfix, which relays through m3.noisebridge.net # ----- ReCaptcha (login brute-force only) ----- wfLoadExtension( 'ConfirmEdit/ReCaptchaNoCaptcha' ); $wgReCaptchaSiteKey = '6Le_REPLACE_SITE_KEY'; $wgReCaptchaSecretKey = trim(file_get_contents('${config.age.secrets.mediawiki-recaptcha.path}')); $wgCaptchaTriggers['badlogin'] = true; $wgCaptchaTriggers['createaccount'] = false; $wgCaptchaTriggers['edit'] = false; $wgCaptchaTriggers['create'] = false; ''; # PHP-FPM: static pool for maximum performance # Use individual mkForce to override defaults without clobbering # required settings (listen, user, group) set by the mediawiki module services.phpfpm.pools.mediawiki.settings = { "pm" = lib.mkForce "static"; "pm.max_children" = lib.mkForce 30; "pm.max_requests" = lib.mkForce 500; "request_terminate_timeout" = lib.mkForce "30s"; "catch_workers_output" = lib.mkForce true; "pm.status_path" = "/fpm-status"; # OPcache "php_admin_value[opcache.enable]" = 1; "php_admin_value[opcache.memory_consumption]" = 256; "php_admin_value[opcache.max_accelerated_files]" = 10000; "php_admin_value[opcache.revalidate_freq]" = 60; "php_admin_value[opcache.jit]" = 1255; "php_admin_value[opcache.jit_buffer_size]" = "64M"; # Memory & execution "php_admin_value[memory_limit]" = "256M"; "php_admin_value[max_execution_time]" = 30; "php_admin_value[upload_max_filesize]" = "10M"; "php_admin_value[post_max_size]" = "12M"; }; # File cache directory systemd.tmpfiles.rules = [ "d /var/cache/mediawiki 0755 mediawiki mediawiki -" ]; # MediaWiki job runner (since wgJobRunRate=0) systemd.services.mediawiki-jobrunner = { description = "MediaWiki job runner"; after = [ "mysql.service" "phpfpm-mediawiki.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "simple"; User = "mediawiki"; Group = "mediawiki"; ExecStart = "${pkgs.php}/bin/php ${config.services.mediawiki.finalPackage}/share/mediawiki/maintenance/runJobs.php --wait --maxjobs=10"; Restart = "always"; RestartSec = "30s"; }; }; # Sync uploaded images to replica over Tailscale (hourly) # Writes textfile metrics so Prometheus can alert on stale syncs systemd.services.wiki-image-sync = { description = "Sync wiki images to replica"; after = [ "tailscale-autoconnect.service" ]; path = [ pkgs.rsync ]; serviceConfig = { Type = "oneshot"; User = "root"; }; script = '' TEXTFILE_DIR="/var/lib/prometheus-node-exporter/textfile" if rsync -az --delete /var/lib/mediawiki/images/ wiki-replica:/var/lib/mediawiki/images/; then SYNC_OK=1 else SYNC_OK=0 fi cat > "$TEXTFILE_DIR/imagesync.prom" <