Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
TetraWiki
Search
Search
Appearance
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Wiki.tetrain.com Runbook
Page
Discussion
English
Read
Edit
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
View history
General
What links here
Related changes
Special pages
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
This is a reproducible, step-by-step runbook β commands in the order they were actually run, so someone else could redo this migration on a fresh box and land in the same state. It's the companion to [[Wiki.tetrain.com Upgrade Plan|<code><nowiki>wiki.tetrain.com_upgrade_plan.md</nowiki></code>]], which is the decision log (why each choice was made, problems hit, alternatives considered). Read that first for context; use this to actually execute. '''Provenance note on exactness''': every command in Phases 3, 5-8 was either captured live in this session or reconstructed from artifacts still present on the server (Docker image layer history via <code><nowiki>docker history --no-trunc</nowiki></code>, <code><nowiki>.git</nowiki></code> remotes/branches on installed extensions, live config files, <code><nowiki>certbot</nowiki></code>'s own renewal-params file). Phases 1-2 predate what this session could verify command-by-command (interactive shell, no bash history retained) β those steps are given as the standard/equivalent command for what the decision log describes, '''explicitly marked''' <code><nowiki>[reconstructed]</nowiki></code> where the literal originally-run command isn't recoverable. Nothing below is guessed silently. ---- == Phase 1 β Target server base setup <code><nowiki>[reconstructed β standard equivalents]</nowiki></code> == Run on the fresh Rocky Linux 9 box (<code><nowiki>wiki-new.tetrain.com</nowiki></code>, provided by client with DNS already pointed at it). <pre> <nowiki> hostnamectl set-hostname wiki-new.tetrain.com dnf update -y # kernel gets bumped by this update; a reboot is needed later to actually run it (Phase 8 covers # the reboot that happened, driven by other work β if doing this fresh, reboot here instead) systemctl enable --now firewalld firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload # Docker CE (official repo, not the distro's own docker package) dnf install -y dnf-plugins-core dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin systemctl enable --now docker </nowiki> </pre> '''Verify''': <code><nowiki>docker ps</nowiki></code> runs without error; <code><nowiki>firewall-cmd --list-services</nowiki></code> shows <code><nowiki>http https ssh</nowiki></code> (confirmed live state β <code><nowiki>dhcpv6-client</nowiki></code> and <code><nowiki>cockpit</nowiki></code> are also present on the real box, likely Rocky defaults, harmless). ---- == Phase 2 β Retrieve source data from the old server <code><nowiki>[reconstructed β standard equivalents]</nowiki></code> == On <code><nowiki>wiki.tetrain.com</nowiki></code> (old CentOS 7 box, 172.105.56.64 at the time): <pre> <nowiki> # DB dump mysqldump -u root my_wiki > my_wiki_source.sql # 49MB # images + config/extensions, packaged for transfer tar czf images.tar.gz -C /var/www/wiki images # 215MB uncompressed source tar czf config_and_code.tar.gz -C /var/www/wiki extensions LocalSettings.php skins # 161MB, archival only </nowiki> </pre> Transfer both to the new box (<code><nowiki>scp</nowiki></code> or equivalent) into <code><nowiki>/root/mw-hop-migration/</nowiki></code>: <pre> <nowiki> mkdir -p /root/mw-hop-migration scp root@<old-box>:my_wiki_source.sql /root/mw-hop-migration/ scp root@<old-box>:images.tar.gz /root/mw-hop-migration/ scp root@<old-box>:config_and_code.tar.gz /root/mw-hop-migration/ </nowiki> </pre> '''Verify integrity''' (this session used MD5, confirmed matching before/after transfer): <pre> <nowiki> md5sum my_wiki_source.sql images.tar.gz config_and_code.tar.gz # compare against source-side sums </nowiki> </pre> All three files are still present on the live box at <code><nowiki>/root/mw-hop-migration/</nowiki></code> if you need to re-derive anything (49MB SQL, 225MB images tarball, 168MB config/code tarball). ---- == Phase 3 β Docker-based version-hop chain (verified exact β reconstructed from live Docker images) == '''Why Docker per-hop''': the hop chain needs 5 different PHP runtimes (5.6 β 7.2 β 7.4 β 8.0 β 8.1) that can't coexist natively on one Rocky 9 box. Each hop is a disposable container built from the official <code><nowiki>php</nowiki></code> Docker Hub image (which retains every historical tag) plus the matching MediaWiki release tarball downloaded directly from <code><nowiki>releases.wikimedia.org</nowiki></code>. === 3.1 Download the 6 release tarballs === <pre> <nowiki> cd /root/mw-hop-migration mkdir -p tarballs && cd tarballs for v in 1.23.16 1.27.7 1.31.16 1.35.13 1.39.11 1.43.2; do curl -O "https://releases.wikimedia.org/mediawiki/${v%.*}/mediawiki-${v}.tar.gz" done # 1.43.2 was later replaced with 1.43.9 (see 3.5) β its pinned Composer deps hit a security # advisory block; 1.43.9 resolved cleanly: curl -O "https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.9.tar.gz" </nowiki> </pre> (All 7 tarballs β including the superseded 1.43.2 β are still on disk at <code><nowiki>/root/mw-hop-migration/tarballs/</nowiki></code>.) === 3.2 Shared MariaDB container (persists across every hop) === <pre> <nowiki> docker network create mwmigrate mkdir -p /root/mw-hop-migration/db-data docker run -d --name mw-mariadb \ --network mwmigrate \ -e MARIADB_ROOT_PASSWORD=migrate_temp_pw \ -v /root/mw-hop-migration/db-data:/var/lib/mysql \ mariadb:10.11 </nowiki> </pre> (Verified live β this exact container is still running, <code><nowiki>docker inspect mw-mariadb</nowiki></code> confirms the env var, mount, and network above.) Load the source dump into it: <pre> <nowiki> docker exec -i mw-mariadb mariadb -uroot -pmigrate_temp_pw -e "CREATE DATABASE my_wiki;" docker exec -i mw-mariadb mariadb -uroot -pmigrate_temp_pw my_wiki < /root/mw-hop-migration/my_wiki_source.sql </nowiki> </pre> === 3.3 Per-hop Dockerfile (shared template, confirmed exact via <code><nowiki>docker history --no-trunc</nowiki></code>) === One template, parameterized by PHP tag: <pre> <nowiki> # Dockerfile.template ARG PHP_TAG FROM php:${PHP_TAG} RUN apt-get update && apt-get install -y --no-install-recommends \ libicu-dev libpng-dev libjpeg-dev libxml2-dev libonig-dev zlib1g-dev \ && docker-php-ext-configure gd --with-jpeg 2>/dev/null || docker-php-ext-configure gd 2>/dev/null || true \ && docker-php-ext-install mysqli intl gd mbstring calendar opcache 2>&1 | tail -20 \ && rm -rf /var/lib/apt/lists/* </nowiki> </pre> (This is the literal, byte-for-byte content still on disk at <code><nowiki>/root/mw-hop-migration/hops/Dockerfile.template</nowiki></code>; the <code><nowiki>RUN</nowiki></code> line matches exactly what <code><nowiki>docker history --no-trunc mw-hop1-1.23:latest</nowiki></code> shows as that image's top custom layer.) PHP tag per hop (confirmed by running <code><nowiki>php -v</nowiki></code> inside each surviving image): {| class="wikitable" |- ! Hop !! MediaWiki !! PHP tag !! Confirmed running <code><nowiki>php -v</nowiki></code> |- | 1 || 1.23.16 || <code><nowiki>php:5.6-apache</nowiki></code> || PHP 5.6.40 |- | 2 || 1.27.7 || <code><nowiki>php:5.6-apache</nowiki></code> || PHP 5.6.40 |- | 3 || 1.31.16 || <code><nowiki>php:7.2-apache</nowiki></code> || PHP 7.2.34 |- | 4 || 1.35.13 || <code><nowiki>php:7.4-apache</nowiki></code> || PHP 7.4.33 |- | 5 || 1.39.11 || <code><nowiki>php:8.0-apache</nowiki></code> || PHP 8.0.30 |- | 6 || 1.43.9 || <code><nowiki>php:8.1-apache</nowiki></code> || PHP 8.1.34 |} Build each image (repeat per row above): <pre> <nowiki> cd /root/mw-hop-migration/hops mkdir -p hop1-1.23 && cd hop1-1.23 tar xzf ../../tarballs/mediawiki-1.23.16.tar.gz --strip-components=1 -C . --one-top-level=src 2>/dev/null \ || (mkdir -p src && tar xzf ../../tarballs/mediawiki-1.23.16.tar.gz --strip-components=1 -C src) cp ../Dockerfile.template Dockerfile docker build --build-arg PHP_TAG=5.6-apache -t mw-hop1-1.23:latest . cd .. </nowiki> </pre> Repeat for hop2 (<code><nowiki>5.6-apache</nowiki></code>), hop3 (<code><nowiki>7.2-apache</nowiki></code>), hop4 (<code><nowiki>7.4-apache</nowiki></code>), hop5 (<code><nowiki>8.0-apache</nowiki></code>), hop6 (<code><nowiki>8.1-apache</nowiki></code>), substituting the tarball, directory name, and <code><nowiki>PHP_TAG</nowiki></code> each time. '''Verify''': <code><nowiki>docker images</nowiki></code> should list all 6 (still true on the live box today, ~700-850MB each). === 3.4 Run each hop β copy source in, point at shared DB, run <code><nowiki>update.php</nowiki></code> === For each hop, in order (1β2β3β4β5β6), with the *previous* hop's DB state already loaded: <pre> <nowiki> # Example shown for hop 1; same shape for hops 2-6, just swap the image/paths. docker run --rm \ --network mwmigrate \ -v /root/mw-hop-migration/hops/hop1-1.23/src:/var/www/html \ mw-hop1-1.23:latest \ bash -c " cat > /var/www/html/LocalSettings.php <<'EOF' <?php \$wgDBtype = 'mysql'; \$wgDBserver = 'mw-mariadb'; \$wgDBname = 'my_wiki'; \$wgDBuser = 'root'; \$wgDBpassword = 'migrate_temp_pw'; \$wgServer = 'http://localhost'; \$wgScriptPath = ''; EOF php maintenance/update.php --quick " </nowiki> </pre> Minimal <code><nowiki>LocalSettings.php</nowiki></code> only β '''no extensions loaded during the hop chain''', deliberately: the goal at this stage is walking the core DB schema forward through every LTS version, not reconciling extension-specific schema/data, which happens once at the end on the final 1.43 codebase (Phase 5). '''Verify after every hop''' before moving to the next: <code><nowiki>update.php</nowiki></code> exits 0 with no fatal errors; spot-check row counts are unchanged (<code><nowiki>SELECT COUNT(*) FROM page;</nowiki></code> etc. inside the mariadb container) β this session confirmed 1707 pages / 3634 revisions / 163 users identical before and after the full chain. === 3.5 Final hop note β 1.43.2 β 1.43.9 substitution === Hop 6 was first attempted against <code><nowiki>mediawiki-1.43.2.tar.gz</nowiki></code>; its pinned <code><nowiki>composer.lock</nowiki></code> hit a security-advisory-driven dependency block during <code><nowiki>composer install</nowiki></code>. Fix: re-extracted <code><nowiki>mediawiki-1.43.9.tar.gz</nowiki></code> in its place (rebuilt <code><nowiki>hop6-1.43</nowiki></code>'s <code><nowiki>src/</nowiki></code> from the newer tarball) β same PHP tag (<code><nowiki>8.1-apache</nowiki></code>), same Dockerfile, same <code><nowiki>update.php --quick</nowiki></code> invocation. No other hop was affected. ---- == Phase 4 β Production stack (verified exact β matches live installed packages/config) == On the same Rocky 9 box, independent of the Docker hop chain (which is only used to walk the DB schema forward β production runs natively, not in Docker). === 4.1 Packages === <pre> <nowiki> dnf install -y httpd mod_ssl dnf module reset php -y dnf module enable php:8.3 -y # confirms which stream β live box runs 8.3.31 dnf install -y php php-fpm php-mysqlnd php-gd php-mbstring php-xml php-intl php-opcache dnf install -y mariadb-server mariadb-backup dnf install -y certbot python3-certbot-apache </nowiki> </pre> (Exact versions confirmed live: <code><nowiki>httpd-2.4.62</nowiki></code>, <code><nowiki>php-8.3.31</nowiki></code>/<code><nowiki>php-fpm-8.3.31</nowiki></code>, <code><nowiki>mariadb-server-10.11.18</nowiki></code>, <code><nowiki>certbot-3.1.0</nowiki></code>.) === 4.2 PHP-FPM β Apache wiring === <code><nowiki>/etc/php-fpm.d/www.conf</nowiki></code> (confirmed live values): <pre> <nowiki> listen = /run/php-fpm/www.sock listen.acl_users = apache,nginx listen.allowed_clients = 127.0.0.1 </nowiki> </pre> Apache vhost routes <code><nowiki>.php</nowiki></code> to that socket (see the full vhost block in Phase 8, which shows the final version after the DNS-cutover edit β the original pre-cutover version was identical minus the <code><nowiki>ServerAlias</nowiki></code>): <pre> <nowiki> <FilesMatch \.php$> SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost" </FilesMatch> </nowiki> </pre> <pre> <nowiki> systemctl enable --now php-fpm systemctl enable --now httpd </nowiki> </pre> === 4.3 MariaDB β hardened, scoped DB user (not root) === <pre> <nowiki> systemctl enable --now mariadb mysql_secure_installation # [reconstructed] β remove anonymous users, remove remote root, # drop test DB; interactive, answers: Y to all prompts, set a root # password when asked mysql -u root -p <<'EOF' CREATE DATABASE my_wiki CHARACTER SET binary; CREATE USER 'wikiuser'@'localhost' IDENTIFIED BY '<random-generated-password>'; GRANT ALL PRIVILEGES ON my_wiki.* TO 'wikiuser'@'localhost'; FLUSH PRIVILEGES; EOF </nowiki> </pre> Credentials were generated randomly and stored root-only-readable at <code><nowiki>/root/.mariadb_root_credentials</nowiki></code> and <code><nowiki>/root/.wiki_db_credentials</nowiki></code> on the box β never in chat, never in this doc. Confirmed live: <code><nowiki>wikiuser</nowiki></code>@<code><nowiki>localhost</nowiki></code> exists and is what <code><nowiki>LocalSettings.php</nowiki></code> actually uses (<code><nowiki>$wgDBuser = "wikiuser"</nowiki></code>), not <code><nowiki>root</nowiki></code>. === 4.4 Firewall + TLS === <pre> <nowiki> firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload certbot --apache -d wiki-new.tetrain.com --non-interactive --agree-tos \ -m root@wiki-new.tetrain.com --redirect </nowiki> </pre> Confirmed live via <code><nowiki>/etc/letsencrypt/renewal/wiki-new.tetrain.com.conf</nowiki></code>: <code><nowiki>authenticator = apache</nowiki></code>, <code><nowiki>installer = apache</nowiki></code>, ECDSA key type, auto-renewal configured. This is the exact same command pattern used again in Phase 8 to expand the cert β see there for the real, later-run command including <code><nowiki>--expand</nowiki></code>. '''Verify''': <code><nowiki>curl -I https://wiki-new.tetrain.com/</nowiki></code> returns a real TLS handshake (this session's original note: "confirmed serving HTTPS correctly, 403 expected β empty docroot, MediaWiki not deployed yet" at this point in the sequence). ---- == Phase 5 β Deploy migrated MediaWiki 1.43.9 to production == === 5.1 Export from the hop chain, import into production MariaDB === <pre> <nowiki> docker exec mw-mariadb mariadb-dump -uroot -pmigrate_temp_pw my_wiki > /root/mw-hop-migration/my_wiki_migrated_1.43.sql mysql -u wikiuser -p my_wiki < /root/mw-hop-migration/my_wiki_migrated_1.43.sql </nowiki> </pre> (The migrated dump β 26.5MB β is still on disk at <code><nowiki>/root/mw-hop-migration/my_wiki_migrated_1.43.sql</nowiki></code> if you need to re-import.) === 5.2 Deploy the codebase === <pre> <nowiki> mkdir -p /var/www/wiki tar xzf /root/mw-hop-migration/tarballs/mediawiki-1.43.9.tar.gz --strip-components=1 -C /var/www/wiki cd /var/www/wiki curl -sS https://getcomposer.org/installer | php php composer.phar install --no-dev </nowiki> </pre> === 5.3 Extensions β 9 standard + MsUpload === Most of the 9 (<code><nowiki>CheckUser</nowiki></code>, <code><nowiki>ConfirmEdit</nowiki></code>, <code><nowiki>Gadgets</nowiki></code>, <code><nowiki>Nuke</nowiki></code>, <code><nowiki>ParserFunctions</nowiki></code>, <code><nowiki>WikiEditor</nowiki></code>, plus many more not in the original list) already ship inside the 1.43.9 tarball itself β only <code><nowiki>Renameuser</nowiki></code>, <code><nowiki>TimedMediaHandler</nowiki></code>, and <code><nowiki>MsUpload</nowiki></code> needed fetching separately: <pre> <nowiki> cd /var/www/wiki/extensions git clone --branch REL1_43 https://gerrit.wikimedia.org/r/mediawiki/extensions/Renameuser.git git clone --branch REL1_43 https://gerrit.wikimedia.org/r/mediawiki/extensions/TimedMediaHandler.git git config --global --add safe.directory /var/www/wiki/extensions/MsUpload git clone --branch REL1_43 https://github.com/wikimedia/mediawiki-extensions-MsUpload.git MsUpload </nowiki> </pre> (Confirmed live: <code><nowiki>MsUpload</nowiki></code>'s <code><nowiki>.git</nowiki></code> remote is exactly <code><nowiki>https://github.com/wikimedia/mediawiki-extensions-MsUpload.git</nowiki></code>, branch <code><nowiki>REL1_43</nowiki></code>, current commit <code><nowiki>0c261546d07d9cdd152541e220b14a8a969b58a</nowiki></code>.) <code><nowiki>UserAdmin</nowiki></code> and <code><nowiki>HTML5video</nowiki></code> are '''not''' cloned here β dropped per the decision log (<code><nowiki>UserAdmin</nowiki></code>: abandoned upstream, no PHP8 fork; <code><nowiki>HTML5video</nowiki></code>: PHP8-incompatible, later replaced by <code><nowiki>EmbedVideo</nowiki></code> in Phase 7, not by <code><nowiki>TimedMediaHandler</nowiki></code> as originally assumed). === 5.4 <code><nowiki>LocalSettings.php</nowiki></code> β production version === Written fresh (not copied from the hop chain's minimal version). Full current content, secrets redacted, confirmed live via <code><nowiki>cat /var/www/wiki/LocalSettings.php</nowiki></code>: <pre> <nowiki> <?php if ( !defined( 'MEDIAWIKI' ) ) { exit; } $wgSitename = "TetraWiki"; $wgMetaNamespace = "TetraWiki"; $wgScriptPath = ""; $wgServer = "https://wiki-new.tetrain.com"; // updated again in Phase 8 to the real domain $wgResourceBasePath = $wgScriptPath; $wgEmergencyContact = "biswajit.tetra@gmail.com"; $wgPasswordSender = "biswajit.tetra@gmail.com"; $wgEnableEmail = true; $wgEnableUserEmail = true; $wgEnotifUserTalk = false; $wgEnotifWatchlist = false; $wgEmailAuthentication = true; $wgDBtype = "mysql"; $wgDBserver = "localhost"; $wgDBname = "my_wiki"; $wgDBuser = "wikiuser"; $wgDBpassword = "<from /root/.wiki_db_credentials>"; $wgSecretKey = "<freshly generated, not the migration-testing placeholder>"; $wgUpgradeKey = "<freshly generated>"; $wgDBprefix = ""; $wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary"; $wgSharedDB = null; $wgMainCacheType = CACHE_ACCEL; $wgMemCachedServers = []; $wgEnableUploads = true; $wgUseImageMagick = false; $wgUseInstantCommons = false; $wgLanguageCode = "en"; $wgLocaltimezone = "UTC"; $wgLocalisationCacheConf['storeDirectory'] = "/var/www/wiki/cache"; $wgSitemapNamespaces = false; $wgDefaultSkin = "vector-2022"; // see Phase 6 β legacy "vector" was the original wrong value wfLoadSkin( 'Vector' ); wfLoadExtension( 'CheckUser' ); wfLoadExtension( 'ConfirmEdit' ); wfLoadExtension( 'ConfirmEdit/QuestyCaptcha' ); wfLoadExtension( 'Gadgets' ); wfLoadExtension( 'Nuke' ); wfLoadExtension( 'ParserFunctions' ); wfLoadExtension( 'Renameuser' ); wfLoadExtension( 'TimedMediaHandler' ); wfLoadExtension( 'WikiEditor' ); wfLoadExtension( 'MsUpload' ); wfLoadExtension( 'EmbedVideo' ); // added in Phase 7, not present at initial deploy $wgGroupPermissions['*']['edit'] = true; $wgGroupPermissions['*']['createaccount'] = true; $wgGroupPermissions['*']['read'] = true; $wgRightsPage = ""; $wgRightsUrl = ""; $wgRightsText = ""; $wgDiff3 = "/usr/bin/diff3"; </nowiki> </pre> === 5.5 Images + SELinux === <pre> <nowiki> tar xzf /root/mw-hop-migration/images.tar.gz -C /var/www/wiki chown -R apache:apache /var/www/wiki semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/wiki/images(/.*)?" semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/wiki/cache(/.*)?" restorecon -Rv /var/www/wiki/images /var/www/wiki/cache </nowiki> </pre> Confirmed live: <code><nowiki>ls -Zd</nowiki></code> shows <code><nowiki>httpd_sys_content_t</nowiki></code> on <code><nowiki>/var/www/wiki</nowiki></code> itself and <code><nowiki>httpd_sys_rw_content_t</nowiki></code> on <code><nowiki>images/</nowiki></code> and <code><nowiki>cache/</nowiki></code> specifically β matches the pattern above (Rocky 9 is SELinux-enforcing by default, this was required, not optional). '''Verify''': homepage loads (200, title "TetraWiki"); a real content page renders (<code><nowiki>ISGEC_-_Next_Cloud_Deployment</nowiki></code> was the one checked); thumbnail generation works (GD-based since <code><nowiki>$wgUseImageMagick = false</nowiki></code>). ---- == Phase 6 β Logo sizing fix (verified exact, from the decision log) == Two root causes, both already diagnosed precisely in the decision log: <pre> <nowiki> # 1. Wrong skin variant β legacy Vector was being selected instead of Vector 2022 # Fix: in LocalSettings.php, change: # $wgDefaultSkin = "vector"; # to: # $wgDefaultSkin = "vector-2022"; </nowiki> </pre> <pre> <nowiki> # 2. Logo was being force-fit into Vector 2022's fixed 50x50 icon slot, distorting it. mkdir -p /var/www/wiki/resources/assets/logo # download the real company logo (tetra_logo_2017Web.png, 198x399px) and host it locally # rather than hotlinking www.tetrain.com, then re-composite onto properly sized, transparent, # square canvases at each density (letterboxed/centered, not stretched): # tetrain_logo_1x.png -> 50x50 # tetrain_logo_1.5x.png -> 75x75 # tetrain_logo_2x.png -> 100x100 </nowiki> </pre> Then set (already reflected in the Phase 5.4 <code><nowiki>LocalSettings.php</nowiki></code> listing above): <pre> <nowiki> $wgLogos = [ "1x" => "$wgResourceBasePath/resources/assets/logo/tetrain_logo_1x.png", "1.5x" => "$wgResourceBasePath/resources/assets/logo/tetrain_logo_1.5x.png", "2x" => "$wgResourceBasePath/resources/assets/logo/tetrain_logo_2x.png", "icon" => "$wgResourceBasePath/resources/assets/logo/tetrain_logo_1x.png", ]; </nowiki> </pre> <pre> <nowiki> php maintenance/run.php purgeList # or Special:Purge on the affected pages β clear the cached logo </nowiki> </pre> '''Verify''': served logo image is genuinely 50Γ50px (checked via direct image fetch), no distortion. ---- == Phase 7 β YouTube video-embed restoration (exact β run in this session) == '''Problem''': <code><nowiki>HTML5video</nowiki></code> (dropped in Phase 5) was actually the extension embedding external YouTube videos, not <code><nowiki>TimedMediaHandler</nowiki></code>'s job (uploaded files only) β this broke 149 embeds across 44 pages. === 7.1 Install EmbedVideo === <pre> <nowiki> cd /var/www/wiki/extensions git clone https://github.com/StarCitizenTools/mediawiki-extensions-EmbedVideo.git EmbedVideo </nowiki> </pre> (Default branch β no <code><nowiki>REL1_43</nowiki></code> branch exists for this third-party extension; <code><nowiki>extension.json</nowiki></code> requires MediaWiki β₯1.29.0, satisfied.) === 7.2 Patch for MediaWiki 1.43's strict <code><nowiki>array</nowiki></code> typing === MediaWiki 1.43 core requires <code><nowiki>ParserOutput::addModules()</nowiki></code>/<code><nowiki>addModuleStyles()</nowiki></code> to receive an <code><nowiki>array</nowiki></code>, not a bare string. Exact diff applied (confirmed live via <code><nowiki>diff</nowiki></code> against the <code><nowiki>.bak</nowiki></code>): <pre> <nowiki> --- EmbedVideo.hooks.php.bak +++ EmbedVideo.hooks.php @@ -650,2 +650,2 @@ - $out->addModules('ext.embedVideo'); - $out->addModuleStyles('ext.embedVideo.styles'); + $out->addModules( [ 'ext.embedVideo' ] ); + $out->addModuleStyles( [ 'ext.embedVideo.styles' ] ); </nowiki> </pre> <pre> <nowiki> cp EmbedVideo/EmbedVideo.hooks.php EmbedVideo/EmbedVideo.hooks.php.bak sed -i "s/\$out->addModules('ext.embedVideo');/\$out->addModules( [ 'ext.embedVideo' ] );/" EmbedVideo/EmbedVideo.hooks.php sed -i "s/\$out->addModuleStyles('ext.embedVideo.styles');/\$out->addModuleStyles( [ 'ext.embedVideo.styles' ] );/" EmbedVideo/EmbedVideo.hooks.php </nowiki> </pre> Diagnosed by temporarily enabling <code><nowiki>$wgShowExceptionDetails = true;</nowiki></code> on a scratch test page, reverted immediately after confirming the fix. === 7.3 Load it === <pre> <nowiki> // add to LocalSettings.php, after the other wfLoadExtension() calls: wfLoadExtension( 'EmbedVideo' ); </nowiki> </pre> === 7.4 Fix content β per page, per video === For each of the 44 pages holding broken embeds: # Pull current wikitext: <code><nowiki>php maintenance/run.php getText.php "<full title, with namespace prefix>"</nowiki></code> β '''note''': most of these "pages" are actually <code><nowiki>Category:</nowiki></code>-namespace pages being used to hold real content (a pre-existing quirk of this wiki, not introduced here); a bare title without the <code><nowiki>Category:</nowiki></code> prefix resolves to "page does not exist." # Replace every <code><nowiki><HTML5video type="youtube" ...>VIDEO_ID</HTML5video></nowiki></code> with: <pre> <nowiki> {{#ev:youtube|VIDEO_ID|640}} '''Video summary:''' <written summary paragraph, sourced from the video's actual YouTube transcript> </nowiki> </pre> # Apply: <code><nowiki>php maintenance/run.php edit.php -s "<summary>" -u Admin -b --nocreate "<full title>" < newcontent.txt</nowiki></code> (content piped via stdin from a file, not passed as a shell argument β avoids quoting issues with apostrophes/backticks in the prose). '''Verify''': DB sweep for zero remaining <code><nowiki><HTML5video></nowiki></code> tags across all touched pages; confirm in a real browser that each embed renders as an actual <code><nowiki><iframe src="https://www.youtube-nocookie.com/embed/VIDEO_ID"></nowiki></code>, not just literal wikitext. Content-quality notes (not a server step, but part of "what was actually done"): summaries are based on real YouTube auto-caption transcripts. Where audio/ASR quality made a transcript unusable, the paragraph says so explicitly (<code><nowiki>[VERY POOR TRANSCRIPT QUALITY]</nowiki></code> / <code><nowiki>[PARTIAL TRANSCRIPT]</nowiki></code>) rather than fabricating detail. 5 of the 149 videos are flagged inaccessible (1 private, 4 removed by YouTube) and 2 are flagged as duplicate content β all noted directly in the published paragraph, not just in this log. ---- == Phase 8 β Production DNS cutover (exact β run in this session) == Client repointed DNS directly (A record for <code><nowiki>wiki.tetrain.com</nowiki></code> β <code><nowiki>172.105.39.56</nowiki></code>; new record <code><nowiki>wiki-old.tetrain.com</nowiki></code> β <code><nowiki>172.105.56.64</nowiki></code>, the old box) β no registrar access was available in this session to do that part. Everything below is what made the *server* actually ready for it. === 8.1 Expand the TLS certificate to cover the real domain === <pre> <nowiki> certbot --apache -d wiki-new.tetrain.com -d wiki.tetrain.com --expand \ --non-interactive --agree-tos -m root@wiki-new.tetrain.com --redirect </nowiki> </pre> This issues/saves the expanded cert correctly but can fail to auto-install with: <code><nowiki>Encountered vhost ambiguity when trying to find a vhost for wiki.tetrain.com</nowiki></code> β if so (happened here), the cert itself is fine; only the vhost wiring needs a manual step next. === 8.2 Add <code><nowiki>ServerAlias</nowiki></code> to both vhosts (only needed if 8.1 hit the ambiguity error) === Back up first: <pre> <nowiki> cp /etc/httpd/conf.d/wiki.conf /etc/httpd/conf.d/wiki.conf.bak.$(date +%s) cp /etc/httpd/conf.d/wiki-le-ssl.conf /etc/httpd/conf.d/wiki-le-ssl.conf.bak.$(date +%s) </nowiki> </pre> Add <code><nowiki>ServerAlias wiki.tetrain.com</nowiki></code> right after each <code><nowiki>ServerName wiki-new.tetrain.com</nowiki></code> line, in both <code><nowiki>/etc/httpd/conf.d/wiki.conf</nowiki></code> (port 80) and <code><nowiki>/etc/httpd/conf.d/wiki-le-ssl.conf</nowiki></code> (port 443): <pre> <nowiki> sed -i '/ServerName wiki-new.tetrain.com/a\ ServerAlias wiki.tetrain.com' /etc/httpd/conf.d/wiki.conf sed -i '/ServerName wiki-new.tetrain.com/a\ ServerAlias wiki.tetrain.com' /etc/httpd/conf.d/wiki-le-ssl.conf </nowiki> </pre> Broaden the HTTPβHTTPS redirect in <code><nowiki>wiki.conf</nowiki></code> to match either hostname: <pre> <nowiki> sed -i 's/RewriteCond %{SERVER_NAME} =wiki-new.tetrain.com$/RewriteCond %{SERVER_NAME} =wiki-new.tetrain.com [OR]\nRewriteCond %{SERVER_NAME} =wiki.tetrain.com/' /etc/httpd/conf.d/wiki.conf </nowiki> </pre> Resulting <code><nowiki>wiki.conf</nowiki></code> (port 80), confirmed live: <pre> <nowiki> <VirtualHost *:80> ServerName wiki-new.tetrain.com ServerAlias wiki.tetrain.com DocumentRoot /var/www/wiki <Directory /var/www/wiki> AllowOverride All Require all granted DirectoryIndex index.php </Directory> <FilesMatch \.php$> SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost" </FilesMatch> ErrorLog /var/log/httpd/wiki-error.log CustomLog /var/log/httpd/wiki-access.log combined RewriteEngine on RewriteCond %{SERVER_NAME} =wiki-new.tetrain.com [OR] RewriteCond %{SERVER_NAME} =wiki.tetrain.com RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] </VirtualHost> </nowiki> </pre> Resulting <code><nowiki>wiki-le-ssl.conf</nowiki></code> (port 443), confirmed live: <pre> <nowiki> <IfModule mod_ssl.c> <VirtualHost *:443> ServerName wiki-new.tetrain.com ServerAlias wiki.tetrain.com DocumentRoot /var/www/wiki <Directory /var/www/wiki> AllowOverride All Require all granted DirectoryIndex index.php </Directory> <FilesMatch \.php$> SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost" </FilesMatch> ErrorLog /var/log/httpd/wiki-error.log CustomLog /var/log/httpd/wiki-access.log combined SSLCertificateFile /etc/letsencrypt/live/wiki-new.tetrain.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/wiki-new.tetrain.com/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf </VirtualHost> </IfModule> </nowiki> </pre> <pre> <nowiki> apachectl configtest systemctl reload httpd </nowiki> </pre> === 8.3 Update MediaWiki's own server config === <pre> <nowiki> cp /var/www/wiki/LocalSettings.php /var/www/wiki/LocalSettings.php.bak.$(date +%s) sed -i 's|$wgServer = "https://wiki-new.tetrain.com";|$wgServer = "https://wiki.tetrain.com";|' /var/www/wiki/LocalSettings.php </nowiki> </pre> Without this, MediaWiki keeps generating every internal link/redirect/canonical URL against the old hostname even with correct DNS and TLS. === 8.4 Verify end-to-end === <pre> <nowiki> # cert now covers both names: echo | openssl s_client -connect wiki.tetrain.com:443 -servername wiki.tetrain.com 2>/dev/null \ | openssl x509 -noout -subject -issuer -ext subjectAltName # redirect chain: curl -sIL https://wiki.tetrain.com/ | grep -i "^location\|^HTTP" # expect: 301 -> /index.php?title=Main_Page -> 200 OK # old box still reachable at its new name: dig +short wiki-old.tetrain.com A # -> 172.105.56.64 </nowiki> </pre> Confirmed live: cert SAN lists <code><nowiki>DNS:wiki-new.tetrain.com, DNS:wiki.tetrain.com</nowiki></code>; redirect chain lands on <code><nowiki>200 OK</nowiki></code>; a page with restored video embeds (Phase 7) renders correctly β real <code><nowiki><iframe></nowiki></code> present β when loaded via <code><nowiki>https://wiki.tetrain.com</nowiki></code>. ---- == Phase 9 β File upload formats: PDF, then Office/image/document formats (exact β run in this session) == === 9.1 PDF uploads === <pre> <nowiki> cp /var/www/wiki/LocalSettings.php /var/www/wiki/LocalSettings.php.bak.$(date +%Y%m%d%H%M%S) </nowiki> </pre> Add to <code><nowiki>LocalSettings.php</nowiki></code>, right after <code><nowiki>$wgEnableUploads = true;</nowiki></code>: <pre> <nowiki> $wgFileExtensions = array_merge( $wgFileExtensions ?? [ 'png', 'gif', 'jpg', 'jpeg' ], [ 'pdf' ] ); </nowiki> </pre> Add after the other <code><nowiki>wfLoadExtension()</nowiki></code> calls: <pre> <nowiki> wfLoadExtension( 'PdfHandler' ); </nowiki> </pre> <code><nowiki>PdfHandler</nowiki></code> ships bundled inside the 1.43.9 tarball already on disk (Phase 5) β it just isn't loaded by default, no separate download needed. <code><nowiki>PdfHandler</nowiki></code> needs four system binaries it depends on for rendering/thumbnailing/text-indexing, none of which were present on the box: <pre> <nowiki> dnf install -y ghostscript poppler-utils ImageMagick # provides: gs ($wgPdfProcessor), convert ($wgPdfPostProcessor), # pdfinfo ($wgPdfInfo), pdftotext ($wgPdftoText) β all four are MediaWiki defaults, # no explicit $wgPdf* overrides were needed once the binaries existed on PATH </nowiki> </pre> (This <code><nowiki>dnf install</nowiki></code> hit the 60s SSH command timeout mid-transaction β verified separately via <code><nowiki>rpm -qa | grep -iE 'ghostscript|poppler-utils|ImageMagick'</nowiki></code> and <code><nowiki>which gs convert pdfinfo pdftotext</nowiki></code> that it had actually completed; not re-run.) '''Verify''': <pre> <nowiki> curl -s 'https://wiki.tetrain.com/api.php?action=query&meta=siteinfo&siprop=fileextensions&format=json' # confirm "pdf" present in the list </nowiki> </pre> Also checked <code><nowiki>Special:Version</nowiki></code> on the live wiki β confirms "PDF Handler" registered as a loaded extension. === 9.2 Extend further: ppt, pptx, tiff, bmp, docx, xlsx, ps, odt, ods, odp, odg === Before touching config, checked whether MediaWiki core already knows how to map each extension to a MIME type (the actual mapping source in this version is <code><nowiki>includes/libs/mime/MimeMap.php</nowiki></code> β '''not''' a flat <code><nowiki>mime.types</nowiki></code>/<code><nowiki>mime.info</nowiki></code> file): <pre> <nowiki> grep -iE "'docx'|'xlsx'|'pptx'|'ppt'|'odt'|'ods'|'odp'|'odg'|'tiff'|'tif'|'bmp'|'ps'" \ /var/www/wiki/includes/libs/mime/MimeMap.php </nowiki> </pre> Confirmed: every one of these was already correctly mapped (e.g. <code><nowiki>'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => [ 'docx' ]</nowiki></code>, <code><nowiki>'image/tiff' => [ 'tiff', 'tif' ]</nowiki></code>, <code><nowiki>'application/postscript' => [ 'ai', 'eps', 'ps' ]</nowiki></code>, etc.) β no core patching needed, only the extensions allowlist. <pre> <nowiki> cp /var/www/wiki/LocalSettings.php /var/www/wiki/LocalSettings.php.bak.$(date +%Y%m%d%H%M%S) </nowiki> </pre> Edit the line from 9.1 to: <pre> <nowiki> $wgFileExtensions = array_merge( $wgFileExtensions ?? [ 'png', 'gif', 'jpg', 'jpeg' ], [ 'pdf', 'ppt', 'pptx', 'docx', 'xlsx', 'tiff', 'tif', 'bmp', 'ps', 'odt', 'ods', 'odp', 'odg' ] ); </nowiki> </pre> (Legacy <code><nowiki>doc</nowiki></code>/<code><nowiki>xls</nowiki></code> deliberately '''not''' added β not part of what was requested.) '''Verify''': same <code><nowiki>siprop=fileextensions</nowiki></code> API check as 9.1; confirmed all 11 new extensions present, no httpd error-log entries after reload. '''Known limitation, disclosed rather than silently shipped''': TIFF and PS files upload fine but render '''no thumbnail preview''' β the site's bitmap pipeline is GD, not ImageMagick (<code><nowiki>$wgUseImageMagick = false</nowiki></code>, unchanged from Phase 5), GD has no TIFF decoder, and no PostScript handler extension is installed (<code><nowiki>ls extensions/ | grep -iE 'tiff|postscript'</nowiki></code> β empty). Both formats behave like Office documents already do (download-only, generic file icon). Not fixed in this pass β flagged to the client as an open choice (add a TIFF/PS handler vs. accept upload-only) rather than guessed at. ---- == Phase 10 β 'Outdated article' banner system (exact β run in this session) == === 10.1 <code><nowiki>Template:Outdated</nowiki></code> === Created as a wiki page via the same <code><nowiki>edit.php</nowiki></code> mechanism as Phase 7. Final version (styling was revised once, from a generic amber box to client-specified red/bold/large, per explicit instruction to match exactly): <pre> <nowiki> <div style="border:2px solid #c0392b; background:#fdecea; color:#c0392b; padding:14px 18px; margin:0 0 16px 0; border-radius:4px; line-height:1.35;"> <span style="font-weight:700; font-size:22px;">This is an Old / Outdated Article, Please use this only as technical Reference</span>{{#if:{{{reason|}}}|<br><span style="font-weight:700; font-size:15px;">Reason: {{{reason}}}</span>}}{{#if:{{{date|}}}|<br><span style="font-size:13px;">Flagged: {{{date}}}</span>}} </div><noinclude> == Usage == Add <nowiki>{{Outdated}}</nowiki> at the top of a page to mark it as outdated (red/bold/large banner). Optional parameters: * <nowiki>{{Outdated|reason=Server decommissioned}}</nowiki> * <nowiki>{{Outdated|date=2026-07}}</nowiki> * Both together: <nowiki>{{Outdated|reason=Client migrated off this platform|date=2026-07}}</nowiki> [[Category:Templates]] </noinclude> </nowiki> </pre> Applied via: <pre> <nowiki> php maintenance/run.php edit.php -s "Create Outdated template" -u Admin -b "Template:Outdated" < template_text.txt </nowiki> </pre> === 10.2 Page inventory (for the client to review and flag) === <pre> <nowiki> SELECT p.page_namespace, p.page_title, p.page_is_redirect, p.page_len, r.rev_timestamp, COUNT(r2.rev_id) AS rev_count FROM page p JOIN revision r ON r.rev_id = p.page_latest LEFT JOIN revision r2 ON r2.rev_page = p.page_id WHERE p.page_namespace IN (0,14) GROUP BY p.page_id ORDER BY r.rev_timestamp ASC </nowiki> </pre> Run via <code><nowiki>php maintenance/run.php sql --query "..."</nowiki></code>, 637 rows returned (490 Article, 147 Category, 7 redirects). Converted to: * an HTML dashboard artifact (sortable/filterable table, live banner mockup) for browsing, and * <code><nowiki>wiki_pages_for_review.csv</nowiki></code> (Page Title, Type, URL, Last Edited, Age, Revisions, Redirect?, and two blank columns β <code><nowiki>Mark as Outdated? (Y/N)</nowiki></code> and <code><nowiki>Reason / Subject</nowiki></code> β for the client to fill in and return). === 10.3 Batch-apply the client's markings === Client returned the CSV with 468 of 637 rows marked <code><nowiki>Y</nowiki></code>/<code><nowiki>y</nowiki></code>, each with a filled-in reason. Rather than 468 separate SSH round-trips, wrote a one-off maintenance script (<code><nowiki>BatchMarkOutdated.php</nowiki></code>, dropped into <code><nowiki>/var/www/wiki/maintenance/</nowiki></code> alongside core scripts, run once, then deleted) that loads a JSON <code><nowiki>{title, reason}</nowiki></code> list built from the CSV and, for each page: * resolves the title (namespace prefix already baked into the CSV's URL column from 10.2's query, so <code><nowiki>Category:</nowiki></code>/main-namespace handling is correct going in β no re-lookup needed), * skips it if the text already contains <code><nowiki>{{Outdated</nowiki></code> (idempotent on re-run), * prepends <code><nowiki>{{Outdated|reason=<csv reason>|date=2026-07}}</nowiki></code> and saves via <code><nowiki>WikiPage::newPageUpdater()</nowiki></code> / <code><nowiki>saveRevision()</nowiki></code> (the same underlying API <code><nowiki>edit.php</nowiki></code> itself calls, just invoked in-process for all 468 rows in one PHP bootstrap instead of 936 separate CLI invocations). <pre> <nowiki> php maintenance/BatchMarkOutdated.php --file=/var/www/wiki/maintenance/outdated_batch.json --date=2026-07 # Done: 465, already-tagged: 3, missing: 0, failed: 0 # (3 "already-tagged" were a 3-row test slice run first to confirm the script before the full batch) </nowiki> </pre> '''Verify''': spot-checked several pages via <code><nowiki>getText.php</nowiki></code> and live in-browser (computed style <code><nowiki>color: rgb(192, 57, 43)</nowiki></code>, <code><nowiki>font-weight: 700</nowiki></code>, <code><nowiki>font-size: 22px</nowiki></code> β matches Template:Outdated exactly); banner text includes each page's specific client-supplied reason and the flag date. ---- == Phase 11 β Outbound email / SMTP relay fix (exact β run in this session) == '''Starting state''': <code><nowiki>$wgEnableEmail</nowiki></code>/<code><nowiki>$wgEnableUserEmail</nowiki></code> were already <code><nowiki>true</nowiki></code> (Phase 5.4), but no MTA existed on the box at all β PHP's <code><nowiki>mail()</nowiki></code> fallback had nowhere to hand off to. Client provided SMTP relay credentials directly: host <code><nowiki>mail.tetrain.com</nowiki></code>, port <code><nowiki>25</nowiki></code>, STARTTLS, username <code><nowiki>smtp_wiki</nowiki></code>, password (entered directly into <code><nowiki>LocalSettings.php</nowiki></code> over SSH, never written to this doc or any other file β same handling as the DB credentials in Phase 4.3). === 11.1 Identify the correct config shape === This MediaWiki version relays mail via '''PEAR's <code><nowiki>Mail_smtp</nowiki></code>''' class (<code><nowiki>vendor/pear/mail/Mail/smtp.php</nowiki></code>), not PHPMailer β confirmed by reading <code><nowiki>includes/mail/UserMailer.php::sendInternal()</nowiki></code>, which calls <code><nowiki>Mail::factory('smtp', $smtp)</nowiki></code> when <code><nowiki>$wgSMTP</nowiki></code> is an array. Accepted keys per <code><nowiki>Mail/smtp.php</nowiki></code>'s constructor: <code><nowiki>host</nowiki></code>, <code><nowiki>port</nowiki></code>, <code><nowiki>auth</nowiki></code>, <code><nowiki>starttls</nowiki></code>, <code><nowiki>username</nowiki></code>, <code><nowiki>password</nowiki></code>, <code><nowiki>localhost</nowiki></code>, <code><nowiki>timeout</nowiki></code>, <code><nowiki>debug</nowiki></code> ('''no''' <code><nowiki>IDHost</nowiki></code> β that's a PHPMailer-only concept and was deliberately not used). === 11.2 Apply config === <pre> <nowiki> cp /var/www/wiki/LocalSettings.php /var/www/wiki/LocalSettings.php.bak.$(date +%Y%m%d%H%M%S) </nowiki> </pre> Inserted right after <code><nowiki>$wgEnableEmail = true;</nowiki></code>: <pre> <nowiki> $wgSMTP = [ 'host' => 'mail.tetrain.com', 'port' => 25, 'auth' => true, 'starttls' => true, 'username' => 'smtp_wiki', 'password' => '<provided by client, entered directly, redacted here>', 'localhost' => 'wiki.tetrain.com', ]; </nowiki> </pre> <pre> <nowiki> chmod 640 /var/www/wiki/LocalSettings.php # owner apache:apache β tightened since the file now # holds an SMTP password, not just the DB password; # confirmed httpd (runs as `apache`) still reads it # fine via the owner bit (curl to the site: 200) </nowiki> </pre> === 11.3 Test send, and the two false starts === Wrote a temporary maintenance script calling <code><nowiki>UserMailer::send()</nowiki></code> directly (the same code path a password-reset email uses), deleted after use. '''Attempt 1''' β <code><nowiki>From: biswajit.tetra@gmail.com</nowiki></code> β relay returned <code><nowiki>250 OK</nowiki></code> (<code><nowiki>SEND OK</nowiki></code>) but the email never arrived. Diagnosed via DNS, not guessed: <pre> <nowiki> dig +short TXT gmail.com # "v=spf1 redirect=_spf.google.com" β only Google infra allowed dig +short TXT _dmarc.gmail.com # p=none; sp=quarantine dig +short TXT spf.tetrain.com # only server-relay(.1/.2)/indorama-relay.tetrain.com authorized dig +short A mail.tetrain.com # 139.84.171.188 β NOT one of the authorized relay hosts above </nowiki> </pre> <code><nowiki>mail.tetrain.com</nowiki></code> is not in <code><nowiki>tetrain.com</nowiki></code>'s own SPF record, and the From address wasn't even on the <code><nowiki>tetrain.com</nowiki></code> domain β a message claiming to be from a personal Gmail address, relayed through an unrelated third-party server, reads as spoofing to the receiving side. '''Attempt 2''' β <code><nowiki>From: wiki@tetrain.com</nowiki></code> (still via <code><nowiki>mail.tetrain.com</nowiki></code>) β also <code><nowiki>SEND OK</nowiki></code> at the relay, not independently confirmed delivered/undelivered (superseded by attempt 3 before checking). '''Attempt 3 (fix)''' β client identified the real constraint directly: the From address must match the *authenticated* SMTP account itself, i.e. <code><nowiki>smtp_wiki@tetrain.com</nowiki></code>, not an arbitrary <code><nowiki>@tetrain.com</nowiki></code> address. Updated: <pre> <nowiki> sed -i 's/$wgEmergencyContact = "biswajit.tetra@gmail.com";/$wgEmergencyContact = "smtp_wiki@tetrain.com";/' /var/www/wiki/LocalSettings.php sed -i 's/$wgPasswordSender = "biswajit.tetra@gmail.com";/$wgPasswordSender = "smtp_wiki@tetrain.com";/' /var/www/wiki/LocalSettings.php </nowiki> </pre> Re-ran the test with <code><nowiki>From: smtp_wiki@tetrain.com</nowiki></code> β <code><nowiki>SEND OK</nowiki></code>, and '''client confirmed actual receipt''' in their inbox. This is the live, working state. '''Verify''' (if reproducing): <code><nowiki>$wgEmergencyContact</nowiki></code> / <code><nowiki>$wgPasswordSender</nowiki></code> in <code><nowiki>LocalSettings.php</nowiki></code> both read <code><nowiki>smtp_wiki@tetrain.com</nowiki></code>; a real password-reset or "email this user" send succeeds and arrives. ---- == Known-incomplete items (not yet part of a repeatable 'done' state) == * Old <code><nowiki>wiki.tetrain.com</nowiki></code> box (now <code><nowiki>wiki-old.tetrain.com</nowiki></code>, 172.105.56.64) is up but not yet decommissioned. * <code><nowiki>TimedMediaHandler</nowiki></code> needs <code><nowiki>ffmpeg</nowiki></code> for transcoding actual *uploaded* video files β not installed, not blocking since this wiki's real video content is all YouTube embeds (Phase 7), not uploads. * Rocky 9 kernel was bumped by <code><nowiki>dnf update</nowiki></code> during initial setup but the box wasn't rebooted onto it at that point β confirm current running kernel matches installed before assuming this is closed. * TIFF and PS uploads (Phase 9.2) have no thumbnail/preview handler β upload-only, by design for now, open question to the client on whether that's sufficient. * 169 of 637 wiki pages were left unmarked after the Phase 10.3 batch (the CSV rows the client did not mark <code><nowiki>Y</nowiki></code>) β expected to remain a rolling/ongoing process, not a one-time close-out. [[Category:Infrastructure Documentation]]
Summary:
Please note that all contributions to TetraWiki may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
TetraWiki:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)