nix-config/hosts/mediawiki/default.nix

284 lines
11 KiB
Nix

{ config, lib, libC, pkgs, ... }:
let
cfg = config.services.mediawiki;
in
{
assertions = [
{
assertion = lib.versions.majorMinor pkgs.mediawiki.version != 1.40;
# https://www.mediawiki.org/wiki/Version_lifecycle
message = "Please keep mediawiki on LTS versions which is required by the LDAP extension";
}
];
c3d2 = {
deployment.server = "server10";
hq.sendmail = true;
};
microvm.mem = 1536;
networking = {
firewall.allowedTCPPorts = [ 80 443 ]; # httpd, not nginx :(
hostName = "mediawiki";
};
services = {
backup.paths = [ "/var/lib/mediawiki/uploads/" ];
logrotate.checkConfig = false;
mediawiki = {
enable = true;
database = {
type = "postgres";
socket = "/run/postgresql";
};
# see https://extdist.wmflabs.org/dist/extensions/ for list of extensions
# save them on https://web.archive.org/save and copy the final URL below
extensions = {
Lockdown = pkgs.fetchzip {
url = "https://web.archive.org/web/20230710141042/https://extdist.wmflabs.org/dist/extensions/Lockdown-REL1_40-7d900ed.tar.gz";
sha256 = "sha256-TgoL9IcwY4EBNUsoVBqpUehVO7TEDT22FoH7Ep4dMxw=";
};
# TODO: replace with https://www.mediawiki.org/wiki/Extension:DynamicPageList3
intersection = pkgs.fetchzip {
url = "https://web.archive.org/web/20230710142223/https://extdist.wmflabs.org/dist/extensions/intersection-REL1_40-f3c1559.tar.gz";
sha256 = "sha256-/Ap56EOfsAlx/gkN8Y+NdU28yuZsZmrrBMmuNoi88/A=";
};
# requires PluggableAuth
LDAPAuthentication2 =
let
src = pkgs.fetchzip {
url = "https://web.archive.org/web/20230710142325/https://extdist.wmflabs.org/dist/extensions/LDAPAuthentication2-REL1_40-2864ae9.tar.gz";
sha256 = "sha256-LWXpmgzUpgEaPe/4cwF2cmJxPkW8ywT7gRAlB58mDfY=";
};
in
# TODO: remove with next release
pkgs.runCommand "LDAPAuthentication2" { } ''
mkdir $out
cp -r ${src}/* $out
sed 's/"PluggableAuth": "6.*"/"PluggableAuth": "*"/g' -i $out/extension.json
'';
LDAPProvider = pkgs.fetchzip {
url = "https://web.archive.org/web/20230710141035/https://extdist.wmflabs.org/dist/extensions/LDAPProvider-REL1_40-99edc23.tar.gz";
sha256 = "sha256-DYq5CCm//rc6Mei9K6S2Ue+hzz6PYHnwpbJouFS5j+o=";
};
PluggableAuth = pkgs.fetchzip {
url = "https://web.archive.org/web/20230710142618/https://extdist.wmflabs.org/dist/extensions/PluggableAuth-REL1_40-519c6d2.tar.gz";
sha256 = "sha256-N1+OV1UdzvU4iXhaS/+fuEoAXqrkVyyEPDirk0vrT8A=";
};
};
name = "C3D2";
nginx.hostName = "wiki.c3d2.de";
package = pkgs.php81.buildComposerProject {
pname = "mediawiki-pre-full";
inherit (pkgs.mediawiki) version postPatch;
src = pkgs.applyPatches {
inherit (pkgs.mediawiki) src;
# update by running the following commands
# nix build .#nixosConfigurations.mediawiki.pkgs.mediawiki
# cp result/share/mediawiki/composer.json .
# composer update
# and updating the vendorHash by trying to deploy once
postPatch = ''
cp ${./composer.local.json} composer.local.json
cp ${./composer.lock} composer.lock
'';
};
composerNoPlugins = false;
vendorHash = "sha256-Ki+rTFWxlWRl5pfeTdVeirgKOFGzXsZ9LQ1QZ0nenhU=";
postInstall = ''
mv $out/share/{php/mediawiki-pre-full,mediawiki}/
rm -r $out/share/php
# https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/web-apps/mediawiki/default.nix#L21-L23
echo "<?php
return require(getenv('MEDIAWIKI_CONFIG'));
?>" > $out/share/mediawiki/LocalSettings.php
substituteInPlace $out/share/mediawiki/includes/config-schema.php \
--replace "\$path/convert" "${pkgs.imagemagick}/bin/convert"
'';
};
#skins = {
# Vector = "${config.services.mediawiki.package}/share/mediawiki/skins/Vector";
# Hector = "${config.services.mediawiki.package}/share/mediawiki/skins/Hector";
#};
# initial admin user password
passwordFile = config.sops.secrets."mediawiki/adminPassword".path;
uploadsDir = "/var/lib/mediawiki/uploads";
webserver = "nginx";
extraConfig = /* php */ ''
$wgAllowUserCss = true;
$wgDBmwschema = "mediawiki";
$wgEnableAPI = true;
$wgEnableMWSuggest = true;
$wgShowExceptionDetails = true;
$wgUseAjax = true;
$wgFavicon = "https://c3d2.de/favicon.ico";
$wgLogos = [
'1x' => "https://www.c3d2.de/images/ck.png",
'1.5x' => "https://www.c3d2.de/images/ck.png",
'2x' => "https://www.c3d2.de/images/ck.png",
'icon' => "https://www.c3d2.de/images/ck.png",
];
$wgEmergencyContact = "wiki@c3d2.de";
$wgPasswordSender = "wiki@c3d2.de";
$wgLanguageCode = "de";
$wgGroupPermissions['*']['edit'] = false;
$wgGroupPermissions['user']['edit'] = true;
$wgGroupPermissions['sysop']['userrights'] = true;
$wgNamespacesWithSubpages[NS_MAIN] = true;
define("NS_INTERN", 100);
define("NS_INTERN_TALK", 101);
$wgExtraNamespaces[NS_INTERN] = "Intern";
$wgExtraNamespaces[NS_INTERN_TALK] = "Intern_Diskussion";
$wgNamespacesWithSubpages[NS_INTERN] = true;
$wgNamespacesWithSubpages[NS_INTERN_TALK] = true;
$wgGroupPermissions['intern']['move'] = true;
$wgGroupPermissions['intern']['move-subpages'] = true;
$wgGroupPermissions['intern']['move-rootuserpages'] = true; // can move root userpages
$wgGroupPermissions['intern']['read'] = true;
$wgGroupPermissions['intern']['edit'] = true;
$wgGroupPermissions['intern']['createpage'] = true;
$wgGroupPermissions['intern']['createtalk'] = true;
$wgGroupPermissions['intern']['writeapi'] = true;
$wgGroupPermissions['intern']['upload'] = true;
$wgGroupPermissions['intern']['reupload'] = true;
$wgGroupPermissions['intern']['reupload-shared'] = true;
$wgGroupPermissions['intern']['minoredit'] = true;
$wgGroupPermissions['intern']['purge'] = true; // can use ?action=purge without clicking "ok"
$wgGroupPermissions['intern']['sendemail'] = true;
$wgNamespacePermissionLockdown[NS_INTERN]['*'] = array('intern');
$wgNamespacePermissionLockdown[NS_INTERN_TALK]['*'] = array('intern');
define("NS_I4R", 102);
define("NS_I4R_TALK", 103);
$wgExtraNamespaces[NS_I4R] = "IT4Refugees";
$wgExtraNamespaces[NS_I4R_TALK] = "IT4Refugees_Diskussion";
$wgNamespacesWithSubpages[NS_I4R] = true;
$wgNamespacesWithSubpages[NS_I4R_TALK] = true;
$wgGroupPermissions['i4r']['move'] = true;
$wgGroupPermissions['i4r']['move-subpages'] = true;
$wgGroupPermissions['i4r']['move-rootuserpages'] = true; // can move root userpages
$wgGroupPermissions['i4r']['read'] = true;
$wgGroupPermissions['i4r']['edit'] = true;
$wgGroupPermissions['i4r']['createpage'] = true;
$wgGroupPermissions['i4r']['createtalk'] = true;
$wgGroupPermissions['i4r']['writeapi'] = true;
$wgGroupPermissions['i4r']['upload'] = true;
$wgGroupPermissions['i4r']['reupload'] = true;
$wgGroupPermissions['i4r']['reupload-shared'] = true;
$wgGroupPermissions['i4r']['minoredit'] = true;
$wgGroupPermissions['i4r']['purge'] = true; // can use ?action=purge without clicking "ok"
$wgGroupPermissions['i4r']['sendemail'] = true;
$wgNamespacePermissionLockdown[NS_I4R]['*'] = array('i4r');
$wgNamespacePermissionLockdown[NS_I4R_TALK]['*'] = array('i4r');
$wgGroupPermissions['sysop']['deletelogentry'] = true;
$wgGroupPermissions['sysop']['deleterevision'] = true;
wfLoadExtension('ConfirmEdit/QuestyCaptcha');
$wgCaptchaClass = 'QuestyCaptcha';
$wgCaptchaQuestions[] = array('question' => 'How is C3D2 logo in ascii?', 'answer' => '<<</>>');
wfLoadExtension('Interwiki');
$wgGroupPermissions['sysop']['interwiki'] = true;
wfLoadExtension('Cite');
wfLoadExtension('CiteThisPage');
wfLoadExtension('ConfirmEdit');
wfLoadExtension('ParserFunctions');
wfLoadExtension('SyntaxHighlight_GeSHi');
wfLoadExtension('WikiEditor');
// TODO: what about $wgUpgradeKey ?
// TODO: does this even work?
// https://www.mediawiki.org/wiki/Extension:Scribunto#Requirements mentions quite some extra steps which we didn't do
wfLoadExtension('Scribunto');
$wgScribuntoDefaultEngine = 'luastandalone';
# LDAP
$LDAPProviderDomainConfigs = "${config.sops.secrets."mediawiki/ldapprovider".path}";
$wgPluggableAuth_EnableLocalLogin = true;
# SemanticMediaWiki
wfLoadExtension('SemanticMediaWiki');
# TODO: expose https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/web-apps/mediawiki.nix#L19
$smwgConfigFileDir = "/var/lib/mediawiki";
# default was 100 which is already occupied, using 200 to 215
# https://www.semantic-mediawiki.org/wiki/Help:$smwgNamespaceIndex
$smwgNamespaceIndex = 200;
enableSemantics('${config.services.mediawiki.nginx.hostName}');
$smwgURITypeSchemeList = array_merge(
$smwgURITypeSchemeList, [
'xmpp', 'mumble', 'ssh'
]
);
'';
};
nginx = {
enable = true;
commonHttpConfig = ''
# for some reason nginx adds a port for the 301 redirect from / to /wiki/
port_in_redirect off;
'';
virtualHosts."${config.services.mediawiki.nginx.hostName}" = {
enableACME = true;
forceSSL = true;
listen = libC.defaultListen;
locations."/".extraConfig = lib.mkForce ''
return 307 /wiki$request_uri;
'';
};
};
phpfpm.phpPackage = pkgs.php.buildEnv {
extensions = { all, enabled }: enabled ++ (with all; [ apcu ]);
};
postgresql = {
enable = true;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [{
name = cfg.database.user;
ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
}];
package = pkgs.postgresql_16;
upgrade.stopServices = [ "phpfpm-mediawiki" ];
};
};
sops = {
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
defaultSopsFile = ./secrets.yaml;
secrets = {
"mediawiki/adminPassword".owner = config.systemd.services.mediawiki-init.serviceConfig.User;
"mediawiki/ldapprovider".owner = config.systemd.services.mediawiki-init.serviceConfig.User;
"mediawiki/secretKey" = {
owner = config.systemd.services.mediawiki-init.serviceConfig.User;
path = "/var/lib/mediawiki/secret.key";
};
"mediawiki/upgradeKey".owner = config.systemd.services.mediawiki-init.serviceConfig.User;
};
};
system.stateVersion = "22.05";
systemd.services.mediawiki-init = {
after = [ "postgresql.service" ];
requires = [ "postgresql.service" ];
};
}