User:Tim/NethackWikiLocalUpgrade

From NetHackWiki
Jump to navigation Jump to search

Local NetHackWiki Docker Setup

This documents how to create a local Docker-based mirror of nethackwiki.com, using the same MediaWiki version and extensions as production.

End Goal Specs

  • MediaWiki: 1.45.1 (upgraded from 1.32.5 — see Upgrade section below)
  • PHP: 8.3.30 (apache2handler)
  • MySQL: 8.4.5 (production) — we use 8.0 locally (see MySQL note below)
  • ICU: 63.1

Prerequisites

  • Docker + Docker Compose v2 (docker compose)
  • The NetHackWiki dumps in ./nethackwiki-dumps/:
    • nethackwiki_current.xml (XML article dump)
    • nethackwiki_current_images.tar.gz (images)
  • The files in this repo:
    • docker-compose.yaml
    • LocalSettings.php
    • install-extensions.sh
    • extensions/ (custom Paxed extensions)

MySQL version note

Production runs MySQL 8.4. However, MySQL 8.4 removed mysql_native_password entirely, and PHP 7.2’s mysqli driver cannot authenticate with caching_sha2_password. We therefore use mysql:8.0 which still supports mysql_native_password. The --default-authentication-plugin=mysql_native_password flag is set in docker-compose.yaml.

Directory structure

nethack-zim/
├── docker-compose.yaml
├── LocalSettings.php
├── install-extensions.sh           (clones gerrit extensions + skins to host)
├── local-docker-setup.md           (this file)
├── extensions/                     (custom Paxed extensions, bind-mounted)
│   ├── MixedSyntaxHighlight/
│   ├── ReplaceCharsBlock/
│   ├── SimpleTabs/
│   └── RandomPageTitle/
├── extensions-gerrit/              (gerrit-cloned extensions, bind-mounted)
│   ├── AbuseFilter/
│   ├── ArticleMetaDescription/
│   ├── CharInsert/
│   ├── DPLforum/
│   ├── EasyTimeline/
│   ├── Editcount/
│   ├── LabeledSectionTransclusion/
│   ├── Math/
│   ├── NewUserMessage/
│   ├── RandomSelection/
│   ├── Scribunto/
│   ├── TextExtracts/
│   └── TitleKey/
├── skins/                          (manually downloaded skins, bind-mounted)
│   └── DarkVector/                 (downloaded from github.com/dolfinus/DarkVector @ 617616f)
├── skins-gerrit/                   (gerrit-cloned skins, bind-mounted)
│   ├── Modern/
│   └── CologneBlue/
└── nethackwiki-dumps/
    ├── nethackwiki_current.xml
    └── nethackwiki_current_images.tar.gz

Setup steps

1. Clone extensions and skins to host

All extensions and skins are bind-mounted from the host into the container, so they survive container recreates without needing to re-clone.

bash install-extensions.sh

This clones all gerrit extensions into ./extensions-gerrit/ and the Modern + CologneBlue skins into ./skins-gerrit/. Existing dirs are skipped on re-run.

See Code Here: https://nethackwiki.com/wiki/User:Tim/NethackWikiLocalUpgrade/install-extensions.sh

2. Download DarkVector skin

DarkVector is not on gerrit. Download from GitHub at the commit matching production:

mkdir -p skins/DarkVector
curl -L https://github.com/dolfinus/DarkVector/archive/617616f.tar.gz \
  | tar -xz --strip-components=1 -C skins/DarkVector

3. Start containers (without LocalSettings.php mount)

MW’s install.php refuses to run if LocalSettings.php already exists. Temporarily comment out the LocalSettings.php bind-mount in docker-compose.yaml:

# - ./LocalSettings.php:/var/www/html/LocalSettings.php:ro

Then start:

docker compose up -d

4. Run the MW installer

This creates the database schema and admin user:

docker exec nethack-zim-mediawiki-1 php /var/www/html/maintenance/install.php \
  --dbtype mysql \
  --dbserver db \
  --dbname nethackwiki \
  --dbuser wikiman \
  --dbpass wikiman \
  --pass adminpassword \
  "NetHackWiki" "Admin"

The installer generates a LocalSettings.php inside the container — discard it, we use our own.

5. Add the LocalSettings.php mount and recreate the container

Uncomment the LocalSettings.php line in docker-compose.yaml, then:

docker compose up -d

/wiki/ URL format: docker-compose.yaml bind-mounts mediawiki-vhost.conf into the container as the default Apache vhost. That config adds a RewriteRule mapping /wiki/Article_Name/index.php/Article_Name, matching the production URL format. LocalSettings.php must have $wgArticlePath = "/wiki/$1"; (already set) for internal links to use this format. Without these two together, wiki links use the ugly /index.php/Article_Name format.

6. Run update.php to apply extension DB schemas

docker exec nethack-zim-mediawiki-1 php /var/www/html/maintenance/update.php --quick

7. Import the XML dump

This takes approximately 1.5–2 hours for the full NetHackWiki dump (~37,500 pages):

docker exec nethack-zim-mediawiki-1 php /var/www/html/maintenance/importDump.php \
  /mnt/dumps/nethackwiki_current.xml

8. Extract images

docker exec nethack-zim-mediawiki-1 bash -c \
  "tar -xzf /mnt/dumps/nethackwiki_current_images.tar.gz \
   -C /var/www/html/images/ --strip-components=1"

9. Register images in the database

Extracting the tarball puts images on disk, but MediaWiki also needs them registered in the image DB table for File: pages to work. Run rebuildImages.php to scan the images directory and populate the table (~10 min for the full set):

docker exec -d nethack-zim-mediawiki-1 bash -c \
  'php /var/www/html/maintenance/run.php rebuildImages.php --missing \
   > /tmp/rebuildImages.log 2>&1'
# Tail progress:
docker exec nethack-zim-mediawiki-1 tail -f /tmp/rebuildImages.log

10. Post-import maintenance

docker exec nethack-zim-mediawiki-1 php /var/www/html/maintenance/run.php rebuildall.php
docker exec nethack-zim-mediawiki-1 php /var/www/html/maintenance/run.php initSiteStats.php --update

11. Access the wiki

Open http://localhost:8080 in your browser.

Database backup and restore

Export (dump to host)

docker exec nethack-zim-db-1 mysqldump -u wikiman -pwikiman nethackwiki \
  | gzip > nethackwiki-dumps/nethackwiki_db.sql.gz

The PROCESS privilege warning is harmless — tablespace metadata is skipped but all table data is intact.

Restore from dump

gunzip -c nethackwiki-dumps/nethackwiki_db.sql.gz \
  | docker exec -i nethack-zim-db-1 mysql -u wikiman -pwikiman nethackwiki

Extensions

Bundled in mediawiki:1.45 (no install needed)

CategoryTree, Cite, ConfirmEdit, ConfirmEdit/QuestyCaptcha, ImageMap, InputBox, Nuke, ParserFunctions, PdfHandler, Poem, ReplaceText, SyntaxHighlight_GeSHi, WikiEditor

Note: Interwiki was bundled in MW 1.32 but was removed from the core bundle in MW 1.45.

Cloned by install-extensions.sh (gerrit REL1_43, except Scribunto → ./extensions-gerrit/)

Extension Gerrit repo
AbuseFilter mediawiki/extensions/AbuseFilter
ArticleMetaDescription mediawiki/extensions/ArticleMetaDescription
CharInsert mediawiki/extensions/CharInsert
DPLforum mediawiki/extensions/DPLforum
EasyTimeline mediawiki/extensions/timeline (cloned to EasyTimeline/)
Editcount mediawiki/extensions/Editcount
LabeledSectionTransclusion mediawiki/extensions/LabeledSectionTransclusion
Math mediawiki/extensions/Math
NewUserMessage mediawiki/extensions/NewUserMessage
RandomSelection mediawiki/extensions/RandomSelection
Scribunto mediawiki/extensions/Scribunto (REL1_45 — see note below)
TextExtracts mediawiki/extensions/TextExtracts
TitleKey mediawiki/extensions/TitleKey

Note: EasyTimeline’s gerrit repo is named timeline, not EasyTimeline.

Scribunto branch note: All gerrit extensions are cloned at REL1_45 (matching the MediaWiki version). Earlier REL1_32 and REL1_43 Scribunto builds produce a TypeError on pages using Lua modules due to a MediaWiki\Title\Title namespace issue that was fixed in the REL1_45 branch.

Custom Paxed extensions (bind-mounted from ./extensions/)

These are NethackWiki-specific extensions written by Pasi Kallinen (Paxed). Source was reconstructed from Paxed’s user page on nethackwiki.com.

Extension Description
MixedSyntaxHighlight magic word to auto-tag C code blocks
ReplaceCharsBlock Template block for character/item substitution tables
SimpleTabs <tabs> tag for tabbed content
RandomPageTitle parser function

Compatibility notes for Paxed extensions (by version hop):

  • MixedSyntaxHighlight (broke at 1.35→1.42): Replaced ParserBeforeStrip hook (removed MW 1.36, deprecated 1.35) with ParserBeforeInternalParse. Also replaced InternalParseBeforeSanitize hook (removed MW 1.40, deprecated 1.35) — this was already gone before 1.42. Replaced MagicWord::get() static (removed MW 1.40) with MagicWordFactory.
  • ReplaceCharsBlock (broke at 1.35→1.42 and 1.42→1.45): Replaced Article::getRevision() + Revision::RAW (removed ~MW 1.36) with RevisionStore::getRevisionByTitle() and SlotRecord::MAIN. Updated Title:: to \MediaWiki\Title\Title::. Replaced static ContentHandler::getContentText($content) (removed MW 1.45) with $content->getText().
  • RandomPageTitle (broke at 1.35→1.42 and 1.42→1.45): Replaced wfGetDB() (deprecated MW 1.42) with DBLoadBalancer::getConnection(). Updated select()/fetchObject() to newSelectQueryBuilder(). Replaced categorylinks.cl_to column access (removed MW 1.43) with a join via the linktarget table. Updated Title:: to \MediaWiki\Title\Title::.
  • SimpleTabs: No changes needed, works as-is in MW 1.45.

Skins

Bundled in mediawiki:1.45

MonoBook, Vector, Timeless, MinervaNeue, CologneBlue, Modern (loaded via wfLoadSkin())

Cloned by install-extensions.sh (gerrit REL1_43 → ./skins-gerrit/)

Skin Gerrit repo
Modern mediawiki/skins/Modern
CologneBlue mediawiki/skins/CologneBlue

DarkVector (manually downloaded → ./skins/)

Downloaded from github.com/dolfinus/DarkVector at commit 617616f (matches production). Uses skin.json for registration; loaded in LocalSettings.php with:

wfLoadSkin('DarkVector');

Note: DarkVector uses the old SkinTemplate-based API removed in MW 1.40. It loads without crashing the wiki but fails if selected as the active skin. The default skin is Vector — DarkVector remains registered in the skin list for reference.

Upgrade from MW 1.32.5 to MW 1.45

The wiki was originally set up with MediaWiki 1.32.5 (matching production at the time). In Feb 2026, it was upgraded to MW 1.45.1.

Upgrade path

Direct 1.32 → 1.45 is not supported. The upgrade was done in hops:

1.32.5 → 1.35 → 1.42 → 1.45

Each hop: update the image tag in docker-compose.yaml, run docker compose up -d, then run update.php.

Running update.php safely

Launch in background so you can tail the log without risk of interruption:

docker exec -d nethack-zim-mediawiki-1 bash -c \
  'php /var/www/html/maintenance/update.php --quick > /tmp/update.log 2>&1'
# Check it's still running:
docker exec nethack-zim-mediawiki-1 pgrep -a php
# Tail the log:
docker exec nethack-zim-mediawiki-1 tail -f /tmp/update.log

MW 1.35 and 1.42 both crash mid-run on already-applied patches (harmless). A second run exits cleanly with code 0 — that is the confirmed-success state.

Breaking changes encountered

Change Version hop Fixed by
Paxed extension hook removals (ParserBeforeStrip, InternalParseBeforeSanitize, MagicWord::get()) 1.35→1.42 Updated PHP in MixedSyntaxHighlight
Article::getRevision() + Revision::RAW removed (~MW 1.36) 1.35→1.42 Updated ReplaceCharsBlock to use RevisionStore API
wfGetDB() deprecated (MW 1.42) 1.35→1.42 Updated RandomPageTitle to use DBLoadBalancer
Title class moved to MediaWiki\Title\Title namespace 1.35→1.42 Updated all usages to fully-qualified name
div.thumb.tright float dropped from mediawiki.legacy.shared CSS 1.35→1.42 Added inline style="float:right; ..." to Template:Monster outer div (see Wiki template changes below)
Scribunto REL1_43 TypeError with MediaWiki\Title\Title 1.42→1.45 Re-cloned Scribunto at REL1_45
categorylinks.cl_to column removed (MW 1.43) 1.42→1.45 Updated RandomPageTitle to join via linktarget table
ContentHandler::getContentText($content) static removed (MW 1.45) 1.42→1.45 Updated ReplaceCharsBlock to use $content->getText()
Interwiki extension removed from MW core bundle (MW 1.45) 1.42→1.45 Commented out in LocalSettings.php
ConfirmEdit/QuestyCaptcha subextension load syntax changed 1.42→1.45 Changed to wfLoadExtension('ConfirmEdit/QuestyCaptcha')

Re-cloning extensions at REL1_45

After upgrading to MW 1.42+, all gerrit extensions must be re-cloned at REL1_45:

rm -rf extensions-gerrit/ skins-gerrit/
bash install-extensions.sh
docker compose restart mediawiki

Troubleshooting

500 error on first load

Enable exception details temporarily to diagnose:

// Add to bottom of LocalSettings.php
$wgShowExceptionDetails = true;

Then restart the container (docker compose restart mediawiki) and visit the page. Remove the setting once resolved.

Common causes: - Extension magic word not registered (add .i18n.magic.php) - Extension requires binary not present in container (e.g. texvc for Math) - DB schema not applied (run update.php)

PHP OPcache stale after file edit

After editing a bind-mounted PHP file, restart the container to clear OPcache:

docker compose restart mediawiki

install.php fails with “LocalSettings.php already exists”

Remove or temporarily comment the LocalSettings.php volume mount from docker-compose.yaml, then docker compose up -d before running install.php.

MySQL auth error

If you see caching_sha2_password errors, ensure the db service uses mysql:8.0 (not 8.4) with --default-authentication-plugin=mysql_native_password in the command flags.

Wiki template changes (production replication required)

These are changes made to wiki templates/pages stored in the database. They are not captured in git and must be manually replicated to production.

Template:Monster — MW 1.45 float fix

Problem: In MW 1.45, the mediawiki.legacy.shared CSS module was dropped. That module provided div.thumb.tright { float: right }, which the monster infobox template relied on to float right next to article text.

Symptom: On any monster page (e.g. Fog_cloud, Killer_bee), the infobox table appeared full-width above the article text instead of floating right.

Fix applied locally: Edited Template:Monster to add inline float styles to the outer wrapper <div>:

-<div class="thumb tright">
+<div class="thumb tright" style="float:right; clear:right; margin:0.5em 0 1.3em 1.4em;">

Why not <figure>: MediaWiki’s wikitext parser does not allow <figure> as raw HTML in templates — it gets escaped to &lt;figure&gt;. Inline styles on the existing div are the correct workaround for templates that cannot use Lua/raw HTML.

To replicate on production: 1. Go to https://nethackwiki.com/wiki/Template:Monster 2. Edit the template (requires admin/template-editor rights) 3. On the first line inside <includeonly>, change: <div class="thumb tright"> to: <div class="thumb tright" style="float:right; clear:right; margin:0.5em 0 1.3em 1.4em;"> 4. Save with summary: MW 1.45 compat: restore float:right lost when mediawiki.legacy.shared was dropped

Note: Template:Infobox_Monster is just a redirect to Template:Monster — only Template:Monster needs to be edited.