MediaWiki Docker Installation

Aus Laub-Home Wiki

Wie kann man ein MediaWiki am besten via Docker bzw. Docker Compose deployen?

Zunächst nehmen wir den von WikiMedia betreuten Container von MediaWiki, packen dazu noch eine MariaDB und für ein wenig mehr Performance noch einen memcached Container. Optional kann dann, für den VisualEditor, Parsoid mit deployt werden. Vor das gesamte Docker Compose Projekt (MediaWiki Applikation) packen wir noch einen NGINX SSL Reverse Proxy für Docker Container, fertig ist unsere MediaWiki Installation. Möchte man dann noch ein bereits bestehendes MediaWiki migrieren, findet ihr im MediaWiki Migration von einem anderen Server HowTo das richtige Vorgehen.

Deployment via Docker Container

Was passiert hier nun in Kurzfassung:

  • es wird ein Projekt erstellt mit MediaWiki, MariaDB und Memcached
  • die MediaWiki und MariaDB Daten werden als Volumes gemountet um sie somit persistent zu machen
  • Danach lauscht das MediaWiki auf localhost:8091
  • sollte dann via NGINX Reverse Proxy in die weite Welt rausgereicht werden
  • Optional: können weitere Extensions eingebunden werden
  • Optional: Migration von einem anderen Server
  • Backup and Restore des gesamten MediaWiki

Docker Compose Projekt

Als erstes legen wir das docker-compose Projekt an:

mkdir -p /opt/mediawiki/data/conf
mkdir /opt/mediawiki/data/extensions
mkdir /opt/mediawiki/data/sitemap
mkdir /opt/mediawiki/data/skins
cd /opt/mediawiki

/opt/mediawiki/.env

# Config File for MediaWiki Application

# Docker Compose Project Name
# max length 11 characters
PROJECT_NAME=mediawiki

# Maria DB Configuration
DB_ROOT_PASS=DBROOTPASSWORD
DB_NAME=wiki
DB_USER=wiki
DB_PASS=DBPASSWORD

# MediaWiki Port Configuration
WIKI_HTTP_PORT=127.0.0.1:8091
# Wiki Version
# for latest:
WIKI_VERSION=latest
# Specific Version
#WIKI_VERSION=1.41

# Memcached Size
CACHE=16M

# Timezone
TZ=Europe/Berlin

/opt/mediawiki/docker-compose.yml

version: '3.8'

services:
  database: 
    image: mariadb:latest
    volumes:
      - data_mw_db:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASS}
      TZ: ${TZ}
    networks:
      backend-nw:
        aliases:
          - db

  memcached:
    image: memcached:alpine
    restart: always
    command: ["-m", "${CACHE}"]
    environment:
        - TZ=${TZ}
    networks:
      backend-nw:
        aliases:
            - wikimemcached

  mediawiki:
    image: mediawiki:${WIKI_VERSION}
    depends_on:
      - database
      - memcached
    restart: always
    environment:
      TZ: ${TZ}
    ports:
      - ${WIKI_HTTP_PORT}:80
    volumes:
      - data_mw_images:/var/www/html/images
      - ./data/sitemap:/var/www/html/sitemap
      # After initial setup, download LocalSettings.php to data/conf directory 
      # and uncomment the following line and use compose to restart
      # the mediawiki service
      #- ./data/conf/LocalSettings.php:/var/www/html/LocalSettings.php:ro
      - ./data/conf/.htaccess:/var/www/html/.htaccess:ro
      # Special Stuff (Google AdSense & Search Console)
      #- ./data/conf/robots.txt:/var/www/html/robots.txt:ro
      #- ./data/conf/ads.txt:/var/www/html/ads.txt:ro
      # Mediawiki Extensions
      #- ./data/extensions/WikiCategoryTagCloud:/var/www/html/extensions/WikiCategoryTagCloud:ro
      #- ./data/extensions/Lockdown:/var/www/html/extensions/Lockdown:ro
      #- ./data/extensions/MobileFrontend:/var/www/html/extensions/MobileFrontend:ro
      #- ./data/extensions/CookieWarning:/var/www/html/extensions/CookieWarning:ro
      #- ./data/extensions/RelatedArticles:/var/www/html/extensions/RelatedArticles:ro
      #- ./data/extensions/Description2:/var/www/html/extensions/Description2:ro
      #- ./data/extensions/RottenLinks:/var/www/html/extensions/RottenLinks:ro
      # Mediawiki Skins
      #- ./data/skins/MinervaNeue:/var/www/html/skins/MinervaNeue:ro

    networks:
      app-nw:
        aliases:
          - wiki
      backend-nw:

volumes:
  data_mw_db:
  data_mw_images:

networks:
  app-nw:
    internal: false
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: app-${PROJECT_NAME}
  backend-nw:
    internal: true
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: be-${PROJECT_NAME}

/opt/mediawiki/data/conf/.htaccess

<IfModule mod_rewrite.c>
RewriteEngine On
# Normale Desktop Short URL Umleitung
RewriteBase /
RewriteRule ^/index.php/(.*) /wiki/$1 [QSA,R=permanent]
RewriteRule ^/?wiki(/.*)?$ %{DOCUMENT_ROOT}/index.php
</IfModule>

# Sitemap umleiten
Redirect /sitemap.xml /sitemap/sitemap-index-wiki.xml

# Upload Limit erhöhen
php_value upload_max_filesize 100M
php_value post_max_size 100M

Optional:

Diese Datei wird von Google AdSense verlangt. Den Inhalt bekommt man aus dem Adsense Webinterface. Im docker-compose.yml bitte die entsprechende Zeile einkommentierten!

/opt/mediawiki/data/conf/ads.txt

google.com, pub-656291473678xxx, DIRECT, f08c47fec094xxx

Optional:

Falls gewollt kann man eine robots.txt für Suchmaschinen anlegen. Diese hier verbietet den zugriff auf die Spezialseiten, Diskussionen und die Index.php selbst, damit nur die Short URLs gecrawlt werden. Zusätzlich informiert sie über den Ort der Sitemap. Im docker-compose.yml bitte die entsprechende Zeile einkommentierten!

/opt/mediawiki/data/conf/robots.txt

User-agent: *
Disallow: /index.php
Disallow: /Index.php
Disallow: /*Spezial:
Disallow: /*Diskussion:
Sitemap: https://www.laub-home.de/sitemap/sitemap-index-wiki.xml

Nun kann das Ganze einfach gestartet werden:

docker compose up -d

nun sollte via

curl http://localhost:8091

eine Ausgabe kommen.

Nginx Reverse Proxy

Um das Ganze dann von außen verfügbar zu machen, richten wir auf unserem NGINX SSL Reverse Proxy für Docker Container einen neuen vhost ein:

/opt/nginxproxy/data/nginx/conf/www.example.tld.conf

server {
  listen 80;
  listen [::]:80;
  server_name www.example.tld wiki.example.tld example.tld;

  return 301 https://$host$request_uri;
}
server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name www.example.tld wiki.example.tld example.tld;
  if ($host != $server_name) {
      rewrite ^/(.*) $scheme://$server_name/$1 permanent;
  }

  ssl_certificate /etc/letsencrypt/live/www.example.tld/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/www.example.tld/privkey.pem;

  include /etc/nginx/conf.d/includes/site-defaults.conf;
  include /etc/nginx/conf.d/includes/cert_bot.conf;
  include /etc/nginx/conf.d/includes/google.conf;
  expires $expires;

  location / {
      proxy_pass http://127.0.0.1:8091;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      client_max_body_size 0;
      #include /etc/nginx/conf.d/includes/proxy_cache.conf;
  }
  # show cache status and any skip cache reason
  #add_header Proxy-Cache $upstream_cache_status;

  add_header X-XSS-Protection "1; mode=block";
}

Nun nicht vergessen die SSL Zertifikate für die neue Domain zu erstellen:

dadurch wird auch der Nginx Proxy neu gestartet und die MediaWiki Startseite sollte im Anschluss verfügbar sein. MediWiki kann dann einfach konfiguriert werden, oder aber ein bereits bestehendes MediaWiki migriert werden.

Konfiguration des Mediawiki

Die Grundkonfiguration erfolgt durch das erstmalige aufrufen der Startseite. Diese, falls es keine LocalSettings.php, ist ein Konfigurationsassistent. Einfach nun nach belieben konfigurieren und an der Stelle wo nach dem Memcached gefragt wird folgendes eintragen:

wikimemcached:11211

Und bei der Frage nach der Datenbankverbindung bitte den DB Alias Namen von Docker eintragen:

db

Im Anschluss kann die Datei heruntergeladen und nach /opt/mediawiki/data/conf/ kopiert werden. Dann im /opt/mediawiki/docker-compose.yml die Zeile mit der LocalSettings.php einkommentierten:

# After initial setup, download LocalSettings.php to data/conf directory 
# and uncomment the following line and use compose to restart
# the mediawiki service
- ./data/conf/LocalSettings.php:/var/www/html/LocalSettings.php:ro

und das Projekt neu deployen:

cd /opt/mediawiki
docker compose up -d

Nun sollte die richtige Startseite angezeigt werden.

Spezielle Einstellungen

Ich habe in der LocalSettings.php noch die folgenden Einstellungen vorgenommen:

  • SMTP Server Konfiguration (da Docker nicht über localhost mailen kann)
  • E-Mail Adressen der Benutzer müssen bestätigt werden
  • Short URLs aktivieren (Achtung, hierfür wird die .htaccess Datei benötigt!)
  • Apple Touch und Favicon definieren
  • Suchmaschinen dürfen Links nicht folgen
  • Setzen von noindex für Seiten die nicht gecrawlt werden sollen
  • Externe Links sollen in neuem Tab geöffnet werden
  • Aushebeln der Fileupload Restriktion, somit können alle Arten von Dateien hochgeladen werden
  • IPv6 Ready Logo im Footer
  • Debugging Optionen (einkommentierten, falls benötigt)
  • Wiki Read Only schalten, damit kann niemand etwas editieren

/opt/mediawiki/data/conf/LocalSettings.php

# End of automatically generated settings.
# Add more configuration options below.

# Mailserver connection
$wgSMTP = [
    'host'     => "ssl://YOURMXSERVER", // could also be an IP address. Where the SMTP server is located
    'IDHost'   => "example.org",        // Generally this will be the domain name of your website (aka mywiki.org)
    'port'     => 465,                  // Port to use when connecting to the SMTP server
    'auth'     => true,                 // Should we use SMTP authentication (true or false)
    'username' => "yourmailadress",     // Username to use for SMTP authentication (if being used)
    'password' => "yourpassword"        // Password to use for SMTP authentication (if being used)
];

# E-Mail Adressvalidierung
$wgEmailConfirmToEdit = true;

# Contribution Credits
$wgMaxCredits = 5;

# Short URLs
$wgScriptExtension  = ".php";
$wgArticlePath = "/wiki/$1";
$wgUsePathInfo = true;

# NoIndex for crawlers
$wgNamespaceRobotPolicies[NS_TALK] = 'noindex';
$wgNamespaceRobotPolicies[NS_SPECIAL] = 'noindex';
$wgNamespaceRobotPolicies[NS_MEDIA] = 'noindex';
$wgNamespaceRobotPolicies[NS_FILE] = 'noindex';
$wgNamespaceRobotPolicies[NS_CATEGORY] = 'noindex';
$wgNamespaceRobotPolicies[NS_CATEGORY_TALK] = 'noindex';
#$wgNamespaceRobotPolicies[NS_USER] = 'noindex';

# Apple Touch Icon
$wgAppleTouchIcon = "/images/apple-touch-icon-ipad3.png";

# Favicon
$wgFavicon = "/images/favicon.ico";

# Follow Links
$wgNoFollowLinks = false;

# Externe Links in neuem Fenster
$wgExternalLinkTarget = '_blank';

# File Upload Restriction
$wgStrictFileExtensions = false;
#$wgFileExtensions = array('txt','rar','gz','tar','zip','pdf','png','jpg','jpeg','ogg','doc','xls','ppt','mp3','sxc','nse','ico');
#$wgVerifyMimeType = false;

# IPV6 Ready Logo
$wgFooterIcons['poweredby']['ipv6'] = [
        "src" => "https://ipv6-test.com/button-ipv6-small.png",
        // you may also use a direct path to the source, e.g. "http://example.com/my/custom/path/to/MyCustomLogo.png"
        "url" => "https://ipv6-test.com/validate.php?url=referer",
        "alt" => "ipv6 ready",
        // If you have a non-default sized icon you can specify the size yourself.
        "height" => "31",
        "width" => "88",
];

# VisualEditor
// OPTIONAL: Enable VisualEditor's experimental code features
$wgDefaultUserOptions['visualeditor-enable-experimental'] = 1;
$wgVisualEditorEnableVisualSectionEditing = true;
$wgVisualEditorEnableWikitext = true;
$wgVisualEditorEnableDiffPage = true;

# ReadOnly Mode
#$wgReadOnly = "<h1><b>Ist nur der Mirror. Bitte unter www.laub-home.de editieren</b></h1><br>";
#$wgReadOnly = "<h1><b>Migration Ongoing</b></h1><br>";

# Enable Debugging
#$wgShowExceptionDetails = true;
#$wgShowDBErrorBacktrace = true;

Am besten nach dem Konfigurieren einmal das Projekt Neustarten und den Browser Cache leeren:

cd /opt/mediawiki
docker compose restart

Extensions herunterladen

Möchte man eigene, zusätzliche extensions nutzen, sollten diese im Ordner /opt/mediawiki/data/extensions geladen werden. Ich habe die folgenden Extension integriert. Möchte man diese dann verwenden, einfach im docker-compose.yml diese als Volume in den Container mounten.

Hier die GIT Befehle, für die von mir verwendeten Extensions:

MW_BRANCH=REL1_39
git clone -b $MW_BRANCH "https://gerrit.wikimedia.org/r/mediawiki/extensions/Lockdown"
git clone -b master "https://gerrit.wikimedia.org/r/mediawiki/extensions/WikiCategoryTagCloud"
git clone -b $MW_BRANCH "https://gerrit.wikimedia.org/r/mediawiki/extensions/Description2"
git clone -b $MW_BRANCH "https://gerrit.wikimedia.org/r/mediawiki/extensions/RelatedArticles"
git clone -b $MW_BRANCH "https://gerrit.wikimedia.org/r/mediawiki/extensions/MobileFrontend"
git clone https://github.com/miraheze/RottenLinks.git

nun im docker-compose.yml die entsprechenden Zeilen einkommentierten und das Projekt neu deployen:

docker compose up -d

Nun können die Extension via LocalSettings.php eingebunden und konfiguriert werden.

/opt/mediawiki/data/conf/LocalSettings.php

# End of Standard Extensions and Settings
# enable more Extensions below

# WikiCategoryTagCloud
wfLoadExtension( 'WikiCategoryTagCloud' );

# Enable SelectCategory
require_once "$IP/extensions/SelectCategory/SelectCategory.php";

# Enable Lockdown
wfLoadExtension( 'Lockdown' );
$wgSpecialPageLockdown['Version'] = array('user', 'bureaucrat', 'sysop');
$wgSpecialPageLockdown['Export'] = array('user', 'bureaucrat', 'sysop');
$wgSpecialPageLockdown['Listfiles'] = array('user', 'bureaucrat', 'sysop');
$wgSpecialPageLockdown['Listusers'] = array('user', 'bureaucrat', 'sysop');
$wgSpecialPageLockdown['Statistics'] = array('user', 'bureaucrat', 'sysop');
$wgSpecialPageLockdown['Booksources'] = array('user', 'bureaucrat', 'sysop');
$wgSpecialPageLockdown['Protectedpages'] = array('user', 'bureaucrat', 'sysop');
$wgActionLockdown['history'] = array('user', 'bureaucrat', 'sysop');
$wgActionLockdown['edit'] = array('user', 'bureaucrat', 'sysop');

# Discription2
wfLoadExtension( 'Description2' );
$wgEnableMetaDescriptionFunctions = true;

# Related Articles
wfLoadExtension( 'RelatedArticles' );
$wgRelatedArticlesFooterWhitelistedSkins = ['minerva', 'vector'];
$wgRelatedArticlesDescriptionSource = 'pagedescription';
$wgRelatedArticlesUseCirrusSearchApiUrl = '/api.php';

# Rotten Links Extension
wfLoadExtension( 'RottenLinks' );

Mehr Extensions findet ihr hier:

VisualEditor einbinden

Achtung! Ab Version des MediaWiki 1.35 ist der VisualEditor inklusive dem Parsoid Service im Paket enthalten und Bedarf keiner separaten Einbindung.

Möchte man noch die Extension VisualEditor (Wysigwyg Editor von Wikipedia) einbinden, um ein einfacheres Bearbeiten von Wiki Seiten zu ermöglichen, braucht man zunächst den Container thenets/parsoid:0.10.0. Ich verwende hier ein MediaWiki 1.34, man sollte auf jedenfalls schauen, welche Parsoid Version zum verwendeten MediaWiki passt. Um den besagten Container mit unserer Applikation hochzufahren, fügen wir vor den MediaWiki Part die folgenden Zeilen ein:

/opt/mediawiki/docker-compose.yml

...

  parsoid:
    image: thenets/parsoid:0.10.0
    restart: always
    environment:
      PARSOID_DOMAIN_localhost: http://wiki:80/api.php
    networks:
      backend-nw:
        aliases:
            - parsoid

...

Nun laden wir die VisualEditor Extension in unseren Extension Ordner unter /opt/mediawiki/data/extensions herunter

MW_BRANCH=$(docker exec laubhome_mediawiki_1 env | grep MEDIAWIKI_BRANCH |cut -d"=" -f2)
cd /opt/mediawiki/data/extensions
git clone -b $MW_BRANCH https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor.git
cd VisualEditor
git submodule update --init

Wichtig zu beachten ist, dass wir hier zwingend den Branch in Form von der MediaWiki Version angeben müssen, da der Master nur mit der Alpha Version von MediaWiki lauffähig ist.

Nun aktivieren wir die Extension noch im docker-compose.yml

/opt/mediawiki/docker-compose.yml

...

      # Mediwaiki Extensions
      - ./data/extensions/VisualEditor:/var/www/html/extensions/VisualEditor:ro

...

Nun können wir das Setup deployen:

docker-compose up -d

Nun konfigurieren wir das Ganze noch in der LocalSettings.php

# VisualEditor and Parsoid
wfLoadExtension( 'VisualEditor' );
// Enable by default for everybody
$wgDefaultUserOptions['visualeditor-enable'] = 1;
// Optional: Set VisualEditor as the default for anonymous users
// otherwise they will have to switch to VE
$wgDefaultUserOptions['visualeditor-editor'] = "visualeditor";
// Don't allow users to disable it
$wgHiddenPrefs[] = 'visualeditor-enable';
// OPTIONAL: Enable VisualEditor's experimental code features
#$wgDefaultUserOptions['visualeditor-enable-experimental'] = 1;
$wgVisualEditorEnableVisualSectionEditing = true;
$wgVisualEditorEnableTocWidget = true;
$wgVirtualRestConfig['modules']['parsoid'] = array(
    // URL to the Parsoid instance
    // Use port 8142 if you use the Debian package
    'url' => 'parsoid:8000',
    // Parsoid "domain", see below (optional)
    'domain' => 'localhost',
    // Parsoid "prefix", see below (optional)
    'prefix' => 'localhost'
);

Wenn man jetzt einen Reload seines Wikis macht, sieht man sofort, dass es nun Bearbeiten und Quelltext Bearbeiten gibt. Quelltext Bearbeiten ist der alte WikiEditor, während Bearbeiten zum neuen Visual Editor führen sollte.

Sitemap generieren

Mediawiki bringt ein Skript mit, welches automatisch eine Sitemap generiert. Will man es Manuel ausführen einfach folgenden Befehl nutzen:

docker exec -i <mediawiki_container_name> php maintenance/generateSitemap.php --skip-redirects --server https://<yourdomain> --fspath sitemap --urlpath sitemap/

Hier das Ganze automatisch, alle 4h via Cron-Job.

/etc/cron.d/wikisitemap

#
# Regular cron job for the Wiki Sitemap generation
#
15 */4 * * *      root   docker exec -i <mediawiki_container_name> php maintenance/generateSitemap.php --skip-redirects --server https://<yourdomain> --fspath sitemap --urlpath sitemap/

Apple Touch Icons

Optional:

Vector-2022 als Standard Skin

Möchtet ihr den neuen Vector-2022 Skin als Default haben, sucht $wgDefaultSkin Parameter in der LocalSettings.php und ändert ihn wie folgt ab. Solltet ihr den Parameter gar nicht haben, einfach einfügen.

LocalSettings.php

## Default skin: you can change the default skin. Use the internal symbolic
## names, ie 'vector', 'monobook':
#$wgDefaultSkin = "vector";
$wgDefaultSkin = 'vector-2022';

Mobile Theme

Will man den selben Mobile Theme wie Wikipedia zur Verfügung stellen, dann die folgende Anleitung nutzen:

Migration eines bestehenden MediaWikis

Hat man bereits auf einem anderen System eine Mediawiki Installation, dann kann man diese einfach in die neue Container basierte integrieren.

Backup des Projektes

  • das MediaWiki Images Volume muss gesichert werden
  • MariaDB Datenbank muss via mysqldump gesichert werden

wie das geht, erfahrt ihr hier:

Update des Mediawiki

Will man das MediaWiki docker compose Projekt aktualisieren, dann muss zunächst das gesamte Projekt undeployt werden:

cd /opt/mediawiki
docker compose down

Solltet ihr nicht mit der latest Version im .env file arbeiten, solltet ihr nun die neue Version konfigurieren.

nun kann mit dem PULL das komplette Projekt / die Container aktualisiert werden:

docker compose pull

Das Ganze kann auch Watchtower übernehmen und die Container automatisch aktualisieren.

nun alle Extensions manuell aktualisieren

cd data/extensions/EXTENSIONFOLDER
git pull

Solltet ihr ein neues MediaWiki Release verwenden, müssen die passenden Extension heruntergeladen werden. Hierfür am besten alle Extension löschen und neu herunterladen.

oder via Script alle automatisch aktualisieren:

Nun das Ganze wieder hochfahren:

docker compose up -d

und nun alle Funktionen testen!

Quellen