Wiki.tetrain.com Upgrade Plan
Status: live in production (2026-07-25). wiki.tetrain.com now serves the migrated MediaWiki 1.43.9 site on Rocky 9; the old CentOS 7 box is reachable at wiki-old.tetrain.com pending decommission. This document is being written and updated as work proceeds, same living-document pattern as the tornedo.tetrain.com plan.
This is the decision log (why each choice was made, problems hit, alternatives considered). For a reproducible, command-by-command sequence you could actually follow to redo this migration, see wiki.tetrain.com_RUNBOOK.md instead.
1. Source state (read-only discovery, 2026-07-24)[edit]
wiki.tetrain.com (172.105.56.64, aka li2092-64.members.linode.com):
| Layer | Version | Status |
|---|---|---|
| OS | CentOS Linux 7.7.1908 | EOL |
| Kernel | 3.10.0-1062 (2019) | EOL |
| Web server | Apache httpd 2.4.6 | HTTP only, no TLS |
| PHP | 5.4.16 | EOL since Sept 2015 |
| Database | MariaDB 5.5.64 | EOL since April 2020 |
| MediaWiki | 1.18.4 (Feb 2012) | ~14 years old, ~20+ major versions behind |
Data footprint: my_wiki DB 81.6 MB; images/ 444 MB (209 MB thumb cache — regeneratable, 18 MB archive, rest originals); whole install 736 MB. VM itself is tiny (990 MB RAM, 25 GB disk, 4.3 GB used) — data-light migration, most of the risk is in code/extension compatibility, not data volume.
Extensions (12 installed):
- 9 standard/officially-maintained: CheckUser, ConfirmEdit, Gadgets, Nuke, ParserFunctions, Renameuser, TimedMediaHandler, Vector, WikiEditor — current versions exist for any modern MediaWiki release.
- 3 old third-party, unmaintained since 2011-2015, will not run under PHP 8 as-is:
HTML5video(2011) — self-hosted video embed. Functionally superseded byTimedMediaHandler, already installed. Decision: drop, don't port.MsUpload(drag-and-drop bulk upload, v10, Schwindl/Schenone) — has a real mediawiki.org page and known community forks. Needs a compatible-fork check.UserAdmin(2012, Lance Gatlin) — admin panel: add/edit/purge users, mass block, password-reset/welcome emails, for private-wiki tighter control. Old, possibly abandoned upstream; core MediaWiki's own user-management special pages cover much of this now.
No TLS currently configured anywhere (no mod_ssl, no certbot).
2. Why this is not an in-place/leapp-style upgrade[edit]
- PHP 5.4 → 8.x is a language-level break — MediaWiki 1.18's own code will not run under PHP 8 (removed functions, changed OOP semantics). No version of "just bump PHP under the existing codebase" exists.
- MediaWiki's own upgrade policy does not support jumping ~20 major versions directly. Confirmed via mediawiki.org and the project's own UPGRADE file: "upgrading from releases older than two LTS releases is not supported... upgrade to a more recent LTS version first, then to this version." For a source as old as 1.18 (pre-dates the first LTS release in this scheme), the safe/documented path is to walk every LTS stop in sequence.
3. Chosen approach[edit]
- Target OS: Rocky Linux 9 (chosen over 10 — more production-proven at this point).
- Target MediaWiki: 1.43 LTS (supported through Dec 2027; requires PHP 8.1+, MariaDB 10.1+/MySQL 5.5.8+). Chosen over the newer 1.46 stable for production stability.
- Migration mechanism: disposable Docker containers, one per LTS hop, since the hop chain needs several different PHP versions that can't sanely coexist natively on one Rocky 9 box. Official MediaWiki Docker Hub images only retain current-era tags, so each hop is built from the official
phpimage (which does keep full historical tags) plus the matching MediaWiki release tarball downloaded directly from releases.wikimedia.org. - LTS hop chain (confirmed via mediawiki.org release history — Compatibility, Manual:Upgrading): 1.18.4 (source) → 1.23.16 → 1.27.7 → 1.31.16 → 1.35.13 → 1.39.11 → 1.43.2. One DB instance (MariaDB 10.11) persists across every hop; only the PHP runtime + MediaWiki codebase change per hop.
update.phprun at each stop reconciles the schema forward; extensions are deliberately *not* loaded during the hop chain (minimalLocalSettings.php, DB connection only) since the goal is walking the core schema, not extension data — extensions get reconciled once on the final 1.43 codebase. - Final production runtime: native (not Docker) on Rocky 9, matching the rest of the fleet's operational pattern — PHP 8.1+, MariaDB 10.11 LTS, httpd or nginx+php-fpm, TLS via Let's Encrypt (client has already pointed DNS at the new box).
4. Target server[edit]
wiki-new.tetrain.com, 172.105.39.56, Rocky Linux 9.8, provided by client 2026-07-24. DNS already pointed here by client. Root access via id_rsa_curio (fleet-standard key). 1 vCPU / 1.9 GB RAM / 49 GB disk.
5. Progress log[edit]
- 2026-07-24: Base OS setup done — hostname set,
dnf updaterun (kernel bumped to 5.14.0-687.29, reboot will be needed before go-live to run the current kernel), firewalld enabled, Docker CE 29.6.2 + compose installed. - 2026-07-24: Backup of source
wiki.tetrain.cominterrupted — its SSH port stopped responding mid-session (ICMP still fine, port 22 silently drops; not an auth issue, no other access path available). Cause unconfirmed (possible fail2ban-style ban, possible resource event on the tiny 990MB-RAM box, possibly provider-side). Backup poller running in background, will resume the backup the moment it's reachable again. - 2026-07-24: On
wiki-new.tetrain.com: persistent MariaDB 10.11 container started for the hop chain (mw-mariadb, networkmwmigrate, data volume/root/mw-hop-migration/db-data). Downloaded all 6 hop-chain release tarballs (1.23.16/1.27.7/1.31.16/1.35.13/1.39.11/1.43.2) into/root/mw-hop-migration/tarballs/. Building 6 Docker images (one per hop, PHP versions 5.6/5.6/7.2/7.4/8.0/8.1 matched to each MediaWiki version's supported range) — in progress. - Real hop-chain execution against actual production data is blocked on the backup (see above) — the mechanics can be smoke-tested on an empty schema, but the meaningful test needs the real 1.18.4 data since that's where any real incompatibility would surface.
- 2026-07-24: All 6 hop Docker images built successfully (PHP 5.6/5.6/7.2/7.4/8.0/8.1 with mysqli, intl, gd, mbstring, calendar, opcache compiled in).
- 2026-07-24: Extension decisions finalized:
HTML5video— drop, superseded byTimedMediaHandler(already installed).MsUpload— turns out to be an official Wikimedia-mirrored extension (not truly third-party as first assessed), actively maintained, confirmed working on 1.43 by other users. Will pullwikimedia/mediawiki-extensions-MsUploadon theREL1_43branch.UserAdmin— confirmed abandoned upstream, no reliable PHP8-compatible fork. Its functionality (add/edit/delete users, group management, password-reset/welcome emails) is fully covered by core MediaWiki's own special pages (Special:UserRights,Special:Block,Special:PasswordReset,Special:CreateAccount). Decision: drop, don't port — flag this explicitly at handover so nobody goes looking for the old UserAdmin panel URL and finds it missing without knowing why.
- 2026-07-24: Production stack built on
wiki-new.tetrain.com, independent of the pending backup:- Apache 2.4.62 + PHP-FPM 8.3.31 (mysqlnd, gd, mbstring, xml, intl, opcache) wired via
proxy:unix:/run/php-fpm/www.sock. - MariaDB 10.11.18, hardened (anonymous users removed, remote root removed, test DB dropped),
my_wikiDB created with a dedicated scopedwikiuseraccount — notrootlike the old box. Credentials generated randomly, stored root-only-readable at/root/.mariadb_root_credentialsand/root/.wiki_db_credentialson the box itself, never transmitted through chat. - firewalld opened for http/https.
- Let's Encrypt cert issued and deployed via certbot (
--redirect, HTTP→HTTPS enforced), auto-renewal configured, expires 2026-10-22. Confirmed serving HTTPS correctly (403 is expected — empty docroot, MediaWiki not deployed yet).
- Apache 2.4.62 + PHP-FPM 8.3.31 (mysqlnd, gd, mbstring, xml, intl, opcache) wired via
- Only remaining blocker for real progress:
wiki.tetrain.comSSH still unreachable (~26 min and counting as of this note) — site itself (HTTP) confirmed still up and serving fine, so this is SSH-specific, not a box-down event. Background poller watching for recovery.
6. Migration completed (2026-07-24) — ready for client testing[edit]
- Backup recovered once
wiki.tetrain.comSSH came back (client confirmed cause: their VPN had disconnected — nothing wrong with the box itself). DB (47MB), images (215MB), and extensions/config (161MB, archival only) transferred towiki-new.tetrain.com, integrity verified via MD5. - Full 6-hop version-hop chain run against the real production data, not just a smoke test: 1.18.4 → 1.23.16 → 1.27.7 → 1.31.16 → 1.35.13 → 1.39.11 → 1.43.9 (switched from the initially-grabbed 1.43.2 to the latest 1.43.x patch after 1.43.2's pinned Composer dependencies hit security-advisory blocks — 1.43.9 resolved cleanly). Every hop's
update.phpcompleted with zero real errors. Data integrity confirmed identical before/after: 1707 pages, 3634 revisions, 163 users. - Migrated DB exported from the migration container and imported into the real production MariaDB (scoped
wikiuseraccount, not root). - MediaWiki 1.43.9 codebase deployed to
/var/www/wiki, Composer dependencies installed properly (composer install --no-dev). - All 9 standard extensions +
MsUploadpulled at theREL1_43branch (CheckUser, ConfirmEdit, Gadgets, Nuke, ParserFunctions, Renameuser, TimedMediaHandler, WikiEditor, Vector skin, MsUpload) — MediaWiki's own 1.43.9 tarball already bundles most of these, only Renameuser/TimedMediaHandler/MsUpload needed fetching separately. Confirmed all 9 loaded correctly viaSpecial:Version. - Images copied in (originals + archive, 236MB total incl. fresh-install defaults), SELinux contexts set correctly (
httpd_sys_rw_content_ton images/cache dirs — Rocky 9 is enforcing by default). LocalSettings.phpwritten fresh for the new environment: properwgServer(HTTPS), freshly generatedwgSecretKey/wgUpgradeKey(not the placeholder used during migration testing), scoped DB credentials pulled from/root/.wiki_db_credentials(never displayed in chat).- End-to-end verification, all passing: homepage loads (200, correct site title "TetraWiki"), a real migrated content page renders correctly (
ISGEC_-_Next_Cloud_Deployment), direct image serving works, on-demand thumbnail generation confirmed working (GD-based, since$wgUseImageMagick = false).
What's deliberately dropped/changed vs. the old site[edit]
HTML5video— dropped from the migration itself (not ported, since it's PHP8-incompatible and functionally superseded byTimedMediaHandlerfor *uploaded* video files). This left every pre-existing YouTube embed on the wiki broken (the tag simply doesn't exist anymore), sinceHTML5videowas actually being used for embedding external YouTube videos, not self-hosted file uploads — a distinct use caseTimedMediaHandlerdoesn't cover. Fixed 2026-07-25, see Section 8 below — this line in earlier versions of this doc said "dropped, superseded by TimedMediaHandler," which undersold the actual user-facing impact and is superseded by that section.UserAdmin— dropped (abandoned upstream, no PHP8-compatible fork). Equivalent functionality now lives in coreSpecial:UserRights,Special:Block,Special:PasswordReset,Special:CreateAccount. Flag this at handover — anyone who goes looking for the old UserAdmin panel URL needs to know it's gone and why.- TLS is now enforced (old site was HTTP-only) — Let's Encrypt, auto-renewing.
- DB access is now a scoped
wikiuseraccount, notrootlike the old box.
Not yet done[edit]
- Old
wiki.tetrain.combox (now atwiki-old.tetrain.com, 172.105.56.64) decommission — DNS cutover is done (Section 9), but the box itself hasn't been shut down/reclaimed yet; still a distinct later decision pending client go-ahead, same gating pattern as every other destructive step in this engagement. - Outbound email is confirmed broken on
wiki-new/wiki.tetrain.com— MediaWiki has$wgEnableEmail/$wgEnableUserEmailon and a sender address configured, but no MTA is installed at all (nosendmail, no Postfix, nothing on port 25; PHP'ssendmail_pathpoints at a binary that doesn't exist). Password resets, "email this user," and watchlist notifications all silently fail right now. Client explicitly deferred this (2026-07-25) — parked until they're ready to take it up. Open question when they do: route through Tetra's existing relay servers (server-relay1/2/3.tetrain.com, used for every other Tetra-hosted mail flow in this fleet) vs. a local Postfix — leaning relay for SPF/deliverability consistency, but needs a decision. TimedMediaHandlerneedsffmpegfor video transcoding if video *uploads* are actually used — not installed yet, wasn't blocking for the text/image content that makes up this wiki, can add if needed. (Separate from the YouTube-embed fix in Section 8, which doesn't touch file uploads.)- Cosmetic:
wgLogopoints at a placeholder path; the old site's custom logo (tetralogo.jpgfrom the oldskins/common/) could be restored if wanted. - Rocky 9 kernel was bumped during initial setup (5.14.0-687.17 → .29) — a reboot is needed at some point to actually run the current kernel; not done yet since this was a live build in progress.
Production URL: https://wiki.tetrain.com/ (live since 2026-07-25). Test/staging alias https://wiki-new.tetrain.com/ still resolves to the same box and still works — both hostnames are on the same Apache vhost and TLS cert now (Section 9).
7. Post-handover fix: logo sizing (2026-07-24)[edit]
Client reported the logo looked wrong on the test site. Root cause was two separate things:
$wgDefaultSkin = "vector"was selecting legacy Vector (SkinVectorLegacy), not modern Vector 2022 (vector-2022,SkinVector22) — MediaWiki 1.43's actual intended default. Legacy Vector uses an old fixed.mw-wiki-logosingle-image class; Vector 2022 uses a proper icon+wordmark structure. Fixed:$wgDefaultSkin = "vector-2022".- Whatever logo was configured (client had already changed
$wgLogoto point at the real tetrain.com company logo,tetra_logo_2017Web.png, 198×399px — tall/narrow, not the oldtetralogo.jpgfrom the original site) was being forced into Vector 2022's fixed 50×50px square icon slot via hardcodedwidth/heightHTML attributes, stretching/distorting it. Fixed: downloaded the logo, hosted it locally (/var/www/wiki/resources/assets/logo/, avoiding a fragile cross-site hotlink to www.tetrain.com), and re-composited it onto properly-sized transparent square canvases (50/75/100px for 1x/1.5x/2x) with the logo letterboxed/centered at its correct aspect ratio rather than stretched. Configured via the modern$wgLogosarray (replacing the legacy single-string$wgLogo).
Verified: served logo image is now genuinely 50×50px matching the skin's fixed slot exactly, no distortion. Cache cleared, confirmed live.
8. Post-handover: YouTube video embed restoration (2026-07-25)[edit]
Discovered as part of the separate Wiki Pages Cleaning project's content audit: dropping HTML5video during the migration (Section 6) broke every pre-existing YouTube embed on the wiki — 149 embeds across 44 pages, all internal KT/training recordings and client-architecture walkthroughs. TimedMediaHandler doesn't cover this use case (it's for self-hosted uploaded video files, not embedding external YouTube links), so this wasn't actually fixed by the original migration decision.
- Platform fix: installed the third-party
EmbedVideoextension (StarCitizenTools/mediawiki-extensions-EmbedVideo— not Wikimedia/Gerrit-hosted, noREL1_43branch, cloned default branch, confirmedextension.jsonsupports MediaWiki ≥1.29.0). Patched a MediaWiki-1.43-incompatibility inEmbedVideo.hooks.php(coreParserOutput::addModules()/addModuleStyles()now require strictarraytyping; EmbedVideo was passing bare strings) — two one-line fixes, verified via a scratch test page with$wgShowExceptionDetailstemporarily enabled, reverted after. Loaded viawfLoadExtension('EmbedVideo')inLocalSettings.php. New embed syntax:{{#ev:youtube|VIDEO_ID|640}}, replacing the dead<HTML5video>tag. - Content fix: for every one of the 149 embeds, retrieved the video's actual YouTube transcript (via browser automation — auto-captions, not audio playback) and wrote an accurate summary paragraph published directly under each embed on its wiki page. Quality varies with source audio: most got full detailed summaries; ~25 are explicitly flagged
[VERY POOR TRANSCRIPT QUALITY]or[PARTIAL TRANSCRIPT]where ASR/audio quality only allowed a partial or topic-level summary — flagged rather than guessed. 5 videos are outright inaccessible and flagged as such: 1 private, 4 removed by YouTube (3 for harassment/bullying policy, 1 general ToS violation — all 4 removals landed on the sameTraining_2022_Linux_teampage, worth raising with whoever owns that YouTube account since repeated strikes risk the account itself). 2 duplicate-content pairs identified and cross-referenced instead of re-summarized. All findings are written directly into the paragraphs published on the wiki, so they're visible to anyone reading the page, not just in this doc. - Publish mechanism: pulled current wikitext per page via
php maintenance/run.php getText.php "<title>", replaced each<HTML5video>...</HTML5video>tag with the{{#ev:...}}embed plus a'''Video summary:'''paragraph, applied viaphp maintenance/run.php edit.php -u Admin -b --nocreate "<title>"(stdin). Note: most of these 44 "pages" are actuallyCategory:-namespace pages being used to hold real content (a pre-existing wiki quirk, not introduced by this work) — titles needed the correct namespace prefix (Category:, orHelp:for one outlier,Editing) to resolve correctly; a plain-namespace title lookup silently reports "page does not exist" otherwise. - Verified: DB sweep confirms zero leftover
<HTML5video>tags across all 44 pages; spot-checked in-browser that embeds render as real<iframe>elements (not just wikitext), including the largest page (50 videos, first/last IDs both confirmed rendering correctly).
9. Post-handover: production DNS cutover (2026-07-25)[edit]
Client updated DNS directly (no registrar/API access was available in this environment to do it here): wiki.tetrain.com A record repointed from the old CentOS 7 box (172.105.56.64) to wiki-new.tetrain.com (172.105.39.56), and a new wiki-old.tetrain.com A record created pointing at the old box so it stays reachable post-cutover.
DNS alone wasn't sufficient — two things on the server side would have made the real domain look broken to visitors even with DNS correct, both found and fixed same-day:
- TLS certificate didn't cover the real domain. The existing Let's Encrypt cert (Section 5) only had
wiki-new.tetrain.comin its SAN list; hittinghttps://wiki.tetrain.comfell through to Apache's default self-signed cert (browser security warning). Expanded the same cert lineage viacertbot --apache -d wiki-new.tetrain.com -d wiki.tetrain.com --expand. Certbot issued the expanded cert but couldn't auto-install it into the vhost (ambiguous vhost match, noServerAliasdeclared) — fixed manually by addingServerAlias wiki.tetrain.comto both the port-80 and port-443 vhost blocks (/etc/httpd/conf.d/wiki.conf,wiki-le-ssl.conf, both backed up before editing) and broadening the HTTP→HTTPSRewriteCondto match either hostname. $wgServerstill pointed at the old hostname. MediaWiki would have kept generating every internal link, canonical URL, and redirect againstwiki-new.tetrain.comeven with the correct cert and DNS in place. Updated$wgServertohttps://wiki.tetrain.cominLocalSettings.php(backed up first).
Verified end-to-end: valid cert presented for both hostnames (confirmed via SNI-specific TLS handshake against each), http:// → https:// redirect works for both, full redirect chain to Main_Page returns 200 OK, and a video-embed page (Section 8) renders correctly — iframe present — when loaded via https://wiki.tetrain.com. wiki-old.tetrain.com resolves to and serves the old box.
Outbound email was checked as part of this same pass and found broken (see "Not yet done" above) — client explicitly deferred fixing it.