<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mwiki.costasano.club/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mngr</id>
	<title>Costa Sano MediaWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://mwiki.costasano.club/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mngr"/>
	<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/Special:Contributions/Mngr"/>
	<updated>2026-07-22T21:25:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.45.1</generator>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Debugging&amp;diff=1644</id>
		<title>ICT:Wiki - Debugging</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Debugging&amp;diff=1644"/>
		<updated>2026-05-14T16:55:06Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Debugging to ICT:Wiki - Debugging without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Troubleshooting Philosophy for MediaWiki &amp;amp; Multi‑Layer Systems =&lt;br /&gt;
&lt;br /&gt;
Maintaining this MediaWiki installation involves several interacting layers:&lt;br /&gt;
&lt;br /&gt;
* IIS ARR (reverse proxy)&lt;br /&gt;
* Apache&lt;br /&gt;
* PHP-FPM&lt;br /&gt;
* MediaWiki&lt;br /&gt;
* ImageMagick&lt;br /&gt;
* SELinux&lt;br /&gt;
* Filesystem permissions&lt;br /&gt;
* Hashed upload directories&lt;br /&gt;
* Rewrite rules&lt;br /&gt;
&lt;br /&gt;
When something breaks, it’s tempting to blame the most external or mysterious component — often the reverse proxy. This can lead to “ghost hunting”: chasing symptoms that look like proxy failures but originate elsewhere.&lt;br /&gt;
&lt;br /&gt;
This page outlines a disciplined approach that avoids that trap.&lt;br /&gt;
&lt;br /&gt;
== 1. Start with direct, observable facts ==&lt;br /&gt;
&lt;br /&gt;
Before forming a hypothesis, gather concrete evidence:&lt;br /&gt;
&lt;br /&gt;
* Can the file be read on disk?&lt;br /&gt;
* Does &amp;lt;code&amp;gt;curl -I&amp;lt;/code&amp;gt; return a status code?&lt;br /&gt;
* Does Apache log the request?&lt;br /&gt;
* Does MediaWiki show a specific error?&lt;br /&gt;
* Does the file exist in the hashed directory?&lt;br /&gt;
&lt;br /&gt;
This prevents assumptions from steering the investigation.&lt;br /&gt;
&lt;br /&gt;
== 2. Test each layer independently ==&lt;br /&gt;
&lt;br /&gt;
A multi-layer system fails in multi-layer ways. Always test each layer in isolation:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Filesystem:&#039;&#039;&#039; &amp;lt;code&amp;gt;ls -lZ&amp;lt;/code&amp;gt;, verify ownership and SELinux&lt;br /&gt;
* &#039;&#039;&#039;Apache:&#039;&#039;&#039; direct URL tests, static file serving&lt;br /&gt;
* &#039;&#039;&#039;Rewrite rules:&#039;&#039;&#039; confirm exceptions for static files&lt;br /&gt;
* &#039;&#039;&#039;MediaWiki:&#039;&#039;&#039; file page metadata, thumbnail generation&lt;br /&gt;
* &#039;&#039;&#039;ImageMagick:&#039;&#039;&#039; command-line conversion&lt;br /&gt;
* &#039;&#039;&#039;Reverse proxy:&#039;&#039;&#039; external vs internal URL behavior&lt;br /&gt;
&lt;br /&gt;
This reveals where the failure actually occurs.&lt;br /&gt;
&lt;br /&gt;
== 3. Avoid the “reverse proxy reflex” ==&lt;br /&gt;
&lt;br /&gt;
Reverse proxies are often blamed first because they sit at the edge and feel like the “gatekeeper.”  &lt;br /&gt;
But many failures originate deeper:&lt;br /&gt;
&lt;br /&gt;
* Apache rewrite rules&lt;br /&gt;
* MediaWiki switching from GD → ImageMagick&lt;br /&gt;
* SELinux blocking read access&lt;br /&gt;
* PHP-FPM socket issues&lt;br /&gt;
* Incorrect &amp;lt;code&amp;gt;$wgUploadPath&amp;lt;/code&amp;gt;&lt;br /&gt;
* Missing static-file exceptions&lt;br /&gt;
&lt;br /&gt;
Only blame the proxy when evidence points there.&lt;br /&gt;
&lt;br /&gt;
== 4. Prefer reproducible tests over assumptions ==&lt;br /&gt;
&lt;br /&gt;
A single &amp;lt;code&amp;gt;curl&amp;lt;/code&amp;gt; test can eliminate entire categories of hypotheses:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -I https://mwiki.example.com/images/x/xy/file.png&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interpretation:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;200 OK&amp;lt;/code&amp;gt; → routing works&lt;br /&gt;
* &amp;lt;code&amp;gt;404&amp;lt;/code&amp;gt; → proxy or rewrite issue&lt;br /&gt;
* &amp;lt;code&amp;gt;403&amp;lt;/code&amp;gt; → permissions or SELinux&lt;br /&gt;
* &amp;lt;code&amp;gt;500&amp;lt;/code&amp;gt; → PHP/ImageMagick&lt;br /&gt;
* blank page → rewrite rule catching static files&lt;br /&gt;
&lt;br /&gt;
This is faster and more reliable than guesswork.&lt;br /&gt;
&lt;br /&gt;
== 5. Remember that MediaWiki changes behavior when ImageMagick is installed ==&lt;br /&gt;
&lt;br /&gt;
This is a subtle but important point:&lt;br /&gt;
&lt;br /&gt;
* With &#039;&#039;&#039;GD&#039;&#039;&#039;, MediaWiki reads images directly from disk.&lt;br /&gt;
* With &#039;&#039;&#039;ImageMagick&#039;&#039;&#039;, MediaWiki validates images via URL and MIME type.&lt;br /&gt;
&lt;br /&gt;
This means:&lt;br /&gt;
&lt;br /&gt;
* A misconfigured rewrite rule may be invisible under GD.&lt;br /&gt;
* The same misconfiguration becomes catastrophic under ImageMagick.&lt;br /&gt;
&lt;br /&gt;
This explains why image failures sometimes appear “out of nowhere.”&lt;br /&gt;
&lt;br /&gt;
== 6. Document the fix, not just the cause ==&lt;br /&gt;
&lt;br /&gt;
Future admins benefit from:&lt;br /&gt;
&lt;br /&gt;
* The symptom&lt;br /&gt;
* The root cause&lt;br /&gt;
* The exact fix&lt;br /&gt;
* The reasoning behind it&lt;br /&gt;
&lt;br /&gt;
This prevents rediscovering the same issue years later.&lt;br /&gt;
&lt;br /&gt;
== 7. Stay calm and methodical ==&lt;br /&gt;
&lt;br /&gt;
The most important principle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Don’t let any single hypothesis dominate before the evidence supports it.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This avoids tunnel vision and keeps the investigation grounded.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Data_Model_and_Media_Architecture&amp;diff=1643</id>
		<title>ICT:Wiki - Data Model and Media Architecture</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Data_Model_and_Media_Architecture&amp;diff=1643"/>
		<updated>2026-05-14T16:54:40Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Data Model and Media Architecture to ICT:Wiki - Data Model and Media Architecture without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Data Modelling &amp;amp; Media Management Architecture =&lt;br /&gt;
&lt;br /&gt;
This page documents the architectural decisions and working principles used for structuring data, relationships, and digital media in this MediaWiki installation.&lt;br /&gt;
&lt;br /&gt;
It reflects conclusions reached during the design phase and serves as a reference for future development and maintenance.&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
The goal of this architecture is to:&lt;br /&gt;
&lt;br /&gt;
* Support complex research data with many relationships&lt;br /&gt;
* Separate internal research work from public presentation&lt;br /&gt;
* Manage digital media (files, derivatives, metadata) in a controlled and scalable way&lt;br /&gt;
* Avoid schema drift and ad-hoc solutions&lt;br /&gt;
* Remain compatible with MediaWiki core and extensions&lt;br /&gt;
&lt;br /&gt;
== Core Technologies ==&lt;br /&gt;
&lt;br /&gt;
The system is based on the following components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Cargo&#039;&#039;&#039; – authoritative data storage (database schema)&lt;br /&gt;
* &#039;&#039;&#039;Page Schemas&#039;&#039;&#039; – page structure and data-entry UI&lt;br /&gt;
* &#039;&#039;&#039;Forms&#039;&#039;&#039; – controlled data input&lt;br /&gt;
* &#039;&#039;&#039;Namespaces&#039;&#039;&#039; – separation of concerns and access control&lt;br /&gt;
* &#039;&#039;&#039;File namespace&#039;&#039;&#039; – physical file storage (MediaWiki core)&lt;br /&gt;
&lt;br /&gt;
Each component has a clearly defined responsibility.&lt;br /&gt;
&lt;br /&gt;
== Authority and Responsibility ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Component !! Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| Cargo tables || Define and own the database schema&lt;br /&gt;
|-&lt;br /&gt;
| Page Schemas || Define page types and map fields to Cargo&lt;br /&gt;
|-&lt;br /&gt;
| Forms || Control how editors enter data&lt;br /&gt;
|-&lt;br /&gt;
| Templates || Store data via Cargo&lt;br /&gt;
|-&lt;br /&gt;
| Database (MySQL) || Implementation detail only&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039;  &lt;br /&gt;
Database tables must &#039;&#039;&#039;not&#039;&#039;&#039; be created or modified directly in MySQL.  &lt;br /&gt;
The Cargo table pages are the single source of truth for schema definition.&lt;br /&gt;
&lt;br /&gt;
== Workflow Principle ==&lt;br /&gt;
&lt;br /&gt;
The general workflow is:&lt;br /&gt;
&lt;br /&gt;
# Design the model (DBML / diagrams)&lt;br /&gt;
# Create or update Cargo tables&lt;br /&gt;
# Activate Cargo tables by saving the Cargo page&lt;br /&gt;
# Create Page Schemas using the UI&lt;br /&gt;
# Generate forms&lt;br /&gt;
# Enter and test real data&lt;br /&gt;
# Iterate carefully&lt;br /&gt;
&lt;br /&gt;
== Namespaces and Their Roles ==&lt;br /&gt;
&lt;br /&gt;
Namespaces are used to separate concerns and control access.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Namespace !! Purpose !! Visibility&lt;br /&gt;
|-&lt;br /&gt;
| (Main) || Public research results and narratives || Public&lt;br /&gt;
|-&lt;br /&gt;
| HO: || Structured Heritage Objects || Club members&lt;br /&gt;
|-&lt;br /&gt;
| DA: || Digital Asset metadata and relationships || Club members&lt;br /&gt;
|-&lt;br /&gt;
| File: || Physical file storage || Uploads restricted&lt;br /&gt;
|-&lt;br /&gt;
| ICT: || Technical and architectural documentation || Club members&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Namespaces must not be redefined.  &lt;br /&gt;
The built-in &#039;&#039;&#039;File:&#039;&#039;&#039; namespace remains unchanged.&lt;br /&gt;
&lt;br /&gt;
== File Management Strategy ==&lt;br /&gt;
&lt;br /&gt;
MediaWiki’s file model is page-centric and limited for complex workflows.  &lt;br /&gt;
To address this, a clear separation is enforced:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;File:&#039;&#039;&#039; pages store physical files only&lt;br /&gt;
* &#039;&#039;&#039;DA:&#039;&#039;&#039; pages store semantic metadata about digital assets&lt;br /&gt;
&lt;br /&gt;
Digital Assets (DA) act as the central abstraction layer.&lt;br /&gt;
&lt;br /&gt;
=== Internal vs Public Files ===&lt;br /&gt;
&lt;br /&gt;
Not all files are equal:&lt;br /&gt;
&lt;br /&gt;
* Internal files:&lt;br /&gt;
** High-resolution masters&lt;br /&gt;
** OCR outputs&lt;br /&gt;
** Working derivatives&lt;br /&gt;
* Public files:&lt;br /&gt;
** Curated, approved derivatives&lt;br /&gt;
** Downscaled or watermarked versions&lt;br /&gt;
&lt;br /&gt;
Internal and public files are managed by convention, not by redefining namespaces.&lt;br /&gt;
&lt;br /&gt;
== Upload Permissions ==&lt;br /&gt;
&lt;br /&gt;
* Uploading files is restricted to club members&lt;br /&gt;
* Viewing files remains public (to support public pages)&lt;br /&gt;
* Editors must ensure that only approved files are embedded on public pages&lt;br /&gt;
&lt;br /&gt;
Public pages must never depend on internal-only files.&lt;br /&gt;
&lt;br /&gt;
== Digital Assets (DA) ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;Digital Asset&#039;&#039;&#039; represents a conceptual media object and may reference:&lt;br /&gt;
&lt;br /&gt;
* One or more File: pages&lt;br /&gt;
* A parent Digital Asset (for derivatives)&lt;br /&gt;
* One or more Heritage Objects&lt;br /&gt;
&lt;br /&gt;
DA pages are internal and never directly exposed to the public.&lt;br /&gt;
&lt;br /&gt;
== Handling Many-to-Many Relationships ==&lt;br /&gt;
&lt;br /&gt;
Relational join tables from the original data model are implemented as:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Cargo subtables&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Repeatable sections in Page Schemas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example use cases:&lt;br /&gt;
* Object–Person relationships&lt;br /&gt;
* Object–Set memberships&lt;br /&gt;
* Provenance chains&lt;br /&gt;
&lt;br /&gt;
This avoids page explosion and keeps relationships contextual.&lt;br /&gt;
&lt;br /&gt;
== Page Schemas vs Cargo Tables ==&lt;br /&gt;
&lt;br /&gt;
Cargo tables may be created in two ways:&lt;br /&gt;
&lt;br /&gt;
* Manually (Cargo-first)&lt;br /&gt;
* Via Page Schemas UI (UI-first)&lt;br /&gt;
&lt;br /&gt;
In both cases:&lt;br /&gt;
&lt;br /&gt;
* The Cargo table page must be saved manually to activate the database table&lt;br /&gt;
* Page Schemas do not execute database changes automatically&lt;br /&gt;
&lt;br /&gt;
For complex, stable models, a Cargo-first approach is preferred.&lt;br /&gt;
&lt;br /&gt;
== Design Principles ==&lt;br /&gt;
&lt;br /&gt;
The following principles guide all future development:&lt;br /&gt;
&lt;br /&gt;
* Cargo owns structure, Page Schemas own usability&lt;br /&gt;
* Internal complexity is allowed; public simplicity is required&lt;br /&gt;
* Publication is a controlled act, not a permission toggle&lt;br /&gt;
* Add fields freely; rename or remove fields carefully&lt;br /&gt;
* Prefer conventions over hacks&lt;br /&gt;
* Avoid direct database manipulation&lt;br /&gt;
&lt;br /&gt;
== Status ==&lt;br /&gt;
&lt;br /&gt;
This architecture is considered the current baseline.&lt;br /&gt;
&lt;br /&gt;
Changes must be documented and reviewed before implementation.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Dashboard_help_function&amp;diff=1642</id>
		<title>ICT:Wiki - Dashboard help function</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Dashboard_help_function&amp;diff=1642"/>
		<updated>2026-05-14T16:46:33Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Dashboard help function to ICT:Wiki - Dashboard help function without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Dashboard Help System – Implementation Guide =&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
This page explains how dashboard pages provide integrated user help.&lt;br /&gt;
&lt;br /&gt;
Goal:&lt;br /&gt;
&lt;br /&gt;
* guide club members directly inside the system&lt;br /&gt;
* explain what each dashboard is for&lt;br /&gt;
* avoid separate manuals or PDFs&lt;br /&gt;
* reduce mistakes during data entry&lt;br /&gt;
&lt;br /&gt;
Help must be visible &#039;&#039;&#039;at the place where the user works&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Design principles ==&lt;br /&gt;
&lt;br /&gt;
The help system follows these rules:&lt;br /&gt;
&lt;br /&gt;
* documentation is integrated, not external&lt;br /&gt;
* each dashboard has its own explanation&lt;br /&gt;
* help is easy to maintain&lt;br /&gt;
* help does not clutter the screen&lt;br /&gt;
* layout is identical on all dashboards&lt;br /&gt;
&lt;br /&gt;
Technical approach:&lt;br /&gt;
&lt;br /&gt;
* one help subpage per dashboard&lt;br /&gt;
* one reusable template&lt;br /&gt;
* transclusion into dashboard page&lt;br /&gt;
* collapsible display&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Structure ==&lt;br /&gt;
&lt;br /&gt;
For every dashboard:&lt;br /&gt;
&lt;br /&gt;
 Dashboard:Chapter&lt;br /&gt;
 Dashboard:Chapter/Help&lt;br /&gt;
&lt;br /&gt;
 Dashboard:Place&lt;br /&gt;
 Dashboard:Place/Help&lt;br /&gt;
&lt;br /&gt;
 Dashboard:Organisation&lt;br /&gt;
 Dashboard:Organisation/Help&lt;br /&gt;
&lt;br /&gt;
 etc.&lt;br /&gt;
&lt;br /&gt;
Each dashboard has its own help subpage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Step 1 – Create the reusable template ==&lt;br /&gt;
&lt;br /&gt;
Create:&lt;br /&gt;
&lt;br /&gt;
 Template:DashboardHelp&lt;br /&gt;
&lt;br /&gt;
Content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;includeonly&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible mw-collapsed&amp;quot;&lt;br /&gt;
     style=&amp;quot;border:1px solid #ccc; padding:8px; margin-bottom:12px; background:#f8f9fa;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ℹ️ Help – click to open&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;mw-collapsible-content&amp;quot;&amp;gt;&lt;br /&gt;
{{{1}}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose:&lt;br /&gt;
&lt;br /&gt;
* provides consistent styling&lt;br /&gt;
* provides collapsible behaviour&lt;br /&gt;
* keeps dashboards compact&lt;br /&gt;
* avoids repeating HTML everywhere&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Step 2 – Create a Help subpage ==&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 Dashboard:Chapter/Help&lt;br /&gt;
&lt;br /&gt;
Typical content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
== Purpose ==&lt;br /&gt;
Use this page to manage historical chapters.&lt;br /&gt;
&lt;br /&gt;
== When to use ==&lt;br /&gt;
Create a chapter when you define a new historical period or theme.&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
* CH01 – Early History&lt;br /&gt;
* CH02 – Interwar Period&lt;br /&gt;
&lt;br /&gt;
== Do NOT use for ==&lt;br /&gt;
* buildings&lt;br /&gt;
* persons&lt;br /&gt;
* organisations&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Guidelines:&lt;br /&gt;
&lt;br /&gt;
* keep short&lt;br /&gt;
* use examples&lt;br /&gt;
* avoid technical language&lt;br /&gt;
* focus on practical usage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Step 3 – Include help in the dashboard ==&lt;br /&gt;
&lt;br /&gt;
At the top of the dashboard page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{DashboardHelp|{{/Help}}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanation:&lt;br /&gt;
&lt;br /&gt;
* {{/Help}} loads the subpage&lt;br /&gt;
* DashboardHelp wraps it in a collapsible box&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
User sees:&lt;br /&gt;
&lt;br /&gt;
  ℹ️ Help – click to open&lt;br /&gt;
&lt;br /&gt;
Click → explanation appears.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Why use subpages instead of writing help directly in the dashboard? ==&lt;br /&gt;
&lt;br /&gt;
Advantages:&lt;br /&gt;
&lt;br /&gt;
* separation of concerns&lt;br /&gt;
* easier editing&lt;br /&gt;
* cleaner dashboard source&lt;br /&gt;
* reusable template&lt;br /&gt;
* successors immediately understand structure&lt;br /&gt;
* documentation can be updated without touching logic&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Why collapsible? ==&lt;br /&gt;
&lt;br /&gt;
Dashboards often contain:&lt;br /&gt;
&lt;br /&gt;
* large tables&lt;br /&gt;
* many records&lt;br /&gt;
* frequent data entry&lt;br /&gt;
&lt;br /&gt;
Permanent help text would push content down.&lt;br /&gt;
&lt;br /&gt;
Collapsible:&lt;br /&gt;
&lt;br /&gt;
* visible when needed&lt;br /&gt;
* hidden during work&lt;br /&gt;
* better UX&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Recommended writing style ==&lt;br /&gt;
&lt;br /&gt;
Write for non-technical users.&lt;br /&gt;
&lt;br /&gt;
Good:&lt;br /&gt;
&lt;br /&gt;
* short sentences&lt;br /&gt;
* concrete examples&lt;br /&gt;
* “do this / do not do this”&lt;br /&gt;
&lt;br /&gt;
Avoid:&lt;br /&gt;
&lt;br /&gt;
* database terminology&lt;br /&gt;
* technical explanations&lt;br /&gt;
* long paragraphs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Example complete dashboard ==&lt;br /&gt;
&lt;br /&gt;
Dashboard:Chapter&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
= Chapter Management =&lt;br /&gt;
&lt;br /&gt;
{{DashboardHelp|{{/Help}}}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Code !! Title !! Parent&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
 tables=Chapters&lt;br /&gt;
 |fields=_pageName,code,title,parent&lt;br /&gt;
 |format=template&lt;br /&gt;
 |template=ChapterRow&lt;br /&gt;
 |named args=yes&lt;br /&gt;
}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{{#forminput:&lt;br /&gt;
 form=Chapter&lt;br /&gt;
 |namespace=Chapter&lt;br /&gt;
 |button text=➕ New chapter&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Maintenance ==&lt;br /&gt;
&lt;br /&gt;
When rules change:&lt;br /&gt;
&lt;br /&gt;
1. edit only the /Help subpage&lt;br /&gt;
2. dashboards update automatically&lt;br /&gt;
&lt;br /&gt;
No template changes required.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
&lt;br /&gt;
This system:&lt;br /&gt;
&lt;br /&gt;
* integrates documentation directly into the workflow&lt;br /&gt;
* improves usability&lt;br /&gt;
* reduces training effort&lt;br /&gt;
* prevents data entry mistakes&lt;br /&gt;
* keeps dashboards clean&lt;br /&gt;
&lt;br /&gt;
This approach is recommended for all present and future dashboards.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Dashboard_autopurge_architecture&amp;diff=1641</id>
		<title>ICT:Wiki - Dashboard autopurge architecture</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Dashboard_autopurge_architecture&amp;diff=1641"/>
		<updated>2026-05-14T16:46:01Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Dashboard autopurge architecture to ICT:Wiki - Dashboard autopurge architecture without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ICT: Dashboard Auto‑Purge Architecture =&lt;br /&gt;
&lt;br /&gt;
This page documents why dashboards in this wiki require an automatic purge after saving a Page Forms form, why several intuitive approaches fail, and why the final solution works reliably.&lt;br /&gt;
&lt;br /&gt;
== 1. The Problem ==&lt;br /&gt;
&lt;br /&gt;
Dashboards such as &#039;&#039;&#039;Dashboard:Place&#039;&#039;&#039; display data stored in Cargo tables.  &lt;br /&gt;
After saving a form, the updated Cargo data does not appear immediately because:&lt;br /&gt;
&lt;br /&gt;
* Cargo updates are asynchronous  &lt;br /&gt;
* MediaWiki caches parser output  &lt;br /&gt;
* APCu/object cache may serve stale HTML  &lt;br /&gt;
* Reverse proxies may cache responses  &lt;br /&gt;
* Page Forms redirects do not trigger a purge  &lt;br /&gt;
&lt;br /&gt;
A reliable, automatic purge mechanism is required.&lt;br /&gt;
&lt;br /&gt;
== 2. Why Simple Solutions Do Not Work ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. HTML &amp;lt;meta&amp;gt; refresh ===&lt;br /&gt;
MediaWiki sanitizes &amp;lt;meta&amp;gt; tags, even inside &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#tag:html&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.  &lt;br /&gt;
The tag is displayed as text and never executed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Conclusion:&#039;&#039;&#039; HTML refresh cannot be used.&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Redirecting to &amp;lt;code&amp;gt;?action=purge&amp;lt;/code&amp;gt; ===&lt;br /&gt;
A redirect to &amp;lt;code&amp;gt;?action=purge&amp;lt;/code&amp;gt; always triggers MediaWiki’s confirmation dialog.  &lt;br /&gt;
This dialog cannot be suppressed via GET requests.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Conclusion:&#039;&#039;&#039; GET‑based purge is never silent.&lt;br /&gt;
&lt;br /&gt;
=== 2.3. Page Forms limitations ===&lt;br /&gt;
Page Forms does not provide hooks or callbacks that run after saving.  &lt;br /&gt;
It cannot trigger a purge.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Conclusion:&#039;&#039;&#039; Page Forms cannot be used for purge logic.&lt;br /&gt;
&lt;br /&gt;
=== 2.4. JavaScript redirect loops ===&lt;br /&gt;
Redirecting to &amp;lt;code&amp;gt;?action=purge&amp;lt;/code&amp;gt; causes:&lt;br /&gt;
&lt;br /&gt;
# Purge dialog  &lt;br /&gt;
# Page reload  &lt;br /&gt;
# JavaScript fires again  &lt;br /&gt;
# Loop  &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Conclusion:&#039;&#039;&#039; Redirect‑based purge is unstable.&lt;br /&gt;
&lt;br /&gt;
=== 2.5. Query parameters being stripped ===&lt;br /&gt;
Reverse proxies, skins, and canonical URL rewrites may strip unknown parameters such as &amp;lt;code&amp;gt;?purged=1&amp;lt;/code&amp;gt;.  &lt;br /&gt;
This prevents loop‑detection.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Conclusion:&#039;&#039;&#039; Only parameters MediaWiki preserves can be used.&lt;br /&gt;
&lt;br /&gt;
== 3. Requirements for a Working Solution ==&lt;br /&gt;
&lt;br /&gt;
A correct solution must:&lt;br /&gt;
&lt;br /&gt;
* purge silently  &lt;br /&gt;
* avoid loops  &lt;br /&gt;
* work for all dashboards  &lt;br /&gt;
* survive reverse proxies  &lt;br /&gt;
* be centralized  &lt;br /&gt;
* be successor‑friendly  &lt;br /&gt;
&lt;br /&gt;
== 4. The Final, Working Solution ==&lt;br /&gt;
&lt;br /&gt;
=== 4.1. Purge via the MediaWiki API ===&lt;br /&gt;
Silent purge requires:&lt;br /&gt;
&lt;br /&gt;
* POST request  &lt;br /&gt;
* CSRF token  &lt;br /&gt;
* API module  &lt;br /&gt;
&lt;br /&gt;
=== 4.2. Use a preserved query parameter ===&lt;br /&gt;
MediaWiki never strips parameters beginning with &amp;lt;code&amp;gt;mw_&amp;lt;/code&amp;gt;.  &lt;br /&gt;
We use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;?mw_purged=1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4.3. Centralize logic in &amp;lt;code&amp;gt;MediaWiki:Common.js&amp;lt;/code&amp;gt; ===&lt;br /&gt;
One place, all dashboards.&lt;br /&gt;
&lt;br /&gt;
== 5. The Working Code (Common.js) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
$(function () {&lt;br /&gt;
    const title = mw.config.get(&#039;wgPageName&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (title &amp;amp;&amp;amp; title.startsWith(&#039;Dashboard:&#039;)) {&lt;br /&gt;
&lt;br /&gt;
        // Only purge once&lt;br /&gt;
        if (!location.search.includes(&#039;mw_purged=1&#039;)) {&lt;br /&gt;
&lt;br /&gt;
            new mw.Api().get({&lt;br /&gt;
                action: &#039;query&#039;,&lt;br /&gt;
                meta: &#039;tokens&#039;,&lt;br /&gt;
                type: &#039;csrf&#039;&lt;br /&gt;
            }).done(function (data) {&lt;br /&gt;
&lt;br /&gt;
                const token = data.query.tokens.csrftoken;&lt;br /&gt;
&lt;br /&gt;
                new mw.Api().post({&lt;br /&gt;
                    action: &#039;purge&#039;,&lt;br /&gt;
                    titles: title,&lt;br /&gt;
                    token: token&lt;br /&gt;
                }).always(function () {&lt;br /&gt;
&lt;br /&gt;
                    // Reload the dashboard normally, marked as purged&lt;br /&gt;
                    const url = mw.util.getUrl(title, { mw_purged: 1 });&lt;br /&gt;
                    location.replace(url);&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Why This Works ==&lt;br /&gt;
&lt;br /&gt;
=== Silent purge ===&lt;br /&gt;
* API POST + CSRF token  &lt;br /&gt;
* No confirmation dialog  &lt;br /&gt;
&lt;br /&gt;
=== No loops ===&lt;br /&gt;
* &amp;lt;code&amp;gt;mw_purged=1&amp;lt;/code&amp;gt; is preserved  &lt;br /&gt;
* JS sees the marker and stops  &lt;br /&gt;
&lt;br /&gt;
=== Works for all dashboards ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;wgPageName&amp;lt;/code&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
=== Infrastructure‑safe ===&lt;br /&gt;
* Survives reverse proxies  &lt;br /&gt;
* Survives canonical URL rewrites  &lt;br /&gt;
* Survives short URLs  &lt;br /&gt;
&lt;br /&gt;
=== Successor‑friendly ===&lt;br /&gt;
* One central rule  &lt;br /&gt;
* No per‑page hacks  &lt;br /&gt;
&lt;br /&gt;
== 7. Architecture Diagram ==&lt;br /&gt;
&lt;br /&gt;
The following ASCII diagram shows the complete flow from saving a form to the final dashboard refresh.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                +-----------------------+&lt;br /&gt;
                |   User saves form     |&lt;br /&gt;
                |   (Page Forms)        |&lt;br /&gt;
                +-----------+-----------+&lt;br /&gt;
                            |&lt;br /&gt;
                            v&lt;br /&gt;
                +-----------------------+&lt;br /&gt;
                | Page Forms redirect   |&lt;br /&gt;
                | to Dashboard:XYZ      |&lt;br /&gt;
                +-----------+-----------+&lt;br /&gt;
                            |&lt;br /&gt;
                            v&lt;br /&gt;
                +-----------------------+&lt;br /&gt;
                | Dashboard loads       |&lt;br /&gt;
                | Common.js executes    |&lt;br /&gt;
                +-----------+-----------+&lt;br /&gt;
                            |&lt;br /&gt;
                            | JS checks:&lt;br /&gt;
                            |   - Is this Dashboard:* ?&lt;br /&gt;
                            |   - Is mw_purged=1 absent?&lt;br /&gt;
                            v&lt;br /&gt;
                +-----------------------+&lt;br /&gt;
                | Request CSRF token    |&lt;br /&gt;
                | via API (GET)         |&lt;br /&gt;
                +-----------+-----------+&lt;br /&gt;
                            |&lt;br /&gt;
                            v&lt;br /&gt;
                +-----------------------+&lt;br /&gt;
                | Silent purge via API  |&lt;br /&gt;
                | (POST + token)        |&lt;br /&gt;
                +-----------+-----------+&lt;br /&gt;
                            |&lt;br /&gt;
                            v&lt;br /&gt;
                +-----------------------+&lt;br /&gt;
                | Reload dashboard with |&lt;br /&gt;
                | ?mw_purged=1 marker   |&lt;br /&gt;
                +-----------+-----------+&lt;br /&gt;
                            |&lt;br /&gt;
                            v&lt;br /&gt;
                +-----------------------+&lt;br /&gt;
                | Dashboard loads fresh |&lt;br /&gt;
                | JS sees mw_purged=1   |&lt;br /&gt;
                | -&amp;gt; No purge triggered |&lt;br /&gt;
                +-----------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Summary ==&lt;br /&gt;
&lt;br /&gt;
The final solution works because it respects all of MediaWiki’s constraints:&lt;br /&gt;
&lt;br /&gt;
* Purge must be done via API POST  &lt;br /&gt;
* CSRF token is required  &lt;br /&gt;
* GET purge always shows a dialog  &lt;br /&gt;
* Page Forms cannot trigger purge  &lt;br /&gt;
* Unknown query parameters may be stripped  &lt;br /&gt;
* Only &amp;lt;code&amp;gt;mw_*&amp;lt;/code&amp;gt; parameters survive reliably  &lt;br /&gt;
&lt;br /&gt;
This produces a stable, silent, automatic purge mechanism for all dashboards.&lt;br /&gt;
&lt;br /&gt;
== 9. Failure Mode Diagrams ==&lt;br /&gt;
&lt;br /&gt;
The following diagrams illustrate each attempted solution, why it seemed plausible, and why it ultimately failed.  &lt;br /&gt;
These are included so future administrators can immediately understand the architectural traps and avoid repeating them.&lt;br /&gt;
&lt;br /&gt;
=== 9.1. Failure Mode 1 — HTML &amp;lt;meta&amp;gt; Refresh (Sanitized) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Dashboard page contains   |&lt;br /&gt;
| &amp;lt;meta http-equiv=&amp;quot;refresh&amp;quot;&amp;gt; &lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| MediaWiki sanitizes HTML  |&lt;br /&gt;
| &amp;lt;meta&amp;gt; is escaped         |&lt;br /&gt;
| (displayed as text)       |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| No refresh occurs         |&lt;br /&gt;
| Dashboard stays stale     |&lt;br /&gt;
+---------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for failure:&#039;&#039;&#039;  &lt;br /&gt;
MediaWiki strips or escapes &amp;lt;meta&amp;gt; tags for security. They never execute.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 9.2. Failure Mode 2 — Redirect to ?action=purge (Confirmation Dialog) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS redirects to           |&lt;br /&gt;
| Dashboard:XYZ?action=purge&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| MediaWiki shows dialog:   |&lt;br /&gt;
| &amp;quot;Do you want to purge?&amp;quot;   |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| User must click OK        |&lt;br /&gt;
| (not silent)              |&lt;br /&gt;
+---------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for failure:&#039;&#039;&#039;  &lt;br /&gt;
GET-based purge always triggers a confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 9.3. Failure Mode 3 — JS Redirect Loop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Dashboard loads           |&lt;br /&gt;
| JS sees &amp;quot;not purged&amp;quot;      |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS redirects to purge     |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Purge dialog appears      |&lt;br /&gt;
| User clicks OK            |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Dashboard reloads         |&lt;br /&gt;
| URL has no marker         |&lt;br /&gt;
| JS thinks &amp;quot;not purged&amp;quot;    |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS redirects again        |&lt;br /&gt;
| (infinite loop)           |&lt;br /&gt;
+---------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for failure:&#039;&#039;&#039;  &lt;br /&gt;
The dashboard reloads without a marker, so JS purges again.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 9.4. Failure Mode 4 — Query Parameter Stripping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS reloads dashboard with |&lt;br /&gt;
| ?purged=1                 |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Reverse proxy / skin      |&lt;br /&gt;
| strips unknown parameter  |&lt;br /&gt;
| (purged=1 removed)        |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Dashboard loads as        |&lt;br /&gt;
| Dashboard:XYZ             |&lt;br /&gt;
| (no marker)               |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS purges again           |&lt;br /&gt;
| (loop)                    |&lt;br /&gt;
+---------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for failure:&#039;&#039;&#039;  &lt;br /&gt;
Unknown parameters like &amp;lt;code&amp;gt;purged=1&amp;lt;/code&amp;gt; are removed by canonical URL rewriting.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 9.5. Failure Mode 5 — API Purge Without CSRF Token ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS calls API purge        |&lt;br /&gt;
| without CSRF token        |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| MediaWiki rejects purge   |&lt;br /&gt;
| &amp;quot;badtoken&amp;quot; or &amp;quot;permission&amp;quot;|&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Dashboard reloads         |&lt;br /&gt;
| still stale               |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for failure:&#039;&#039;&#039;  &lt;br /&gt;
MediaWiki requires a CSRF token for all write operations, including purge.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 9.6. Failure Mode 6 — API Purge Works, But Loop Continues ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS purges via API         |&lt;br /&gt;
| (correct)                 |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS reloads dashboard with |&lt;br /&gt;
| ?purged=1                 |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Skin / proxy strips       |&lt;br /&gt;
| ?purged=1                 |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Dashboard loads without   |&lt;br /&gt;
| marker                    |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| JS purges again           |&lt;br /&gt;
| (loop)                    |&lt;br /&gt;
+---------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for failure:&#039;&#039;&#039;  &lt;br /&gt;
Even with correct API purge, the loop persists if the marker is stripped.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 9.7. Final Working Architecture (for comparison) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Dashboard loads           |&lt;br /&gt;
| JS executes               |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              | JS checks:&lt;br /&gt;
              |   - Is Dashboard:* ?&lt;br /&gt;
              |   - Is mw_purged=1 absent?&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Request CSRF token        |&lt;br /&gt;
| via API (GET)             |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Silent purge via API      |&lt;br /&gt;
| (POST + token)            |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Reload dashboard with     |&lt;br /&gt;
| ?mw_purged=1              |&lt;br /&gt;
+-------------+-------------+&lt;br /&gt;
              |&lt;br /&gt;
              v&lt;br /&gt;
+---------------------------+&lt;br /&gt;
| Dashboard loads fresh     |&lt;br /&gt;
| JS sees mw_purged=1       |&lt;br /&gt;
| -&amp;gt; No purge triggered     |&lt;br /&gt;
+---------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reason for success:&#039;&#039;&#039;  &lt;br /&gt;
&amp;lt;code&amp;gt;mw_purged=1&amp;lt;/code&amp;gt; is preserved by MediaWiki, and API POST purge is silent.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Choosing_MediaWiki&amp;diff=1640</id>
		<title>ICT:Wiki - Choosing MediaWiki</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Choosing_MediaWiki&amp;diff=1640"/>
		<updated>2026-05-14T15:34:13Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Choosing MediaWiki to ICT:Wiki - Choosing MediaWiki without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Why MediaWiki (and not Omeka-S or Zotero) =&lt;br /&gt;
&lt;br /&gt;
This page explains the rationale for choosing MediaWiki as the technical platform for this project, instead of Omeka-S or Zotero.&lt;br /&gt;
&lt;br /&gt;
It is intended for collaborators who are familiar with digital research tools but not with system architecture or MediaWiki extensions.&lt;br /&gt;
&lt;br /&gt;
The goal is to provide sufficient context to understand later design documents without requiring technical expertise.&lt;br /&gt;
&lt;br /&gt;
== Initial Context ==&lt;br /&gt;
&lt;br /&gt;
At the start of the project, two existing platforms were considered:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Zotero&#039;&#039;&#039; – for managing references and sources&lt;br /&gt;
* &#039;&#039;&#039;Omeka-S&#039;&#039;&#039; – for publishing cultural heritage collections&lt;br /&gt;
&lt;br /&gt;
Both tools are well-established and widely used.&lt;br /&gt;
&lt;br /&gt;
However, as the research progressed, it became clear that neither tool fully matched the needs of the project.&lt;br /&gt;
&lt;br /&gt;
== What the Project Actually Requires ==&lt;br /&gt;
&lt;br /&gt;
The project is not only about collecting items or references.&lt;br /&gt;
&lt;br /&gt;
It requires the ability to:&lt;br /&gt;
&lt;br /&gt;
* Describe complex historical objects at multiple levels&lt;br /&gt;
* Represent relationships between objects, people, places, and institutions&lt;br /&gt;
* Handle uncertainty and interpretation explicitly&lt;br /&gt;
* Structure research into overlapping periods or chapters&lt;br /&gt;
* Manage large numbers of digital files and derivatives&lt;br /&gt;
* Separate internal research work from public presentation&lt;br /&gt;
* Allow the data model to evolve over time&lt;br /&gt;
&lt;br /&gt;
These requirements go beyond what a simple collection or bibliography system can provide.&lt;br /&gt;
&lt;br /&gt;
== Limitations of Zotero ==&lt;br /&gt;
&lt;br /&gt;
Zotero is excellent for:&lt;br /&gt;
&lt;br /&gt;
* Bibliographic references&lt;br /&gt;
* Citation management&lt;br /&gt;
* Personal or shared libraries&lt;br /&gt;
&lt;br /&gt;
However, Zotero:&lt;br /&gt;
&lt;br /&gt;
* Treats items as flat records&lt;br /&gt;
* Has limited support for complex relationships&lt;br /&gt;
* Is not designed for narrative structuring&lt;br /&gt;
* Is not intended as a publication platform&lt;br /&gt;
* Cannot model historical entities beyond references&lt;br /&gt;
&lt;br /&gt;
Zotero remains useful as a *supporting tool*, but not as the core research platform.&lt;br /&gt;
&lt;br /&gt;
== Limitations of Omeka-S ==&lt;br /&gt;
&lt;br /&gt;
Omeka-S is designed for:&lt;br /&gt;
&lt;br /&gt;
* Publishing cultural heritage collections&lt;br /&gt;
* Describing items with metadata&lt;br /&gt;
* Linking items to vocabularies&lt;br /&gt;
&lt;br /&gt;
However, Omeka-S:&lt;br /&gt;
&lt;br /&gt;
* Assumes relatively flat “items”&lt;br /&gt;
* Is rigid once a data model is chosen&lt;br /&gt;
* Handles hierarchy and recursion poorly&lt;br /&gt;
* Does not support complex, evolving research structures well&lt;br /&gt;
* Makes it difficult to separate internal research from public publication&lt;br /&gt;
* Is less suitable for long-term exploratory research&lt;br /&gt;
&lt;br /&gt;
Omeka-S is strongest when the structure is known in advance.&lt;br /&gt;
This project requires the structure to emerge through research.&lt;br /&gt;
&lt;br /&gt;
== Why MediaWiki Was Chosen ==&lt;br /&gt;
&lt;br /&gt;
MediaWiki is not a heritage platform by default.&lt;br /&gt;
&lt;br /&gt;
Its strength lies elsewhere:&lt;br /&gt;
&lt;br /&gt;
* It is concept-centric, not item-centric&lt;br /&gt;
* It supports gradual formalization&lt;br /&gt;
* It allows separation between content, structure, and presentation&lt;br /&gt;
* It scales well with complexity&lt;br /&gt;
* It supports collaborative knowledge building&lt;br /&gt;
* It can serve both internal and public audiences&lt;br /&gt;
&lt;br /&gt;
Most importantly:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;MediaWiki allows the research model to evolve without locking decisions too early.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== How MediaWiki Is Used in This Project (Conceptually) ==&lt;br /&gt;
&lt;br /&gt;
MediaWiki is used as a **knowledge platform**, not just a wiki.&lt;br /&gt;
&lt;br /&gt;
Conceptually, the system distinguishes between:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Concept !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| Heritage Objects || What is being studied (buildings, places, concepts)&lt;br /&gt;
|-&lt;br /&gt;
| Digital Assets || How something is represented digitally&lt;br /&gt;
|-&lt;br /&gt;
| Actors || Who was involved historically&lt;br /&gt;
|-&lt;br /&gt;
| Research Chapters || How the research is structured narratively&lt;br /&gt;
|-&lt;br /&gt;
| Files || Physical digital files (images, scans, PDFs)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These concepts exist independently of the technical implementation.&lt;br /&gt;
&lt;br /&gt;
== Why Additional Components Are Needed ==&lt;br /&gt;
&lt;br /&gt;
MediaWiki core handles pages and files very well.&lt;br /&gt;
&lt;br /&gt;
However, it does not natively support:&lt;br /&gt;
&lt;br /&gt;
* Structured data fields&lt;br /&gt;
* Repeating relationships&lt;br /&gt;
* Explicit modeling of uncertainty&lt;br /&gt;
* Querying structured relationships&lt;br /&gt;
&lt;br /&gt;
For this reason, additional components are used internally.&lt;br /&gt;
&lt;br /&gt;
These components are **implementation tools**, not concepts.&lt;br /&gt;
&lt;br /&gt;
== Meaning of the Main Components (Non-Technical) ==&lt;br /&gt;
&lt;br /&gt;
The following table explains the role of the main components without technical detail:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Component !! What it does (conceptually)&lt;br /&gt;
|-&lt;br /&gt;
| MediaWiki || Provides pages, collaboration, and publication&lt;br /&gt;
|-&lt;br /&gt;
| Structured forms || Guide users when entering information&lt;br /&gt;
|-&lt;br /&gt;
| Structured storage || Ensures data is consistent and queryable&lt;br /&gt;
|-&lt;br /&gt;
| Internal documentation || Records design decisions and reasoning&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Collaborators are not expected to understand or manage these components directly.&lt;br /&gt;
&lt;br /&gt;
== Internal vs Public Use ==&lt;br /&gt;
&lt;br /&gt;
The system deliberately separates:&lt;br /&gt;
&lt;br /&gt;
* Internal research work&lt;br /&gt;
* Public presentation of results&lt;br /&gt;
&lt;br /&gt;
Internal work:&lt;br /&gt;
* May be incomplete&lt;br /&gt;
* May change&lt;br /&gt;
* May include uncertainty and discussion&lt;br /&gt;
&lt;br /&gt;
Public content:&lt;br /&gt;
* Is curated&lt;br /&gt;
* Is stable&lt;br /&gt;
* Represents agreed results&lt;br /&gt;
&lt;br /&gt;
This separation is difficult to achieve in Omeka-S or Zotero, but natural in MediaWiki.&lt;br /&gt;
&lt;br /&gt;
== What This Means for Collaborators ==&lt;br /&gt;
&lt;br /&gt;
For most club members:&lt;br /&gt;
&lt;br /&gt;
* Interaction happens through forms&lt;br /&gt;
* Concepts are visible, not technical mechanisms&lt;br /&gt;
* No knowledge of MediaWiki internals is required&lt;br /&gt;
* The system behaves like a structured research environment&lt;br /&gt;
&lt;br /&gt;
Architectural complexity exists only to support clarity and flexibility.&lt;br /&gt;
&lt;br /&gt;
== How to Read the Other ICT Documents ==&lt;br /&gt;
&lt;br /&gt;
The other ICT documents:&lt;br /&gt;
&lt;br /&gt;
* Architecture&lt;br /&gt;
* Entity definitions&lt;br /&gt;
* ER model&lt;br /&gt;
* Workflow&lt;br /&gt;
* Policy&lt;br /&gt;
&lt;br /&gt;
are written to ensure long-term consistency.&lt;br /&gt;
&lt;br /&gt;
They are not manuals, but shared agreements.&lt;br /&gt;
&lt;br /&gt;
This page should be read first to understand the context in which those documents exist.&lt;br /&gt;
&lt;br /&gt;
== Status ==&lt;br /&gt;
&lt;br /&gt;
This document explains the platform choice and conceptual approach.&lt;br /&gt;
&lt;br /&gt;
It is intended to be stable and accessible to non-technical collaborators.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_and_Page_Forms_Architecture_Guide&amp;diff=1639</id>
		<title>ICT:Wiki - Cargo and Page Forms Architecture Guide</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_and_Page_Forms_Architecture_Guide&amp;diff=1639"/>
		<updated>2026-05-14T15:33:34Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Cargo and Page Forms Architecture Guide to ICT:Wiki - Cargo and Page Forms Architecture Guide without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Cargo + Page Forms Architecture Guide =&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
This document explains the architectural principles used to build the Costasano Heritage system in MediaWiki.&lt;br /&gt;
&lt;br /&gt;
The system uses:&lt;br /&gt;
&lt;br /&gt;
* Cargo → structured data storage (database tables)&lt;br /&gt;
* Templates → schema definitions&lt;br /&gt;
* Page Forms → controlled data entry&lt;br /&gt;
&lt;br /&gt;
We intentionally DO NOT use Page Schemas for production workflows.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Core philosophy ==&lt;br /&gt;
&lt;br /&gt;
MediaWiki is treated as:&lt;br /&gt;
&lt;br /&gt;
  Database + Forms + Pages&lt;br /&gt;
&lt;br /&gt;
NOT as free-form wiki text.&lt;br /&gt;
&lt;br /&gt;
We design like a relational application, not a document collection.&lt;br /&gt;
&lt;br /&gt;
Goals:&lt;br /&gt;
&lt;br /&gt;
* predictable behaviour&lt;br /&gt;
* explicit schemas&lt;br /&gt;
* enforced namespaces&lt;br /&gt;
* zero manual page naming&lt;br /&gt;
* minimal “magic”&lt;br /&gt;
&lt;br /&gt;
Clarity beats automation.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Responsibilities of each component ==&lt;br /&gt;
&lt;br /&gt;
=== Cargo ===&lt;br /&gt;
Responsible for:&lt;br /&gt;
* storing structured data&lt;br /&gt;
* tables&lt;br /&gt;
* querying&lt;br /&gt;
&lt;br /&gt;
Not responsible for:&lt;br /&gt;
* page creation&lt;br /&gt;
* validation&lt;br /&gt;
* UI&lt;br /&gt;
&lt;br /&gt;
=== Templates ===&lt;br /&gt;
Responsible for:&lt;br /&gt;
* defining table structure using #cargo_store&lt;br /&gt;
* acting as schema definitions&lt;br /&gt;
&lt;br /&gt;
Rule:&lt;br /&gt;
  1 template = 1 Cargo table&lt;br /&gt;
&lt;br /&gt;
=== Page Forms ===&lt;br /&gt;
Responsible for:&lt;br /&gt;
* creating/editing pages&lt;br /&gt;
* namespace enforcement&lt;br /&gt;
* page naming&lt;br /&gt;
* validation&lt;br /&gt;
* user experience&lt;br /&gt;
&lt;br /&gt;
Forms control workflow.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Standard stack ==&lt;br /&gt;
&lt;br /&gt;
For every entity:&lt;br /&gt;
&lt;br /&gt;
* Template&lt;br /&gt;
* Cargo table&lt;br /&gt;
* Form&lt;br /&gt;
* Namespace&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 DigitalAssets&lt;br /&gt;
   Template:DigitalAsset&lt;br /&gt;
   Form:DigitalAsset&lt;br /&gt;
   Namespace: DA&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Why not Page Schemas? ==&lt;br /&gt;
&lt;br /&gt;
Page Schemas lacks:&lt;br /&gt;
&lt;br /&gt;
* enforced namespaces&lt;br /&gt;
* automatic page names&lt;br /&gt;
* strict workflow control&lt;br /&gt;
* flexibility&lt;br /&gt;
&lt;br /&gt;
It is useful for learning, but too limited for production systems.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Design principles ==&lt;br /&gt;
&lt;br /&gt;
* explicit &amp;gt; implicit&lt;br /&gt;
* simple &amp;gt; clever&lt;br /&gt;
* small steps &amp;gt; big generation&lt;br /&gt;
* manual control &amp;gt; hidden automation&lt;br /&gt;
&lt;br /&gt;
If something feels magical, redesign it.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_and_PageForms&amp;diff=1638</id>
		<title>ICT:Wiki - Cargo and PageForms</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_and_PageForms&amp;diff=1638"/>
		<updated>2026-05-14T15:33:15Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Cargo and PageForms to ICT:Wiki - Cargo and PageForms without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Cargo and Page Forms Implementation Guide (2026) ==&lt;br /&gt;
&lt;br /&gt;
This guide explains how to set up a structured data system using the &#039;&#039;&#039;Cargo&#039;&#039;&#039; and &#039;&#039;&#039;Page Forms&#039;&#039;&#039; extensions in MediaWiki 1.45.&lt;br /&gt;
&lt;br /&gt;
=== 1. The Data Schema (Template:Book) ===&lt;br /&gt;
The template is the &amp;quot;brain&amp;quot; of the operation. It declares the database structure and stores the data when a page is saved.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Path:&#039;&#039;&#039; [[Template:Book]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{#cargo_declare:&lt;br /&gt;
_table = Books&lt;br /&gt;
|Title = String&lt;br /&gt;
|Author = String&lt;br /&gt;
|Year = Integer&lt;br /&gt;
}}&lt;br /&gt;
This template is used to store book metadata in the Cargo database.&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&amp;lt;includeonly&amp;gt;&lt;br /&gt;
{{#cargo_store:&lt;br /&gt;
_table = Books&lt;br /&gt;
}}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 300px;&amp;quot;&lt;br /&gt;
! Title&lt;br /&gt;
| {{{Title|}}}&lt;br /&gt;
|-&lt;br /&gt;
! Author&lt;br /&gt;
| {{{Author|}}}&lt;br /&gt;
|-&lt;br /&gt;
! Year&lt;br /&gt;
| {{{Year|}}}&lt;br /&gt;
|}&lt;br /&gt;
[[Category:Books]]&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. The Input Interface (Form:Book) ===&lt;br /&gt;
The form provides a user-friendly way to fill out the template without touching wikitext. It also enables autocompletion from existing Cargo data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Path:&#039;&#039;&#039; [[Form:Book]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{standard input|itemname|label=Book Page Title}}}&lt;br /&gt;
&lt;br /&gt;
{{{for template|Book}}}&lt;br /&gt;
{| class=&amp;quot;formtable&amp;quot;&lt;br /&gt;
! Book Title:&lt;br /&gt;
| {{{field|Title|mandatory}}}&lt;br /&gt;
|-&lt;br /&gt;
! Author:&lt;br /&gt;
| {{{field|Author|input type=combobox|cargo table=Books|cargo field=Author}}}&lt;br /&gt;
|-&lt;br /&gt;
! Publication Year:&lt;br /&gt;
| {{{field|Year|input type=number}}}&lt;br /&gt;
|}&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary of changes:&#039;&#039;&#039;&lt;br /&gt;
{{{standard input|summary}}}&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}} {{{standard input|preview}}} {{{standard input|cancel}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Activation Steps ===&lt;br /&gt;
After saving the pages above, you MUST perform these steps to activate the database:&lt;br /&gt;
# Go to [[Template:Book]].&lt;br /&gt;
# Click the &#039;&#039;&#039;&amp;quot;Create data table&amp;quot;&#039;&#039;&#039; (or &amp;quot;Recreate data&amp;quot;) tab at the top.&lt;br /&gt;
# Click &#039;&#039;&#039;OK&#039;&#039;&#039; to initialize the SQL table.&lt;br /&gt;
# Go to [[Category:Books]] and add {{code|{{#default_form:Book}}}} to ensure the &amp;quot;Edit with form&amp;quot; button appears automatically.&lt;br /&gt;
&lt;br /&gt;
=== 4. Querying the Data ===&lt;br /&gt;
To display the data stored in your &amp;quot;Books&amp;quot; table on any other page, use a Cargo query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
|tables = Books&lt;br /&gt;
|fields = _pageName=Page, Title, Author, Year&lt;br /&gt;
|where = Year &amp;gt; 2000&lt;br /&gt;
|format = table&lt;br /&gt;
|display_columns = Page, Title, Author, Year&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Resources ===&lt;br /&gt;
* [www.mediawiki.org Cargo Storing Documentation]&lt;br /&gt;
* [www.mediawiki.org Page Forms Definition Guide]&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_Geo_Coordinnates&amp;diff=1637</id>
		<title>ICT:Wiki - Cargo Geo Coordinnates</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_Geo_Coordinnates&amp;diff=1637"/>
		<updated>2026-05-14T15:32:57Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Cargo Geo Coordinnates to ICT:Wiki - Cargo Geo Coordinnates without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Handling Geographical Coordinates in Cargo ==&lt;br /&gt;
&lt;br /&gt;
Geographical data is stored using the &#039;&#039;&#039;Coordinates&#039;&#039;&#039; field type. This allows for both precise database storage and interactive map displays using [[Extension:Page Forms|Page Forms]] and [[Extension:Cargo|Cargo]].&lt;br /&gt;
&lt;br /&gt;
=== 1. Define the Cargo Table ===&lt;br /&gt;
In your table declaration, use the `Coordinates` field type.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_declare:_table=Places&lt;br /&gt;
|Name=String&lt;br /&gt;
|Location=Coordinates&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Create the Input Form ===&lt;br /&gt;
Use the `leaflet` input type (part of [[Extension:Page Forms]]) to provide an interactive map where users can click to set coordinates.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{field|Location|input type=leaflet|height=300|width=500}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Displaying Maps ===&lt;br /&gt;
&lt;br /&gt;
==== Display a map for a single location ====&lt;br /&gt;
Use the `#cargo_display_map` function on the page itself to show where the specific place is located.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_display_map:&lt;br /&gt;
|point={{{Location|}}}&lt;br /&gt;
|service=leaflet&lt;br /&gt;
|zoom=14&lt;br /&gt;
|height=400&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Display all places on a master map ====&lt;br /&gt;
To show all entries from your `Places` table on one map, use a `#cargo_query` with a map format.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
|tables=Places&lt;br /&gt;
|fields=_pageName=Page, Name, Location&lt;br /&gt;
|format=leaflet&lt;br /&gt;
|height=500&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Technical Note: Coordinate Format ===&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;: Cargo stores coordinates as &amp;quot;Latitude, Longitude&amp;quot; in decimal degrees (e.g., `51.2194, 2.8972`).&lt;br /&gt;
* &#039;&#039;&#039;Precision&#039;&#039;&#039;: Ensure you use a period (`.`) for decimals and a comma (`,`) to separate the two values.&lt;br /&gt;
* &#039;&#039;&#039;Services&#039;&#039;&#039;: While `leaflet` is recommended for its ease of use, you can also use `googlemaps` or `openlayers` if they are configured on your wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Choosing a Map Service for Forms ==&lt;br /&gt;
&lt;br /&gt;
To display a map in a form for coordinate input, use the `input type` parameter.&lt;br /&gt;
&lt;br /&gt;
=== Option A: Leaflet (Recommended) ===&lt;br /&gt;
Uses OpenStreetMap. No API key required.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{field|Location|input type=leaflet}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Option B: OpenLayers (Default) ===&lt;br /&gt;
Solid open-source alternative.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{field|Location|input type=openlayers}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Option C: Google Maps ===&lt;br /&gt;
Requires a Google Maps API Key to be configured in your wiki&#039;s LocalSettings.php.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{field|Location|input type=googlemaps}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Common Parameters ===&lt;br /&gt;
You can customize the map&#039;s appearance in the form using these parameters:&lt;br /&gt;
* `height`: Height in pixels (e.g., `300`).&lt;br /&gt;
* `width`: Width in pixels (e.g., `500`).&lt;br /&gt;
* `starting bounds`: Initial map area if no coordinate is set yet (e.g., `-20,-15;50,55`).&lt;br /&gt;
&lt;br /&gt;
=== Leaflet Troubleshooting ===&lt;br /&gt;
* &#039;&#039;&#039;Map not appearing:&#039;&#039;&#039; Ensure the `height` parameter is set (e.g., `height=400`).&lt;br /&gt;
* &#039;&#039;&#039;Marker not saving:&#039;&#039;&#039; Make sure you clicked the map to place the marker; simply zooming in won&#039;t store coordinates in the field.&lt;br /&gt;
* &#039;&#039;&#039;Search box:&#039;&#039;&#039; To add a search-by-address bar to your form map, add `|show search box` to the field parameters.&lt;br /&gt;
&lt;br /&gt;
== Automating Place Data with Geocoding ==&lt;br /&gt;
&lt;br /&gt;
The [[Extension:Maps|Maps extension]] provides the `{{#geocode:}}` function, which can automatically turn human-readable addresses into Cargo-compatible coordinates.&lt;br /&gt;
&lt;br /&gt;
=== 1. Using Geocode in a Template ===&lt;br /&gt;
You can set up your template so that it accepts a &amp;quot;Street Address&amp;quot; but stores &amp;quot;Coordinates&amp;quot; in Cargo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_store:_table=Places&lt;br /&gt;
|Name={{{Name|}}}&lt;br /&gt;
|Location={{#geocode:{{{Address|}}}}}&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Using Geocode in a Query ===&lt;br /&gt;
You can also geocode &amp;quot;on the fly&amp;quot; to find distances or filter by location without having coordinates stored.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
|tables=Places&lt;br /&gt;
|fields=Name&lt;br /&gt;
|where=DISTANCE(Location, &#039;{{#geocode:Brussels, Belgium}}&#039;) &amp;lt; 5000&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Configuration Tips ===&lt;br /&gt;
* &#039;&#039;&#039;Default Service:&#039;&#039;&#039; By default, Maps uses &#039;&#039;&#039;Nominatim&#039;&#039;&#039; (OpenStreetMap). This is free and requires no API key.&lt;br /&gt;
* &#039;&#039;&#039;Accuracy:&#039;&#039;&#039; Geocoding results depend on the external service. For high-volume wikis, results are cached to improve performance.&lt;br /&gt;
* &#039;&#039;&#039;Manual Overrides:&#039;&#039;&#039; Always provide a field for manual coordinates in case the auto-geocoding fails for a specific obscure location.&lt;br /&gt;
&lt;br /&gt;
SearchBox&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{field|Location|input type=leaflet|show search box}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Research Documentation: Sanatoria of the Belgian Coast (1850–2026) ==&lt;br /&gt;
&lt;br /&gt;
This research tracks the spatial and chronological evolution of tuberculosis (TBC) treatment centers for children.&lt;br /&gt;
&lt;br /&gt;
=== 1. Cargo Table Structure ===&lt;br /&gt;
We use a specific table to link physical coordinates with historical time periods.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_declare:_table=Sanatoria&lt;br /&gt;
|Name=String          &amp;lt;!-- Current or common name (e.g., Zeepreventorium) --&amp;gt;&lt;br /&gt;
|HistoricalName=String &amp;lt;!-- Name used in 1850-1950 (e.g., Solarium Touriste) --&amp;gt;&lt;br /&gt;
|City=String          &amp;lt;!-- Modern municipality --&amp;gt;&lt;br /&gt;
|OpeningYear=Date      &amp;lt;!-- Use &amp;quot;year&amp;quot; input type in forms --&amp;gt;&lt;br /&gt;
|ClosingYear=Date      &amp;lt;!-- Leave blank if still active in 2026 --&amp;gt;&lt;br /&gt;
|Location=Coordinates  &amp;lt;!-- Physical GPS spot --&amp;gt;&lt;br /&gt;
|Type=String           &amp;lt;!-- Sanatorium, Preventorium, or Openluchtschool --&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Mapping Historical &amp;quot;Existence&amp;quot; ===&lt;br /&gt;
To show where a sanatorium &amp;quot;was&amp;quot; during a specific historical period, use a query that filters by your year fields.&lt;br /&gt;
&lt;br /&gt;
==== Example: Map of all sites active in 1920 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
|tables=Sanatoria&lt;br /&gt;
|fields=Name, Location, OpeningYear&lt;br /&gt;
|where=YEAR(OpeningYear) &amp;lt;= 1920 AND (YEAR(ClosingYear) &amp;gt;= 1920 OR ClosingYear IS NULL)&lt;br /&gt;
|format=leaflet&lt;br /&gt;
|height=500&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Historical Map Layers (Advanced) ===&lt;br /&gt;
Since modern OpenStreetMap didn&#039;t exist in 1850, you can overlay historical Belgian maps using WMTS services (e.g., from the NGI or AGIV). &lt;br /&gt;
&lt;br /&gt;
In your Leaflet display, you can add a historical base layer:&lt;br /&gt;
* &#039;&#039;&#039;Vandermaelen (1846-1854):&#039;&#039;&#039; Useful for the start of your study period.&lt;br /&gt;
* &#039;&#039;&#039;Ferraris (1777):&#039;&#039;&#039; For pre-industrial coastal context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_display_map:&lt;br /&gt;
|point={{{Location|}}}&lt;br /&gt;
|service=leaflet&lt;br /&gt;
|layers=HistoricalBelgianMap &amp;lt;!-- Requires Wiki-side configuration --&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Research Notes on Coordinates ===&lt;br /&gt;
* &#039;&#039;&#039;Lost Buildings:&#039;&#039;&#039; If a sanatorium was demolished (e.g., many coastal villas during WWII), use coordinates from historical cadastral maps (Atlas der Buurtwegen).&lt;br /&gt;
* &#039;&#039;&#039;Accuracy:&#039;&#039;&#039; If the exact coordinate is approximate, document this in a &amp;quot;Notes&amp;quot; field so other researchers know the marker is an estimate.&lt;br /&gt;
&lt;br /&gt;
=== Using Map Clustering ===&lt;br /&gt;
To keep the map clean when many sanatoria are close together, always add `|cluster=yes` to your queries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
|tables=Sanatoria&lt;br /&gt;
|fields=Location&lt;br /&gt;
|format=leaflet&lt;br /&gt;
|cluster=yes&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Advantage:&#039;&#039;&#039; Improved performance and a cleaner user interface.&lt;br /&gt;
* &#039;&#039;&#039;Behavior:&#039;&#039;&#039; Clicking a cluster zooms the map automatically to reveal the individual markers.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_-_Adding_a_New_Entity/Table&amp;diff=1634</id>
		<title>ICT:Wiki - Cargo - Adding a New Entity/Table</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_-_Adding_a_New_Entity/Table&amp;diff=1634"/>
		<updated>2026-05-14T15:30:52Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Cargo - Adding a New Entity/Table to ICT:Wiki - Cargo - Adding a New Entity/Table without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= How to Add a New Entity/Table =&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
Step-by-step guide for adding new data entities to the system.&lt;br /&gt;
&lt;br /&gt;
Follow this order strictly.&lt;br /&gt;
&lt;br /&gt;
Do not skip steps.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 1 – Update DBML ==&lt;br /&gt;
Add the table definition to the DBML model first.&lt;br /&gt;
&lt;br /&gt;
DBML is the source of truth.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 2 – Create template ==&lt;br /&gt;
&lt;br /&gt;
Create:&lt;br /&gt;
&lt;br /&gt;
 Template:EntityName&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_store:&lt;br /&gt;
 _table=EntityNames&lt;br /&gt;
 |field1={{{field1|}}}&lt;br /&gt;
 |field2={{{field2|}}}&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 3 – Create Cargo table ==&lt;br /&gt;
&lt;br /&gt;
Go to:&lt;br /&gt;
&lt;br /&gt;
 Special:CargoTables&lt;br /&gt;
&lt;br /&gt;
Click:&lt;br /&gt;
&lt;br /&gt;
 Recreate data&lt;br /&gt;
&lt;br /&gt;
Verify table exists.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 4 – Create form ==&lt;br /&gt;
&lt;br /&gt;
Go to:&lt;br /&gt;
&lt;br /&gt;
 Special:CreateForm&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&lt;br /&gt;
* template&lt;br /&gt;
* fields&lt;br /&gt;
* target namespace&lt;br /&gt;
* page name formula&lt;br /&gt;
* hide title&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 5 – Test manually ==&lt;br /&gt;
&lt;br /&gt;
Create one page.&lt;br /&gt;
&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
* page in correct namespace&lt;br /&gt;
* data stored&lt;br /&gt;
* queries work&lt;br /&gt;
&lt;br /&gt;
Only then proceed.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 6 – Add queries or lists ==&lt;br /&gt;
&lt;br /&gt;
After structure works:&lt;br /&gt;
&lt;br /&gt;
* Cargo queries&lt;br /&gt;
* lists&lt;br /&gt;
* reports&lt;br /&gt;
&lt;br /&gt;
Never design UI before schema works.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Checklist ==&lt;br /&gt;
&lt;br /&gt;
Before marking complete:&lt;br /&gt;
&lt;br /&gt;
[ ] template exists  &lt;br /&gt;
[ ] cargo table created  &lt;br /&gt;
[ ] form works  &lt;br /&gt;
[ ] namespace enforced  &lt;br /&gt;
[ ] page name automatic  &lt;br /&gt;
[ ] test page saved  &lt;br /&gt;
[ ] query returns data  &lt;br /&gt;
&lt;br /&gt;
If any box unchecked → fix first.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Rule ==&lt;br /&gt;
Small working increments beat big automatic generation.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Bullet_Proof_UI_checklist&amp;diff=1633</id>
		<title>ICT:Wiki - Bullet Proof UI checklist</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Bullet_Proof_UI_checklist&amp;diff=1633"/>
		<updated>2026-05-14T15:30:25Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Bullet Proof UI checklist to ICT:Wiki - Bullet Proof UI checklist without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Bullet-proof UI Checklist (MediaWiki / Page Forms) =&lt;br /&gt;
&lt;br /&gt;
This page documents practical rules for designing robust,&lt;br /&gt;
low-error user interfaces in MediaWiki using Page Forms and Cargo.&lt;br /&gt;
&lt;br /&gt;
The target users of the system are historians and domain experts,&lt;br /&gt;
not ICT specialists. The UI must therefore prevent mistakes by design,&lt;br /&gt;
not by training.&lt;br /&gt;
&lt;br /&gt;
This checklist is based on real production observations.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Core Principle ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If a user can make a mistake, eventually someone will.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Therefore:&lt;br /&gt;
* Do not rely on user understanding&lt;br /&gt;
* Do not rely on documentation alone&lt;br /&gt;
* Encode rules directly into the form UI whenever possible&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Prefer Guidance over Enforcement (v1 rule) ==&lt;br /&gt;
&lt;br /&gt;
In early versions (v1):&lt;br /&gt;
* Guide users clearly&lt;br /&gt;
* Avoid complex enforcement logic&lt;br /&gt;
* Avoid JavaScript unless strictly necessary&lt;br /&gt;
&lt;br /&gt;
Enforcement can be added later once behavior is understood.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Every Field Must Answer Three Questions ==&lt;br /&gt;
&lt;br /&gt;
For each form field, the UI must make clear:&lt;br /&gt;
&lt;br /&gt;
# What should I do here?&lt;br /&gt;
# What should I NOT do here?&lt;br /&gt;
# What happens after I do it?&lt;br /&gt;
&lt;br /&gt;
If the UI does not answer these visually or textually,&lt;br /&gt;
the field is not safe.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. Use Instructional Placeholders ==&lt;br /&gt;
&lt;br /&gt;
Use placeholders to guide action and discourage typing&lt;br /&gt;
when typing is not intended.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
|placeholder=Click “Upload file” to select a file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Good use cases:&lt;br /&gt;
* file uploads&lt;br /&gt;
* auto-generated values&lt;br /&gt;
* system-controlled fields&lt;br /&gt;
&lt;br /&gt;
Placeholders are read before interaction and reduce errors.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. Put Rules Next to the Field, Not in Documentation ==&lt;br /&gt;
&lt;br /&gt;
Never rely on users reading separate documentation.&lt;br /&gt;
&lt;br /&gt;
Rules must appear directly where the decision is made.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;small&amp;gt;&lt;br /&gt;
Exactly one file must be uploaded for each Asset.&lt;br /&gt;
The file name cannot be changed afterwards.&lt;br /&gt;
&amp;lt;/small&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Short, explicit rules are preferred over long explanations.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5. Remove Wrong Affordances ==&lt;br /&gt;
&lt;br /&gt;
Do not present UI elements that suggest the wrong action.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
* Avoid text inputs where free typing is not expected&lt;br /&gt;
* Prefer selectors, upload buttons, and controlled inputs&lt;br /&gt;
&lt;br /&gt;
Do not “forbid” actions silently — avoid suggesting them visually.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 6. Editable on Creation, Stable Afterwards ==&lt;br /&gt;
&lt;br /&gt;
Many values should be decided once and then remain stable.&lt;br /&gt;
&lt;br /&gt;
Use this pattern where applicable:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
|editifempty=yes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typical use cases:&lt;br /&gt;
* identifiers&lt;br /&gt;
* original file names&lt;br /&gt;
* source references&lt;br /&gt;
* archival metadata&lt;br /&gt;
&lt;br /&gt;
This matches how archivists think:&lt;br /&gt;
&#039;&#039;decide once, then preserve&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 7. Avoid Ambiguous Optionality ==&lt;br /&gt;
&lt;br /&gt;
Avoid wording like:&lt;br /&gt;
* “optional”&lt;br /&gt;
* “if applicable”&lt;br /&gt;
* “you may leave empty”&lt;br /&gt;
&lt;br /&gt;
Prefer explicit rules:&lt;br /&gt;
&lt;br /&gt;
Bad:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
(Optional – leave empty if using Organisation)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Better:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Use either Place or Organisation, not both.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clear rules reduce hesitation and inconsistent data.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 8. Separate Technical Identifiers from Human Labels ==&lt;br /&gt;
&lt;br /&gt;
* Page names are technical identifiers&lt;br /&gt;
* Labels are human-readable and may change&lt;br /&gt;
&lt;br /&gt;
Never expose technical identifiers unnecessarily in the UI.&lt;br /&gt;
Always display labels where possible.&lt;br /&gt;
&lt;br /&gt;
This prevents:&lt;br /&gt;
* copying of technical IDs&lt;br /&gt;
* accidental misuse&lt;br /&gt;
* inconsistent conventions&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 9. No Silent Automation ==&lt;br /&gt;
&lt;br /&gt;
If a value is generated automatically (now or in the future),&lt;br /&gt;
announce this clearly in the UI.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;small&amp;gt;&lt;br /&gt;
This value is generated automatically by the system.&lt;br /&gt;
Do not try to change it manually.&lt;br /&gt;
&amp;lt;/small&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Users must understand when the system is in control.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 10. Prefer Deterministic Storage ==&lt;br /&gt;
&lt;br /&gt;
For v1:&lt;br /&gt;
* Prefer deterministic storage over strict typing&lt;br /&gt;
* Avoid race conditions between UI and storage&lt;br /&gt;
* Decouple user interaction from data persistence when necessary&lt;br /&gt;
&lt;br /&gt;
Correctness is more important than elegance in early versions.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Final Sanity Check ==&lt;br /&gt;
&lt;br /&gt;
Before accepting a form field, ask:&lt;br /&gt;
&lt;br /&gt;
# Can a user misunderstand this field?&lt;br /&gt;
# Does the UI invite the wrong action?&lt;br /&gt;
# Is the rule visible at the point of action?&lt;br /&gt;
# Is the value stable when it should be?&lt;br /&gt;
# Would a non-technical historian feel confident using this?&lt;br /&gt;
&lt;br /&gt;
If any answer is “no”, improve the UI.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Status ==&lt;br /&gt;
&lt;br /&gt;
This checklist is considered **stable for v1**.&lt;br /&gt;
It will be extended when JavaScript-based enforcement&lt;br /&gt;
and v2 automation are introduced.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo-Workflow&amp;diff=1632</id>
		<title>ICT:Wiki - Cargo-Workflow</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo-Workflow&amp;diff=1632"/>
		<updated>2026-05-14T15:30:04Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Cargo-Workflow to ICT:Wiki - Cargo-Workflow without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ICT:Cargo-Workflow – Final Working Configuration (Cargo + PageForms) =&lt;br /&gt;
&lt;br /&gt;
This page documents the final, stable configuration for the postcard archive using Cargo and PageForms.  &lt;br /&gt;
It contains the complete working setup in one place, ready for successors.&lt;br /&gt;
&lt;br /&gt;
== 1) LocalSettings.php configuration ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Cargo extension&lt;br /&gt;
$wgCargoDBtype = &amp;quot;mysql&amp;quot;;&lt;br /&gt;
$wgCargoDBserver = &amp;quot;10.10.10.2&amp;quot;;&lt;br /&gt;
$wgCargoDBname = &amp;quot;cargodb&amp;quot;;&lt;br /&gt;
$wgCargoDBuser = &amp;quot;cargouser&amp;quot;;&lt;br /&gt;
$wgCargoDBpassword = &amp;quot;Mhv+mak!90&amp;quot;;&lt;br /&gt;
$wgCargoDBprefix = &amp;quot;&amp;quot;;&lt;br /&gt;
$wgCargo24HourTime = true;&lt;br /&gt;
&lt;br /&gt;
wfLoadExtension( &#039;Cargo&#039; );&lt;br /&gt;
&lt;br /&gt;
# PageForms extension&lt;br /&gt;
wfLoadExtension( &#039;PageForms&#039; );&lt;br /&gt;
$wgPageFormsUploadableFiles = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039;  &lt;br /&gt;
$wgPageFormsUploadableFiles = true; must appear &#039;&#039;after&#039;&#039; wfLoadExtension( &#039;PageForms&#039; ).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2) Template:Item ==&lt;br /&gt;
&lt;br /&gt;
This template defines the Cargo table and how each item page displays.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;amp;lt;includeonly&amp;amp;gt;&lt;br /&gt;
{{#cargo_declare:&lt;br /&gt;
  _table=Items,&lt;br /&gt;
  Title=String,&lt;br /&gt;
  Image=File&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Title:&#039;&#039;&#039; {{{Title}}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Image:&#039;&#039;&#039; [[File:{{{Image}}}|400px]]&lt;br /&gt;
&amp;amp;lt;/includeonly&amp;amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* Only the &amp;amp;lt;includeonly&amp;amp;gt; section is used by Cargo and PageForms.  &lt;br /&gt;
* The Image field must be declared as File.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3) Form:Item ==&lt;br /&gt;
&lt;br /&gt;
This is the form used to create new items.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{info|page name=Item_&amp;lt;unique number&amp;gt;}}}&lt;br /&gt;
{{{for template|Item}}}&lt;br /&gt;
&lt;br /&gt;
;Title&lt;br /&gt;
:{{{field|Title}}}&lt;br /&gt;
&lt;br /&gt;
;Image&lt;br /&gt;
:{{{field|Image|input type=upload|uploadable}}}&lt;br /&gt;
&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}}&lt;br /&gt;
{{{standard input|cancel}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Key points:&lt;br /&gt;
* The info directive &#039;&#039;&#039;must be the first line&#039;&#039;&#039; (no blank lines above it).  &lt;br /&gt;
* input type=upload|uploadable enables the upload widget.  &lt;br /&gt;
* Page names are automatically generated: Item_0001, Item_0002, …&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4) AddItem page ==&lt;br /&gt;
&lt;br /&gt;
This page provides a simple button for club members to add new items.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
== Add a new item ==&lt;br /&gt;
&lt;br /&gt;
Click the button below to add a new item.&lt;br /&gt;
&lt;br /&gt;
{{#formlink:form=Item|link text=➕ Add a new item|link type=button}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Users never see Special:FormStart and never choose page names.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5) BrowseItems page ==&lt;br /&gt;
&lt;br /&gt;
This page shows all items in a gallery.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
== Browse Items ==&lt;br /&gt;
&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
  tables=Items&lt;br /&gt;
  |fields=Title,Image&lt;br /&gt;
  |format=gallery&lt;br /&gt;
  |image size=200&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* tables=Items must be on its own line.  &lt;br /&gt;
* All other parameters start with |.  &lt;br /&gt;
* Produces a clickable gallery of all postcards.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 6) Final User Workflow ==&lt;br /&gt;
&lt;br /&gt;
Club members now follow a simple workflow:&lt;br /&gt;
&lt;br /&gt;
# Go to &#039;&#039;&#039;Add a new item&#039;&#039;&#039;&lt;br /&gt;
# Click the button  &lt;br /&gt;
# Fill in Title + upload an image  &lt;br /&gt;
# Save  &lt;br /&gt;
# The item appears automatically in &#039;&#039;&#039;Browse Items&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No technical knowledge required.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 7) System Status ==&lt;br /&gt;
&lt;br /&gt;
The system now provides:&lt;br /&gt;
&lt;br /&gt;
* A working Cargo table  &lt;br /&gt;
* A working PageForms form  &lt;br /&gt;
* Automatic page naming  &lt;br /&gt;
* Working file uploads  &lt;br /&gt;
* A clean Add Item button  &lt;br /&gt;
* A gallery-style Browse page  &lt;br /&gt;
* A stable foundation for future expansion  &lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Automatic_Numbering&amp;diff=1631</id>
		<title>ICT:Wiki - Automatic Numbering</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Automatic_Numbering&amp;diff=1631"/>
		<updated>2026-05-14T15:29:18Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Automatic Numbering to ICT:Wiki - Automatic Numbering without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== ICT Documentation: Automatic Identifier Logic (Lua) ==&lt;br /&gt;
&lt;br /&gt;
The `DigitalAssets` table uses a Lua script ([[Module:AssetIdentifier]]) to ensure unique, sequential numbering.&lt;br /&gt;
&lt;br /&gt;
=== 1. Input Variables ===&lt;br /&gt;
The script requires three inputs from the [[Form:DigitalAsset]]:&lt;br /&gt;
* `chapter_id` (from ResearchChapters)&lt;br /&gt;
* `context_code` (from Places or Organisations)&lt;br /&gt;
* `sequence_number` (calculated automatically)&lt;br /&gt;
&lt;br /&gt;
=== 2. Identifier Construction ===&lt;br /&gt;
The final ID is constructed using the pattern: &lt;br /&gt;
`[ChapterCode]-[ContextCode]-[Sequence]`&lt;br /&gt;
* Example: `CH01-OST-0001` (Chapter 1, Ostend, first asset)&lt;br /&gt;
&lt;br /&gt;
=== 3. Maintenance Note ===&lt;br /&gt;
If a record is deleted, the `sequence_number` for that specific context will have a &amp;quot;gap.&amp;quot; This is acceptable in archival practice to maintain the integrity of existing permalinks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ICT Documentation: Sequential Numbering (Lua) ==&lt;br /&gt;
&lt;br /&gt;
To generate the `sequence_number` (e.g., 0007), the Lua module performs a Cargo query on the `DigitalAssets` table before the save is finalized.&lt;br /&gt;
&lt;br /&gt;
=== 1. The Lookup Query ===&lt;br /&gt;
The script filters by `chapter_id` AND `context_code`:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
local results = mw.ext.cargo.query(&lt;br /&gt;
    &#039;DigitalAssets&#039;,&lt;br /&gt;
    &#039;sequence_number&#039;,&lt;br /&gt;
    {&lt;br /&gt;
        where = &#039;chapter_id = &amp;quot;&#039; .. selectedChapter .. &#039;&amp;quot; AND context_code = &amp;quot;&#039; .. selectedContext .. &#039;&amp;quot;&#039;,&lt;br /&gt;
        order_by = &#039;sequence_number DESC&#039;,&lt;br /&gt;
        limit = 1&lt;br /&gt;
    }&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Increment Logic ===&lt;br /&gt;
* If no records exist: `sequence_number = 1`&lt;br /&gt;
* If records exist: `sequence_number = results[1].sequence_number + 1`&lt;br /&gt;
&lt;br /&gt;
=== 3. Format Padding ===&lt;br /&gt;
The number is always padded to 4 digits for visual consistency in the archive:&lt;br /&gt;
`string.format(&amp;quot;%04d&amp;quot;, sequence_number)`&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:WIKI_-_Architecture&amp;diff=1628</id>
		<title>ICT:WIKI - Architecture</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:WIKI_-_Architecture&amp;diff=1628"/>
		<updated>2026-05-14T15:06:57Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Architecture to ICT:WIKI - Architecture without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= System Architecture =&lt;br /&gt;
&lt;br /&gt;
This page describes the overall technical architecture of the MediaWiki installation used for heritage research and digital asset management.&lt;br /&gt;
&lt;br /&gt;
It explains the roles of the main components and how they interact.&lt;br /&gt;
&lt;br /&gt;
== Architectural Goals ==&lt;br /&gt;
&lt;br /&gt;
The architecture is designed to:&lt;br /&gt;
&lt;br /&gt;
* Support complex, relational research data&lt;br /&gt;
* Scale to many objects, persons, and digital assets&lt;br /&gt;
* Separate internal research work from public presentation&lt;br /&gt;
* Minimize future refactoring&lt;br /&gt;
* Remain compatible with MediaWiki core and extensions&lt;br /&gt;
&lt;br /&gt;
== Layered Architecture ==&lt;br /&gt;
&lt;br /&gt;
The system is structured in logical layers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Component !! Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| Presentation || Pages (Main namespace) || Public narratives and results&lt;br /&gt;
|-&lt;br /&gt;
| Structured Content || HO:, DA: namespaces || Internal structured entities&lt;br /&gt;
|-&lt;br /&gt;
| Data Entry || Forms (Page Schemas) || Controlled input&lt;br /&gt;
|-&lt;br /&gt;
| Schema Definition || Page Schemas || Mapping fields to storage&lt;br /&gt;
|-&lt;br /&gt;
| Data Storage || Cargo || Database schema and persistence&lt;br /&gt;
|-&lt;br /&gt;
| Physical Storage || File: namespace || Uploaded files&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each layer has a single responsibility and must not take over the role of another layer.&lt;br /&gt;
&lt;br /&gt;
== Core Components ==&lt;br /&gt;
&lt;br /&gt;
=== Cargo ===&lt;br /&gt;
&lt;br /&gt;
Cargo is the authoritative data storage layer.&lt;br /&gt;
&lt;br /&gt;
* Defines database tables&lt;br /&gt;
* Controls field types&lt;br /&gt;
* Executes schema changes&lt;br /&gt;
* Stores normalized data&lt;br /&gt;
&lt;br /&gt;
Cargo tables are defined on wiki pages (`Cargo:…`) and must be manually activated by saving the page.&lt;br /&gt;
&lt;br /&gt;
=== Forms ===&lt;br /&gt;
&lt;br /&gt;
Forms provide:&lt;br /&gt;
&lt;br /&gt;
* Editor-friendly data entry&lt;br /&gt;
* Controlled creation of pages&lt;br /&gt;
* Enforcement of required fields&lt;br /&gt;
* Repeatable sections for relationships&lt;br /&gt;
&lt;br /&gt;
Forms are the only supported way to create structured pages.&lt;br /&gt;
&lt;br /&gt;
=== Namespaces ===&lt;br /&gt;
&lt;br /&gt;
Namespaces separate concerns and enable access control.&lt;br /&gt;
&lt;br /&gt;
Namespaces are structural and long-lived decisions.&lt;br /&gt;
&lt;br /&gt;
== Files and the Digital Asset Abstraction ==&lt;br /&gt;
&lt;br /&gt;
Digital Assets (DA) are metadata pages that represent conceptual media objects (files)&lt;br /&gt;
&lt;br /&gt;
They abstract over:&lt;br /&gt;
&lt;br /&gt;
* One or more files&lt;br /&gt;
* Derivatives&lt;br /&gt;
* OCR outputs&lt;br /&gt;
* Language versions&lt;br /&gt;
* Relationships to heritage objects&lt;br /&gt;
&lt;br /&gt;
Files are never treated as data entities by themselves.&lt;br /&gt;
&lt;br /&gt;
== Architectural Constraints ==&lt;br /&gt;
&lt;br /&gt;
The following constraints apply:&lt;br /&gt;
&lt;br /&gt;
* No direct database schema manipulation&lt;br /&gt;
* No semantic meaning stored only on File: pages&lt;br /&gt;
* No public dependency on private files&lt;br /&gt;
* No uncontrolled page creation in structured namespaces&lt;br /&gt;
&lt;br /&gt;
== Status ==&lt;br /&gt;
&lt;br /&gt;
This architecture is the baseline for all future development.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Account_protection&amp;diff=1627</id>
		<title>ICT:Wiki - Account protection</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Account_protection&amp;diff=1627"/>
		<updated>2026-05-14T14:38:32Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Account protection to ICT:Wiki - Account protection without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:Access Control: The &amp;quot;Lockdown&amp;quot; Model}}&lt;br /&gt;
__TOC__&lt;br /&gt;
== Philosophy ==&lt;br /&gt;
This wiki is a &#039;&#039;&#039;Private Research Platform&#039;&#039;&#039;. To simplify management, we avoid &amp;quot;blacklisting&amp;quot; individual default namespaces. Instead, we use a &amp;quot;White-room&amp;quot; approach: everything is forbidden by default, and access is granted only to the specific functional layers required for research.&lt;br /&gt;
&lt;br /&gt;
== 1. Global Restrictions ==&lt;br /&gt;
Applied in `LocalSettings.php` to ensure the wiki is invisible to the public and restricted for standard users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
# Full Privacy: Revoke read from all by default&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;read&#039;] = false;&lt;br /&gt;
$wgGroupPermissions[&#039;user&#039;][&#039;read&#039;] = false; &lt;br /&gt;
&lt;br /&gt;
# Sysop Override: Ensure admins maintain full visibility&lt;br /&gt;
$wgGroupPermissions[&#039;sysop&#039;][&#039;read&#039;] = true;&lt;br /&gt;
&lt;br /&gt;
# Essential Whitelist: Required for login and site rendering&lt;br /&gt;
$wgWhitelistRead = [&lt;br /&gt;
    &amp;quot;Special:UserLogin&amp;quot;,&lt;br /&gt;
    &amp;quot;MediaWiki:Common.css&amp;quot;,&lt;br /&gt;
    &amp;quot;MediaWiki:Common.js&amp;quot;&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Research Environment Exceptions ==&lt;br /&gt;
Using [[Extension:Lockdown]], we grant the `user` group access to the specific namespaces required for the Dashboard, Cargo queries, and Page Forms.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
# Research Namespaces&lt;br /&gt;
$wgNamespacePermissionLockdown[NS_RESEARCH][&#039;read&#039;] = [&#039;user&#039;, &#039;sysop&#039;];&lt;br /&gt;
$wgNamespacePermissionLockdown[NS_DASHBOARD][&#039;read&#039;] = [&#039;user&#039;, &#039;sysop&#039;];&lt;br /&gt;
&lt;br /&gt;
# Supporting Infrastructure (Required for Dashboard rendering)&lt;br /&gt;
# Researchers need &#039;read&#039; access to these so templates and forms function.&lt;br /&gt;
$wgNamespacePermissionLockdown[NS_TEMPLATE][&#039;read&#039;] = [&#039;user&#039;, &#039;sysop&#039;];&lt;br /&gt;
$wgNamespacePermissionLockdown[NS_FORM][&#039;read&#039;]     = [&#039;user&#039;, &#039;sysop&#039;];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Page Forms &amp;amp; Cargo Interaction ==&lt;br /&gt;
The Dashboard utilizes `Template:EntityRow` for layout and queries the Cargo database. &lt;br /&gt;
* &#039;&#039;&#039;Note:&#039;&#039;&#039; If researchers can see the Dashboard but not the data results, ensure the Cargo-specific namespaces are also allowed.&lt;br /&gt;
* &#039;&#039;&#039;Editing:&#039;&#039;&#039; The `edit` permission is granted globally to the `user` group, but restricted by namespace via Lockdown.&lt;br /&gt;
&lt;br /&gt;
== 4. Default System Accounts ==&lt;br /&gt;
* &#039;&#039;&#039;MediaWiki default:&#039;&#039;&#039; Internal system user. No password; no login allowed. Safe.&lt;br /&gt;
* &#039;&#039;&#039;Admin/Sysop:&#039;&#039;&#039; Full credentials required.&lt;br /&gt;
&lt;br /&gt;
== Successor Notes ==&lt;br /&gt;
* &#039;&#039;&#039;Adding Entities:&#039;&#039;&#039; When creating a new Research Entity, ensure the associated Template and Form are placed in the permitted namespaces.&lt;br /&gt;
* &#039;&#039;&#039;Testing Access:&#039;&#039;&#039; Always test new Dashboard sections with a non-admin &amp;quot;Fellow&amp;quot; account to ensure no &amp;quot;Permission Denied&amp;quot; errors occur during template transclusion.&lt;br /&gt;
&lt;br /&gt;
{{DISPLAYTITLE:User Experience &amp;amp; Stealth Configuration}}&lt;br /&gt;
__TOC__&lt;br /&gt;
== Strategy: Forbidden by Default ==&lt;br /&gt;
To prevent &amp;quot;clutter&amp;quot; and spying, the wiki uses a **Negative Lockdown** model. Users are explicitly denied access to all default MediaWiki namespaces.&lt;br /&gt;
&lt;br /&gt;
== Configuration Implementation ==&lt;br /&gt;
=== 1. Namespace Stealth ===&lt;br /&gt;
The following namespaces are hidden from the Search bar and &#039;All Pages&#039; list for standard members to prevent them from seeing technical infrastructure:&lt;br /&gt;
* {{ns:ICT}} (ID: 3000)&lt;br /&gt;
* {{ns:Template}} (ID: 10)&lt;br /&gt;
* {{ns:Form}} (ID: 106)&lt;br /&gt;
&lt;br /&gt;
=== 2. Functional Access ===&lt;br /&gt;
Members are restricted to the following functional &amp;quot;Safe Zones&amp;quot;:&lt;br /&gt;
* &#039;&#039;&#039;Dashboard:&#039;&#039;&#039; Entry point for all research.&lt;br /&gt;
* &#039;&#039;&#039;Research:&#039;&#039;&#039; The data repository.&lt;br /&gt;
&lt;br /&gt;
=== 3. Maintenance Logic ===&lt;br /&gt;
Standard users (`group: user`) have had their global `[&#039;read&#039;]` permission revoked in [[LocalSettings.php]]. They only &amp;quot;see&amp;quot; what is explicitly whitelisted via the Lockdown extension.&lt;br /&gt;
&lt;br /&gt;
== Successor Warning ==&lt;br /&gt;
If a researcher reports a &amp;quot;Broken Template&amp;quot; error (e.g., seeing raw {{...}} code), it usually means a new Template was created in a namespace that isn&#039;t yet whitelisted for the `user` group.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:ICT Documentation]]&lt;br /&gt;
[[Category:Security Operations]]&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_-_Adding_a_New_Entity/Table&amp;diff=1626</id>
		<title>ICT:Wiki - Cargo - Adding a New Entity/Table</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Wiki_-_Cargo_-_Adding_a_New_Entity/Table&amp;diff=1626"/>
		<updated>2026-05-14T14:37:55Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:Adding a New Entity/Table to ICT:Cargo - Adding a New Entity/Table without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= How to Add a New Entity/Table =&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
Step-by-step guide for adding new data entities to the system.&lt;br /&gt;
&lt;br /&gt;
Follow this order strictly.&lt;br /&gt;
&lt;br /&gt;
Do not skip steps.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 1 – Update DBML ==&lt;br /&gt;
Add the table definition to the DBML model first.&lt;br /&gt;
&lt;br /&gt;
DBML is the source of truth.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 2 – Create template ==&lt;br /&gt;
&lt;br /&gt;
Create:&lt;br /&gt;
&lt;br /&gt;
 Template:EntityName&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{#cargo_store:&lt;br /&gt;
 _table=EntityNames&lt;br /&gt;
 |field1={{{field1|}}}&lt;br /&gt;
 |field2={{{field2|}}}&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 3 – Create Cargo table ==&lt;br /&gt;
&lt;br /&gt;
Go to:&lt;br /&gt;
&lt;br /&gt;
 Special:CargoTables&lt;br /&gt;
&lt;br /&gt;
Click:&lt;br /&gt;
&lt;br /&gt;
 Recreate data&lt;br /&gt;
&lt;br /&gt;
Verify table exists.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 4 – Create form ==&lt;br /&gt;
&lt;br /&gt;
Go to:&lt;br /&gt;
&lt;br /&gt;
 Special:CreateForm&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&lt;br /&gt;
* template&lt;br /&gt;
* fields&lt;br /&gt;
* target namespace&lt;br /&gt;
* page name formula&lt;br /&gt;
* hide title&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 5 – Test manually ==&lt;br /&gt;
&lt;br /&gt;
Create one page.&lt;br /&gt;
&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
* page in correct namespace&lt;br /&gt;
* data stored&lt;br /&gt;
* queries work&lt;br /&gt;
&lt;br /&gt;
Only then proceed.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 6 – Add queries or lists ==&lt;br /&gt;
&lt;br /&gt;
After structure works:&lt;br /&gt;
&lt;br /&gt;
* Cargo queries&lt;br /&gt;
* lists&lt;br /&gt;
* reports&lt;br /&gt;
&lt;br /&gt;
Never design UI before schema works.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Checklist ==&lt;br /&gt;
&lt;br /&gt;
Before marking complete:&lt;br /&gt;
&lt;br /&gt;
[ ] template exists  &lt;br /&gt;
[ ] cargo table created  &lt;br /&gt;
[ ] form works  &lt;br /&gt;
[ ] namespace enforced  &lt;br /&gt;
[ ] page name automatic  &lt;br /&gt;
[ ] test page saved  &lt;br /&gt;
[ ] query returns data  &lt;br /&gt;
&lt;br /&gt;
If any box unchecked → fix first.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Rule ==&lt;br /&gt;
Small working increments beat big automatic generation.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MWC/FinalConfig-Chapter&amp;diff=1625</id>
		<title>ICT:MWC/FinalConfig-Chapter</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MWC/FinalConfig-Chapter&amp;diff=1625"/>
		<updated>2026-04-13T09:01:02Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:MWC - FinalConfig-Chapter to ICT:MWC/FinalConfig-Chapter without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Final Configuration for the Chapter Entity =&lt;br /&gt;
&lt;br /&gt;
Document revision: {{#time:Y-m-d|{{REVISIONTIMESTAMP}}}} by {{REVISIONUSER}}&lt;br /&gt;
&lt;br /&gt;
The aim is to create an interface without MediaWiki clutter and well protected to avoid confusing users with unnecessary elements on the page. &lt;br /&gt;
The Cargo template follows what has been decided in the DBML and is fully aligned with the reference entities Place and Organisation.&lt;br /&gt;
&lt;br /&gt;
The Chapter entity is structurally simple:&lt;br /&gt;
- it is recursive (parent chapter)&lt;br /&gt;
- it has no foreign keys to other entities&lt;br /&gt;
&lt;br /&gt;
This entity serves as the reference for the simplest recursive pattern in the system.&lt;br /&gt;
&lt;br /&gt;
This configuration deliberately favors explicit behavior and robustness over visual polish or implicit framework behavior, in order to ensure long-term maintainability.&lt;br /&gt;
&lt;br /&gt;
= Cargo Table: =&lt;br /&gt;
Template:Chapter&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
Chapter data template&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{#cargo_declare:&lt;br /&gt;
 |_table=Chapters&lt;br /&gt;
 |Code=Page&lt;br /&gt;
 |Label=String&lt;br /&gt;
 |Parent=Page&lt;br /&gt;
 |Sequence=Integer&lt;br /&gt;
 |Description=Text&lt;br /&gt;
 |StartDate=Date&lt;br /&gt;
 |EndDate=Date&lt;br /&gt;
 |Notes=Text&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{#cargo_store:&lt;br /&gt;
 |Code={{FULLPAGENAME}}&lt;br /&gt;
 |Label={{{Label|}}}&lt;br /&gt;
 |Parent={{{Parent|}}}&lt;br /&gt;
 |Sequence={{{Sequence|}}}&lt;br /&gt;
 |Description={{{Description|}}}&lt;br /&gt;
 |StartDate={{{StartDate|}}}&lt;br /&gt;
 |EndDate={{{EndDate|}}}&lt;br /&gt;
 |Notes={{{Notes|}}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== {{{Label|}}} ==&lt;br /&gt;
{{DISPLAYTITLE:{{{Label}}}}}&lt;br /&gt;
&lt;br /&gt;
{{#if:{{{Parent|}}}|&lt;br /&gt;
&#039;&#039;&#039;Parent chapter:&#039;&#039;&#039; [[{{{Parent}}}]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
{{{Notes|}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the template is created, the Cargo table must be created manually.&lt;br /&gt;
If modifications are made to the table structure, the table must be recreated and the temporary table swapped via the Cargo administration interface.&lt;br /&gt;
&lt;br /&gt;
The field Code stores the full page name (including namespace) to ensure unambiguous identification.&lt;br /&gt;
&lt;br /&gt;
Important conventions:&lt;br /&gt;
- Field names start with a capital letter&lt;br /&gt;
- Code is the page name and acts as the technical identifier&lt;br /&gt;
- Label is the human-readable name and is mandatory for all entities&lt;br /&gt;
- Parent is stored as a Page field&lt;br /&gt;
- The field name Label must not be renamed, as it is relied upon by shared JavaScript validation logic&lt;br /&gt;
&lt;br /&gt;
Special lines at the bottom of the template:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
== {{{Label|}}} ==&lt;br /&gt;
{{DISPLAYTITLE:{{{Label}}}}}&lt;br /&gt;
&lt;br /&gt;
{{#if:{{{Parent|}}}|&lt;br /&gt;
&#039;&#039;&#039;Parent chapter:&#039;&#039;&#039; [[{{{Parent}}}]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
{{{Notes|}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These lines ensure that the human-readable name (Label) is consistently used as the visible page title, while the actual page name remains the stable technical identifier (Code).&lt;br /&gt;
&lt;br /&gt;
This decoupling allows renaming the label without breaking Cargo relations or dashboards.&lt;br /&gt;
&lt;br /&gt;
= Page Form: =&lt;br /&gt;
Form:Chapter&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
Form for creating and editing Chapter pages.&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{{info&lt;br /&gt;
|no summary&lt;br /&gt;
|no preview&lt;br /&gt;
|no minor edit&lt;br /&gt;
|no watch&lt;br /&gt;
|no footer&lt;br /&gt;
}}}&lt;br /&gt;
&#039;&#039;Fields marked with (*) are required.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{{for template|Chapter}}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;formtable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
! Code&lt;br /&gt;
| {{PAGENAME}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Name (*)&lt;br /&gt;
| {{{field|Label}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Parent chapter&lt;br /&gt;
| {{{field|Parent&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Chapter&lt;br /&gt;
 |placeholder=Top level (no parent)&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Sequence&lt;br /&gt;
| {{{field|Sequence}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Description&lt;br /&gt;
| {{{field|Description|input type=textarea}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Start date&lt;br /&gt;
| {{{field|StartDate|input type=datepicker|year range=1800:2100|show year dropdown|show month dropdown}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! End date&lt;br /&gt;
| {{{field|EndDate|input type=datepicker|year range=1800:2100|show year dropdown|show month dropdown}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Notes&lt;br /&gt;
| {{{field|Notes|input type=textarea}}}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}}&lt;br /&gt;
&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first section avoids MediaWiki edit clutter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{info&lt;br /&gt;
|no summary&lt;br /&gt;
|no preview&lt;br /&gt;
|no minor edit&lt;br /&gt;
|no watch&lt;br /&gt;
|no footer&lt;br /&gt;
}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The field Label (displayed to the user as “Name”) is mandatory for all entities.&lt;br /&gt;
This requirement is not implemented using the Page Forms |mandatory option, as this produces unusable white error boxes in the dark Vector-2022 environment.&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
- the requirement is communicated via text and (*)&lt;br /&gt;
- enforcement is handled via JavaScript at save time&lt;br /&gt;
&lt;br /&gt;
= Dashboard page =&lt;br /&gt;
Dashboard:Chapter&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
= 📘 Costa Sano Research CHAPTER Dashboard =&lt;br /&gt;
&lt;br /&gt;
📖 [[Dashboard:Chapter/Help|Need Help?]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Code !! Name !! Parent&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
 tables=Chapters&lt;br /&gt;
 |fields=_pageName,_pageTitle,Label,Parent&lt;br /&gt;
 |where=_pageNamespace=3004&lt;br /&gt;
 |order by=_pageTitle&lt;br /&gt;
 |format=template&lt;br /&gt;
 |template=ChapterRow&lt;br /&gt;
 |named args=yes&lt;br /&gt;
 |cache=no&lt;br /&gt;
}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Choose your chapter code corresponding to above table and respecting the naming conventions.&lt;br /&gt;
&lt;br /&gt;
{{#forminput:&lt;br /&gt;
 form=Chapter&lt;br /&gt;
 |namespace=Chapter&lt;br /&gt;
 |button text=➕ New chapter&lt;br /&gt;
 |returnto=Dashboard:Chapter&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:right; font-size:90%;&amp;quot;&amp;gt;&lt;br /&gt;
Last updated: {{CURRENTDAY}} {{CURRENTMONTHNAME}} {{CURRENTYEAR}} – {{CURRENTTIME}} UTC&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
IMPORTANT:&lt;br /&gt;
Dashboard tables are positional.&lt;br /&gt;
The number and order of:&lt;br /&gt;
- table headers&lt;br /&gt;
- Cargo query fields&lt;br /&gt;
- row template cells&lt;br /&gt;
MUST match exactly.&lt;br /&gt;
&lt;br /&gt;
Only the first column (Code) is clickable and leads to the edit form.&lt;br /&gt;
All other columns are displayed as plain text to prevent navigation to record pages.&lt;br /&gt;
&lt;br /&gt;
= Row transclusion Template =&lt;br /&gt;
Template:ChapterRow&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;includeonly&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| {{#formlink:&lt;br /&gt;
   form=Chapter&lt;br /&gt;
   |target={{{_pageName}}}&lt;br /&gt;
   |link text={{{_pageTitle}}}&lt;br /&gt;
   |returnto=Dashboard:Chapter&lt;br /&gt;
 }}&lt;br /&gt;
| {{{Label}}}&lt;br /&gt;
| {{#if:{{{Parent|}}}|{{#titleparts:{{{Parent}}}|1}}|—}}&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parent values are displayed as plain text (not links) to prevent users from navigating directly to record pages. All record editing is performed via forms accessed from the dashboard.&lt;br /&gt;
&lt;br /&gt;
= Javascript =&lt;br /&gt;
&lt;br /&gt;
The Chapter entity reuses the same shared JavaScript infrastructure as Place and Organisation:&lt;br /&gt;
- dashboard auto-purge&lt;br /&gt;
- save-time mandatory field enforcement (Label)&lt;br /&gt;
- no Page Forms |mandatory usage&lt;br /&gt;
&lt;br /&gt;
No Chapter-specific JavaScript is required.&lt;br /&gt;
&lt;br /&gt;
All Chapter pages are stored in the Chapter namespace with the page name acting as the Code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Chapter&lt;br /&gt;
|Label=In the beginning&lt;br /&gt;
|Description=Chapter describing what happened before Berck-sur-Mer...&lt;br /&gt;
|StartDate=1800-01&lt;br /&gt;
|EndDate=1849-12&lt;br /&gt;
|Notes=NIHIL&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such pages are configuration pages and must be accessed via the dashboard, not directly.&lt;br /&gt;
&lt;br /&gt;
== References: ==&lt;br /&gt;
&lt;br /&gt;
* [[mediawikiwiki:Extension:Cargo/Storing_data|Cargo table explanation]]&lt;br /&gt;
* [[mediawikiwiki:Extension:Page_Forms|Page Forms explained]]&lt;br /&gt;
&lt;br /&gt;
[[Category:FinalConfig]]&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MWC&amp;diff=1624</id>
		<title>ICT:MWC</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MWC&amp;diff=1624"/>
		<updated>2026-04-13T09:00:32Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;= Section for MediaWiki Cargo application =  This application got stuck on the automatic numbering of the assests.  Her the interesting pages about this application are collected.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Section for MediaWiki Cargo application =&lt;br /&gt;
&lt;br /&gt;
This application got stuck on the automatic numbering of the assests.&lt;br /&gt;
&lt;br /&gt;
Her the interesting pages about this application are collected.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MWC/FinalConfig-Chapter&amp;diff=1623</id>
		<title>ICT:MWC/FinalConfig-Chapter</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MWC/FinalConfig-Chapter&amp;diff=1623"/>
		<updated>2026-04-13T08:43:33Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:FinalConfig-Chapter to ICT:MWC - FinalConfig-Chapter without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Final Configuration for the Chapter Entity =&lt;br /&gt;
&lt;br /&gt;
Document revision: {{#time:Y-m-d|{{REVISIONTIMESTAMP}}}} by {{REVISIONUSER}}&lt;br /&gt;
&lt;br /&gt;
The aim is to create an interface without MediaWiki clutter and well protected to avoid confusing users with unnecessary elements on the page. &lt;br /&gt;
The Cargo template follows what has been decided in the DBML and is fully aligned with the reference entities Place and Organisation.&lt;br /&gt;
&lt;br /&gt;
The Chapter entity is structurally simple:&lt;br /&gt;
- it is recursive (parent chapter)&lt;br /&gt;
- it has no foreign keys to other entities&lt;br /&gt;
&lt;br /&gt;
This entity serves as the reference for the simplest recursive pattern in the system.&lt;br /&gt;
&lt;br /&gt;
This configuration deliberately favors explicit behavior and robustness over visual polish or implicit framework behavior, in order to ensure long-term maintainability.&lt;br /&gt;
&lt;br /&gt;
= Cargo Table: =&lt;br /&gt;
Template:Chapter&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
Chapter data template&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{#cargo_declare:&lt;br /&gt;
 |_table=Chapters&lt;br /&gt;
 |Code=Page&lt;br /&gt;
 |Label=String&lt;br /&gt;
 |Parent=Page&lt;br /&gt;
 |Sequence=Integer&lt;br /&gt;
 |Description=Text&lt;br /&gt;
 |StartDate=Date&lt;br /&gt;
 |EndDate=Date&lt;br /&gt;
 |Notes=Text&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{#cargo_store:&lt;br /&gt;
 |Code={{FULLPAGENAME}}&lt;br /&gt;
 |Label={{{Label|}}}&lt;br /&gt;
 |Parent={{{Parent|}}}&lt;br /&gt;
 |Sequence={{{Sequence|}}}&lt;br /&gt;
 |Description={{{Description|}}}&lt;br /&gt;
 |StartDate={{{StartDate|}}}&lt;br /&gt;
 |EndDate={{{EndDate|}}}&lt;br /&gt;
 |Notes={{{Notes|}}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== {{{Label|}}} ==&lt;br /&gt;
{{DISPLAYTITLE:{{{Label}}}}}&lt;br /&gt;
&lt;br /&gt;
{{#if:{{{Parent|}}}|&lt;br /&gt;
&#039;&#039;&#039;Parent chapter:&#039;&#039;&#039; [[{{{Parent}}}]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
{{{Notes|}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the template is created, the Cargo table must be created manually.&lt;br /&gt;
If modifications are made to the table structure, the table must be recreated and the temporary table swapped via the Cargo administration interface.&lt;br /&gt;
&lt;br /&gt;
The field Code stores the full page name (including namespace) to ensure unambiguous identification.&lt;br /&gt;
&lt;br /&gt;
Important conventions:&lt;br /&gt;
- Field names start with a capital letter&lt;br /&gt;
- Code is the page name and acts as the technical identifier&lt;br /&gt;
- Label is the human-readable name and is mandatory for all entities&lt;br /&gt;
- Parent is stored as a Page field&lt;br /&gt;
- The field name Label must not be renamed, as it is relied upon by shared JavaScript validation logic&lt;br /&gt;
&lt;br /&gt;
Special lines at the bottom of the template:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
== {{{Label|}}} ==&lt;br /&gt;
{{DISPLAYTITLE:{{{Label}}}}}&lt;br /&gt;
&lt;br /&gt;
{{#if:{{{Parent|}}}|&lt;br /&gt;
&#039;&#039;&#039;Parent chapter:&#039;&#039;&#039; [[{{{Parent}}}]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
{{{Notes|}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These lines ensure that the human-readable name (Label) is consistently used as the visible page title, while the actual page name remains the stable technical identifier (Code).&lt;br /&gt;
&lt;br /&gt;
This decoupling allows renaming the label without breaking Cargo relations or dashboards.&lt;br /&gt;
&lt;br /&gt;
= Page Form: =&lt;br /&gt;
Form:Chapter&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
Form for creating and editing Chapter pages.&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{{info&lt;br /&gt;
|no summary&lt;br /&gt;
|no preview&lt;br /&gt;
|no minor edit&lt;br /&gt;
|no watch&lt;br /&gt;
|no footer&lt;br /&gt;
}}}&lt;br /&gt;
&#039;&#039;Fields marked with (*) are required.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{{for template|Chapter}}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;formtable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
! Code&lt;br /&gt;
| {{PAGENAME}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Name (*)&lt;br /&gt;
| {{{field|Label}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Parent chapter&lt;br /&gt;
| {{{field|Parent&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Chapter&lt;br /&gt;
 |placeholder=Top level (no parent)&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Sequence&lt;br /&gt;
| {{{field|Sequence}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Description&lt;br /&gt;
| {{{field|Description|input type=textarea}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Start date&lt;br /&gt;
| {{{field|StartDate|input type=datepicker|year range=1800:2100|show year dropdown|show month dropdown}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! End date&lt;br /&gt;
| {{{field|EndDate|input type=datepicker|year range=1800:2100|show year dropdown|show month dropdown}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Notes&lt;br /&gt;
| {{{field|Notes|input type=textarea}}}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}}&lt;br /&gt;
&lt;br /&gt;
{{{end template}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first section avoids MediaWiki edit clutter.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{info&lt;br /&gt;
|no summary&lt;br /&gt;
|no preview&lt;br /&gt;
|no minor edit&lt;br /&gt;
|no watch&lt;br /&gt;
|no footer&lt;br /&gt;
}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The field Label (displayed to the user as “Name”) is mandatory for all entities.&lt;br /&gt;
This requirement is not implemented using the Page Forms |mandatory option, as this produces unusable white error boxes in the dark Vector-2022 environment.&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
- the requirement is communicated via text and (*)&lt;br /&gt;
- enforcement is handled via JavaScript at save time&lt;br /&gt;
&lt;br /&gt;
= Dashboard page =&lt;br /&gt;
Dashboard:Chapter&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
= 📘 Costa Sano Research CHAPTER Dashboard =&lt;br /&gt;
&lt;br /&gt;
📖 [[Dashboard:Chapter/Help|Need Help?]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Code !! Name !! Parent&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
 tables=Chapters&lt;br /&gt;
 |fields=_pageName,_pageTitle,Label,Parent&lt;br /&gt;
 |where=_pageNamespace=3004&lt;br /&gt;
 |order by=_pageTitle&lt;br /&gt;
 |format=template&lt;br /&gt;
 |template=ChapterRow&lt;br /&gt;
 |named args=yes&lt;br /&gt;
 |cache=no&lt;br /&gt;
}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Choose your chapter code corresponding to above table and respecting the naming conventions.&lt;br /&gt;
&lt;br /&gt;
{{#forminput:&lt;br /&gt;
 form=Chapter&lt;br /&gt;
 |namespace=Chapter&lt;br /&gt;
 |button text=➕ New chapter&lt;br /&gt;
 |returnto=Dashboard:Chapter&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:right; font-size:90%;&amp;quot;&amp;gt;&lt;br /&gt;
Last updated: {{CURRENTDAY}} {{CURRENTMONTHNAME}} {{CURRENTYEAR}} – {{CURRENTTIME}} UTC&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
IMPORTANT:&lt;br /&gt;
Dashboard tables are positional.&lt;br /&gt;
The number and order of:&lt;br /&gt;
- table headers&lt;br /&gt;
- Cargo query fields&lt;br /&gt;
- row template cells&lt;br /&gt;
MUST match exactly.&lt;br /&gt;
&lt;br /&gt;
Only the first column (Code) is clickable and leads to the edit form.&lt;br /&gt;
All other columns are displayed as plain text to prevent navigation to record pages.&lt;br /&gt;
&lt;br /&gt;
= Row transclusion Template =&lt;br /&gt;
Template:ChapterRow&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;includeonly&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| {{#formlink:&lt;br /&gt;
   form=Chapter&lt;br /&gt;
   |target={{{_pageName}}}&lt;br /&gt;
   |link text={{{_pageTitle}}}&lt;br /&gt;
   |returnto=Dashboard:Chapter&lt;br /&gt;
 }}&lt;br /&gt;
| {{{Label}}}&lt;br /&gt;
| {{#if:{{{Parent|}}}|{{#titleparts:{{{Parent}}}|1}}|—}}&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parent values are displayed as plain text (not links) to prevent users from navigating directly to record pages. All record editing is performed via forms accessed from the dashboard.&lt;br /&gt;
&lt;br /&gt;
= Javascript =&lt;br /&gt;
&lt;br /&gt;
The Chapter entity reuses the same shared JavaScript infrastructure as Place and Organisation:&lt;br /&gt;
- dashboard auto-purge&lt;br /&gt;
- save-time mandatory field enforcement (Label)&lt;br /&gt;
- no Page Forms |mandatory usage&lt;br /&gt;
&lt;br /&gt;
No Chapter-specific JavaScript is required.&lt;br /&gt;
&lt;br /&gt;
All Chapter pages are stored in the Chapter namespace with the page name acting as the Code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Chapter&lt;br /&gt;
|Label=In the beginning&lt;br /&gt;
|Description=Chapter describing what happened before Berck-sur-Mer...&lt;br /&gt;
|StartDate=1800-01&lt;br /&gt;
|EndDate=1849-12&lt;br /&gt;
|Notes=NIHIL&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such pages are configuration pages and must be accessed via the dashboard, not directly.&lt;br /&gt;
&lt;br /&gt;
== References: ==&lt;br /&gt;
&lt;br /&gt;
* [[mediawikiwiki:Extension:Cargo/Storing_data|Cargo table explanation]]&lt;br /&gt;
* [[mediawikiwiki:Extension:Page_Forms|Page Forms explained]]&lt;br /&gt;
&lt;br /&gt;
[[Category:FinalConfig]]&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=IC:MW_Talk_Namespaces&amp;diff=1621</id>
		<title>IC:MW Talk Namespaces</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=IC:MW_Talk_Namespaces&amp;diff=1621"/>
		<updated>2026-04-06T11:53:32Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;= Custom Talk Namespaces in MediaWiki = This document explains the purpose of Talk namespaces in MediaWiki, how custom Talk namespaces are defined, and why they only appear in the namespace list after specific configuration steps.  == 1. Purpose of Talk Namespaces == MediaWiki separates *content* from *discussion* using paired namespaces:  * Even-numbered namespace → content (e.g. &amp;lt;code&amp;gt;Network&amp;lt;/code&amp;gt;) * Odd-numbered namespace → talk/discussion (e.g. &amp;lt;code&amp;gt;Network_Ta...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Custom Talk Namespaces in MediaWiki =&lt;br /&gt;
This document explains the purpose of Talk namespaces in MediaWiki, how custom Talk namespaces are defined, and why they only appear in the namespace list after specific configuration steps.&lt;br /&gt;
&lt;br /&gt;
== 1. Purpose of Talk Namespaces ==&lt;br /&gt;
MediaWiki separates *content* from *discussion* using paired namespaces:&lt;br /&gt;
&lt;br /&gt;
* Even-numbered namespace → content (e.g. &amp;lt;code&amp;gt;Network&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Odd-numbered namespace → talk/discussion (e.g. &amp;lt;code&amp;gt;Network_Talk&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Talk namespaces serve several purposes:&lt;br /&gt;
* Keep content pages clean and factual.&lt;br /&gt;
* Provide a dedicated space for questions, decisions, and editorial notes.&lt;br /&gt;
* Preserve decision history for future maintainers.&lt;br /&gt;
* Support structured workflows (templates, categories, archiving).&lt;br /&gt;
* Allow experimentation and discussion without altering the main content.&lt;br /&gt;
&lt;br /&gt;
Every content namespace should have a corresponding Talk namespace for long-term maintainability.&lt;br /&gt;
&lt;br /&gt;
== 2. Why MediaWiki Does Not Auto‑Create Talk Namespaces ==&lt;br /&gt;
MediaWiki automatically creates Talk namespaces only for its built‑in namespaces (Main, File, Help, etc.).&lt;br /&gt;
&lt;br /&gt;
For custom namespaces, MediaWiki does *not* assume a Talk namespace exists.  &lt;br /&gt;
It will only register a Talk namespace when:&lt;br /&gt;
&lt;br /&gt;
# A numeric ID is defined.&lt;br /&gt;
# A name is assigned in &amp;lt;code&amp;gt;$wgExtraNamespaces&amp;lt;/code&amp;gt;.&lt;br /&gt;
# The ID is an odd number paired with the content namespace.&lt;br /&gt;
&lt;br /&gt;
Until these conditions are met, the Talk namespace will not appear in:&lt;br /&gt;
* Special:SpecialPages → “Namespaces”&lt;br /&gt;
* Special:AllPages namespace dropdown&lt;br /&gt;
* API namespace lists&lt;br /&gt;
&lt;br /&gt;
== 3. Defining a Custom Namespace Pair ==&lt;br /&gt;
A correct custom namespace definition looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# --- Custom namespace: Network ---&lt;br /&gt;
define(&amp;quot;NS_NETWORK&amp;quot;, 3000);&lt;br /&gt;
define(&amp;quot;NS_NETWORK_TALK&amp;quot;, 3001);&lt;br /&gt;
&lt;br /&gt;
$wgExtraNamespaces[NS_NETWORK] = &amp;quot;Network&amp;quot;;&lt;br /&gt;
$wgExtraNamespaces[NS_NETWORK_TALK] = &amp;quot;Network_Talk&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Optional: namespace shortcuts&lt;br /&gt;
$wgNamespaceAliases[&#039;N&#039;] = NS_NETWORK;&lt;br /&gt;
$wgNamespaceAliases[&#039;N_Talk&#039;] = NS_NETWORK_TALK;&lt;br /&gt;
&lt;br /&gt;
# Optional: enable subpages&lt;br /&gt;
$wgNamespaceWithSubpage[NS_NETWORK] = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Required elements ===&lt;br /&gt;
* &amp;lt;code&amp;gt;define(&amp;quot;NS_NETWORK&amp;quot;, 3000);&amp;lt;/code&amp;gt;  &lt;br /&gt;
* &amp;lt;code&amp;gt;define(&amp;quot;NS_NETWORK_TALK&amp;quot;, 3001);&amp;lt;/code&amp;gt;  &lt;br /&gt;
* &amp;lt;code&amp;gt;$wgExtraNamespaces[...]&amp;lt;/code&amp;gt; entries for both&lt;br /&gt;
&lt;br /&gt;
=== Optional but recommended ===&lt;br /&gt;
* namespace aliases  &lt;br /&gt;
* subpage support  &lt;br /&gt;
&lt;br /&gt;
== 4. Why the Talk Namespace Appears Only After Full Definition ==&lt;br /&gt;
MediaWiki registers namespaces early during startup.  &lt;br /&gt;
A Talk namespace will only appear when:&lt;br /&gt;
&lt;br /&gt;
* Both the content and talk IDs are defined.&lt;br /&gt;
* Both names are assigned in &amp;lt;code&amp;gt;$wgExtraNamespaces&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The definitions are placed early enough in &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the Talk namespace is defined later in the file, or after extensions that query namespaces, it may not appear until the next reload.&lt;br /&gt;
&lt;br /&gt;
=== Rule of thumb ===&lt;br /&gt;
Place all custom namespace definitions **at the top of LocalSettings.php**, before loading extensions.&lt;br /&gt;
&lt;br /&gt;
== 5. Namespace ID Pairing (Even/Odd Rule) ==&lt;br /&gt;
MediaWiki uses numeric pairing to link content and talk namespaces:&lt;br /&gt;
&lt;br /&gt;
* Even ID → content namespace  &lt;br /&gt;
* Odd ID → talk namespace  &lt;br /&gt;
* The talk namespace must immediately follow the content namespace&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
* &amp;lt;code&amp;gt;3000 → Network&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;3001 → Network_Talk&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the pairing is broken, MediaWiki will not recognize the Talk namespace correctly.&lt;br /&gt;
&lt;br /&gt;
== 6. Summary ==&lt;br /&gt;
* Talk namespaces store discussion, decisions, and editorial notes separate from content.&lt;br /&gt;
* MediaWiki does not auto-create Talk namespaces for custom namespaces.&lt;br /&gt;
* A Talk namespace appears only after proper definition (ID + name + pairing).&lt;br /&gt;
* Namespace definitions must be placed early in &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Even/odd numeric pairing is essential for correct behavior.&lt;br /&gt;
&lt;br /&gt;
This structure ensures clean content pages, clear editorial history, and a successor‑friendly wiki architecture.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1620</id>
		<title>ICT:MW Installation procedure 1.43 LTS -v2</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1620"/>
		<updated>2026-04-04T16:11:05Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Procedure for a New MediaWiki Instance (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible workflow for deploying a new MediaWiki instance on the existing 3‑VM infrastructure.&lt;br /&gt;
&lt;br /&gt;
The installation is intentionally split into two phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and testing on VM1 (Apache on port 8080)&lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 (nginx reverse‑proxy + HTTPS)&lt;br /&gt;
&lt;br /&gt;
This staged approach ensures safe testing before the wiki becomes accessible from the internet.&lt;br /&gt;
&lt;br /&gt;
== VM Overview ==&lt;br /&gt;
* &#039;&#039;&#039;VM1 (Web Layer):&#039;&#039;&#039; 192.168.33.231  &lt;br /&gt;
* &#039;&#039;&#039;VM2 (Database Layer):&#039;&#039;&#039; 192.168.33.232  &lt;br /&gt;
* &#039;&#039;&#039;VM3 (Reverse‑Proxy Layer):&#039;&#039;&#039; 192.168.33.233  &lt;br /&gt;
* &#039;&#039;&#039;DB user host address (VM1 → VM2):&#039;&#039;&#039; 10.10.10.1  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 1. Create the Database (VM2 – MariaDB) =&lt;br /&gt;
All commands in this section run on VM2 (192.168.33.232).&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
VM1 connects to MariaDB using its internal DB‑facing address: &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;10.10.10.1&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;10.10.10.1&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 2. Prepare the Installation Directory (VM1 – Web Layer) =&lt;br /&gt;
All commands below run on VM1 (192.168.33.231).&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into /var/www ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 3. Download MediaWiki =&lt;br /&gt;
Example: MediaWiki 1.43.8 LTS.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 4. Extract MediaWiki =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 5. Move Extracted Files into newMW =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 6. Ownership and Permissions =&lt;br /&gt;
Allows editing via VS Code while keeping Apache functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Directory/file permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 7. Apache Configuration on VM1 (Port 8080) =&lt;br /&gt;
&lt;br /&gt;
== 7.1 Enable Apache to listen on port 8080 ==&lt;br /&gt;
Edit:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/httpd/conf/httpd.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.2 Validate and restart ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apachectl configtest&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.3 Verify Apache is listening ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ss -tlnp | grep httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.0.0.0:80&lt;br /&gt;
0.0.0.0:8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.4 Firewall rule (VM1) ==&lt;br /&gt;
Allow port 8080:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
firewall-cmd --add-port=8080/tcp --permanent&lt;br /&gt;
firewall-cmd --reload&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.5 Local‑only Apache VirtualHost ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newmw.local&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newmw-local-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newmw-local-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 8. Run the Installer Locally =&lt;br /&gt;
Access:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;http://192.168.33.231:8080&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;http://newmw.local:8080&amp;lt;/code&amp;gt; (if added to /etc/hosts)&lt;br /&gt;
&lt;br /&gt;
== Internal DB Network Logic (10.10.10.x) ==&lt;br /&gt;
The internal network between VM1 and VM2 uses dedicated addresses:&lt;br /&gt;
&lt;br /&gt;
* VM1 (Web Layer): &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;&lt;br /&gt;
* VM2 (Database Layer): &#039;&#039;&#039;10.10.10.2&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When MediaWiki (running on VM1) connects to MariaDB on VM2, the connection originates from VM1’s internal NIC.  &lt;br /&gt;
Therefore:&lt;br /&gt;
&lt;br /&gt;
* VM1 connects **to** MariaDB at:  &lt;br /&gt;
  &amp;lt;code&amp;gt;10.10.10.2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VM2 sees VM1 **coming from**:  &lt;br /&gt;
  &amp;lt;code&amp;gt;10.10.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because MariaDB authorizes users based on the client’s source address, database users must be created as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&#039;wikiuser&#039;@&#039;10.10.10.1&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is why all MediaWiki instances on VM1 use the same host restriction.  &lt;br /&gt;
It ensures that only VM1 can authenticate to MariaDB over the internal network.&lt;br /&gt;
&lt;br /&gt;
== Result after installation flow ==&lt;br /&gt;
&lt;br /&gt;
Installer will generate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;http://192.168.33.231:8080&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Place &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 9. Local Testing =&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
* Page creation  &lt;br /&gt;
* Editing  &lt;br /&gt;
* File uploads  &lt;br /&gt;
* User accounts  &lt;br /&gt;
* Extensions  &lt;br /&gt;
* Permissions  &lt;br /&gt;
* Logging  &lt;br /&gt;
&lt;br /&gt;
Only proceed when everything works locally.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 10. Public Exposure via VM3 (Reverse‑Proxy Layer) =&lt;br /&gt;
&lt;br /&gt;
== 10.1 Create minimal HTTP‑only nginx config (VM3) ==&lt;br /&gt;
File:&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/nginx/conf.d/kb.costasano.club.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTP only)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto http;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 11. Issue the Certificate (VM3) =&lt;br /&gt;
Use the nginx plugin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo certbot --nginx -d kb.costasano.club&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certbot will:&lt;br /&gt;
&lt;br /&gt;
* inject temporary ACME config  &lt;br /&gt;
* validate the domain  &lt;br /&gt;
* obtain the certificate  &lt;br /&gt;
* install it  &lt;br /&gt;
* register it for renewal  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 12. Replace with Full HTTPS Reverse‑Proxy (VM3) =&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTPS)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
# --- HTTP (redirect + ACME) ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 301 https://$host$request_uri;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# --- HTTPS ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 443 ssl;&lt;br /&gt;
    listen [::]:443 ssl;&lt;br /&gt;
    http2 on;&lt;br /&gt;
&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    ssl_certificate     /etc/letsencrypt/live/kb.costasano.club/fullchain.pem;&lt;br /&gt;
    ssl_certificate_key /etc/letsencrypt/live/kb.costasano.club/privkey.pem;&lt;br /&gt;
&lt;br /&gt;
    ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
    ssl_prefer_server_ciphers on;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
&lt;br /&gt;
        proxy_buffering on;&lt;br /&gt;
        proxy_buffers 16 16k;&lt;br /&gt;
        proxy_buffer_size 16k;&lt;br /&gt;
&lt;br /&gt;
        proxy_connect_timeout 60s;&lt;br /&gt;
        proxy_send_timeout 60s;&lt;br /&gt;
        proxy_read_timeout 60s;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 13. Update LocalSettings.php for Public Access =&lt;br /&gt;
Change:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optional:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgCanonicalServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 14. Final Verification =&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -I https://kb.costasano.club&amp;lt;/code&amp;gt; returns 200 or 301  &lt;br /&gt;
* Browser loads the wiki  &lt;br /&gt;
* Editing works  &lt;br /&gt;
* Uploads work  &lt;br /&gt;
* No rewrite errors  &lt;br /&gt;
* nginx proxies correctly  &lt;br /&gt;
* MariaDB connections succeed  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 15. Login Issues After Changing LocalSettings.php =&lt;br /&gt;
MediaWiki is very sensitive to stale cookies and cached sessions, especially&lt;br /&gt;
after changing settings such as:&lt;br /&gt;
&lt;br /&gt;
* $wgServer&lt;br /&gt;
* $wgCookieSecure&lt;br /&gt;
* $wgCookieSameSite&lt;br /&gt;
* $wgUseReverseProxy&lt;br /&gt;
* $wgUseCdn&lt;br /&gt;
&lt;br /&gt;
If login suddenly fails or a Captcha appears even though no Captcha extension&lt;br /&gt;
is enabled, the cause is usually old browser cookies.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fix:&#039;&#039;&#039; open the wiki in a private/incognito window or clear cookies for the&lt;br /&gt;
domain. This forces MediaWiki to create a fresh session and resolves the issue.&lt;br /&gt;
&lt;br /&gt;
=== Differences Between MediaWiki 1.43 and 1.45 (Login, Captcha, Reverse‑Proxy) ===&lt;br /&gt;
MediaWiki 1.43 and 1.45 behave differently when installed behind a reverse‑proxy&lt;br /&gt;
such as nginx. This affects login, session cookies, and the appearance of the&lt;br /&gt;
“phantom Captcha” (a throttle challenge that cannot be solved).&lt;br /&gt;
&lt;br /&gt;
==== MediaWiki 1.45 (more tolerant) ====&lt;br /&gt;
MediaWiki 1.45 includes improved session and cookie handling. It automatically:&lt;br /&gt;
&lt;br /&gt;
* detects HTTPS behind a reverse‑proxy&lt;br /&gt;
* regenerates session cookies when needed&lt;br /&gt;
* accepts SameSite=None cookies more reliably&lt;br /&gt;
* avoids triggering login throttling on fresh installs&lt;br /&gt;
&lt;br /&gt;
As a result, MediaWiki 1.45 usually works immediately behind nginx without&lt;br /&gt;
showing any Captcha or blocking logins.&lt;br /&gt;
&lt;br /&gt;
==== MediaWiki 1.43 (stricter behaviour) ====&lt;br /&gt;
MediaWiki 1.43 uses older, stricter session logic. If any of the following are&lt;br /&gt;
misconfigured:&lt;br /&gt;
&lt;br /&gt;
* $wgServer&lt;br /&gt;
* $wgCookieSecure&lt;br /&gt;
* $wgCookieSameSite&lt;br /&gt;
* $wgUseReverseProxy&lt;br /&gt;
* $wgUseCdn&lt;br /&gt;
* missing $wgCdnServers entry&lt;br /&gt;
&lt;br /&gt;
…MediaWiki may fail to create a valid login session. When this happens, it&lt;br /&gt;
displays a Captcha-like box even though no Captcha extension is enabled. This is&lt;br /&gt;
not a real Captcha but the built‑in login throttle, and it always fails.&lt;br /&gt;
&lt;br /&gt;
==== Why this did not happen on the previous install ====&lt;br /&gt;
The earlier wiki was installed on MediaWiki 1.45, which is more forgiving of&lt;br /&gt;
reverse‑proxy setups. MediaWiki 1.43 requires explicit configuration to trust&lt;br /&gt;
the proxy and accept secure cookies.&lt;br /&gt;
&lt;br /&gt;
==== Fix ====&lt;br /&gt;
Add the following lines to LocalSettings.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgUseCdn = true;&lt;br /&gt;
$wgUseReverseProxy = true;&lt;br /&gt;
$wgCdnServers = [ &amp;quot;192.168.33.233&amp;quot; ];  # nginx reverse-proxy&lt;br /&gt;
$wgCookieSecure = true;&lt;br /&gt;
$wgCookieSameSite = &amp;quot;None&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If login still fails, clear browser cookies or open the wiki in a private window&lt;br /&gt;
to force a fresh session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= 16. Summary =&lt;br /&gt;
This procedure installs MediaWiki in two safe phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and validation on VM1  &lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 with HTTPS  &lt;br /&gt;
&lt;br /&gt;
This ensures a clean, reproducible, low‑risk deployment workflow.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Apache fails to start after adding a new Listen port (SELinux) ==&lt;br /&gt;
&lt;br /&gt;
When adding a new Apache &amp;lt;code&amp;gt;Listen&amp;lt;/code&amp;gt; directive on AlmaLinux (e.g. &amp;lt;code&amp;gt;Listen 8081&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Listen 8888&amp;lt;/code&amp;gt;), &lt;br /&gt;
&amp;lt;code&amp;gt;httpd&amp;lt;/code&amp;gt; may refuse to start even though &amp;lt;code&amp;gt;apachectl configtest&amp;lt;/code&amp;gt; reports &amp;lt;code&amp;gt;Syntax OK&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Typical symptoms:&lt;br /&gt;
* &amp;lt;code&amp;gt;httpd&amp;lt;/code&amp;gt; does not restart after adding a new port&lt;br /&gt;
* &amp;lt;code&amp;gt;configtest&amp;lt;/code&amp;gt; shows no errors&lt;br /&gt;
* &amp;lt;code&amp;gt;journalctl -xe&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;/var/log/audit/audit.log&amp;lt;/code&amp;gt; contains an AVC denial similar to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
type=AVC msg=audit(...): avc:  denied  { name_bind } for  pid=XXXX comm=&amp;quot;httpd&amp;quot; \&lt;br /&gt;
scontext=system_u:system_r:httpd_t:s0 \&lt;br /&gt;
tcontext=system_u:object_r:unreserved_port_t:s0 \&lt;br /&gt;
tclass=tcp_socket permissive=0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cause ===&lt;br /&gt;
SELinux only allows Apache (&amp;lt;code&amp;gt;httpd_t&amp;lt;/code&amp;gt;) to bind to ports labeled as &amp;lt;code&amp;gt;http_port_t&amp;lt;/code&amp;gt;.  &lt;br /&gt;
By default, this includes ports such as 80, 443, 8008, 8009, 8443, and sometimes 8080.&lt;br /&gt;
&lt;br /&gt;
Any new port (e.g. 8081, 8888) is labeled as &amp;lt;code&amp;gt;unreserved_port_t&amp;lt;/code&amp;gt; and is therefore blocked by SELinux.  &lt;br /&gt;
Apache reports this as a binding failure, often misleadingly shown as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
No such device or address&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Check which ports Apache is allowed to use ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
semanage port -l | grep http_port_t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fix: allow Apache to bind to the new port ===&lt;br /&gt;
Add the port to the SELinux &amp;lt;code&amp;gt;http_port_t&amp;lt;/code&amp;gt; type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo semanage port -a -t http_port_t -p tcp 8081&lt;br /&gt;
sudo semanage port -a -t http_port_t -p tcp 8888&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the port already exists under a different SELinux type, modify it instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo semanage port -m -t http_port_t -p tcp 8081&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Restart Apache ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apache will now start normally and bind to the newly added port.&lt;br /&gt;
&lt;br /&gt;
=== Notes for maintainers ===&lt;br /&gt;
* This behaviour is normal on RHEL/AlmaLinux systems with SELinux in enforcing mode.&lt;br /&gt;
* Always document newly opened ports in the infrastructure notes to avoid confusion for successors.&lt;br /&gt;
* Avoid disabling SELinux; adjusting port labels is the correct and safe approach.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_upgrade_1.43.8_to_1.46_LTS&amp;diff=1619</id>
		<title>ICT:MW upgrade 1.43.8 to 1.46 LTS</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_upgrade_1.43.8_to_1.46_LTS&amp;diff=1619"/>
		<updated>2026-04-04T13:59:08Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;= MediaWiki Upgrade Procedure — 1.43.8 → 1.46 LTS = &amp;#039;&amp;#039;&amp;#039;Document version:&amp;#039;&amp;#039;&amp;#039; 2025‑04‑04   &amp;#039;&amp;#039;&amp;#039;Author:&amp;#039;&amp;#039;&amp;#039; Martin   &amp;#039;&amp;#039;&amp;#039;Purpose:&amp;#039;&amp;#039;&amp;#039; Clean, reproducible, successor‑friendly upgrade to MediaWiki 1.46 LTS using a parallel installation in &amp;lt;code&amp;gt;/var/www/mw146&amp;lt;/code&amp;gt; and a reverse‑proxy switch.  This procedure ensures: * Zero downtime   * Instant rollback   * No leftover files from old versions   * Clean, maintainable, successor‑friendly architecture    The upgrade i...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= MediaWiki Upgrade Procedure — 1.43.8 → 1.46 LTS =&lt;br /&gt;
&#039;&#039;&#039;Document version:&#039;&#039;&#039; 2025‑04‑04  &lt;br /&gt;
&#039;&#039;&#039;Author:&#039;&#039;&#039; Martin  &lt;br /&gt;
&#039;&#039;&#039;Purpose:&#039;&#039;&#039; Clean, reproducible, successor‑friendly upgrade to MediaWiki 1.46 LTS using a parallel installation in &amp;lt;code&amp;gt;/var/www/mw146&amp;lt;/code&amp;gt; and a reverse‑proxy switch.&lt;br /&gt;
&lt;br /&gt;
This procedure ensures:&lt;br /&gt;
* Zero downtime  &lt;br /&gt;
* Instant rollback  &lt;br /&gt;
* No leftover files from old versions  &lt;br /&gt;
* Clean, maintainable, successor‑friendly architecture  &lt;br /&gt;
&lt;br /&gt;
The upgrade is executed on the &#039;&#039;&#039;web VM&#039;&#039;&#039; with a final switch on the &#039;&#039;&#039;reverse‑proxy VM&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Preconditions ==&lt;br /&gt;
* Working MediaWiki &#039;&#039;&#039;1.43.8 LTS&#039;&#039;&#039; installation  &lt;br /&gt;
* Database VM reachable and healthy  &lt;br /&gt;
* PHP &#039;&#039;&#039;8.1 or 8.2&#039;&#039;&#039;  &lt;br /&gt;
* Reverse proxy currently pointing to &amp;lt;code&amp;gt;/var/www/mw143&amp;lt;/code&amp;gt;  &lt;br /&gt;
* VM snapshot taken before starting  &lt;br /&gt;
* SSH access to web VM and reverse‑proxy VM  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 1: Prepare new directory ==&lt;br /&gt;
On the &#039;&#039;&#039;web VM&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
mkdir mw146&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Download and extract MediaWiki 1.46 LTS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.46/mediawiki-1.46.0.tar.gz&lt;br /&gt;
tar -xzf mediawiki-1.46.0.tar.gz --strip-components=1 -C mw146&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Resulting structure:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/mw146&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 2: Copy required files from old installation ==&lt;br /&gt;
From the existing 1.43 installation (example path &amp;lt;code&amp;gt;/var/www/mw143&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
=== Copy LocalSettings.php ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cp /var/www/mw143/LocalSettings.php /var/www/mw146/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Copy images directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cp -R /var/www/mw143/images /var/www/mw146/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Copy custom logos (if stored outside images) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cp /var/www/mw143/resources/assets/*logo* /var/www/mw146/resources/assets/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do &#039;&#039;&#039;not&#039;&#039;&#039; copy extensions yet.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 3: Install or update extensions ==&lt;br /&gt;
MediaWiki 1.46 requires updated extensions.&lt;br /&gt;
&lt;br /&gt;
For each extension used in 1.43:&lt;br /&gt;
&lt;br /&gt;
# Download the &#039;&#039;&#039;1.46‑compatible&#039;&#039;&#039; version  &lt;br /&gt;
# Place it in &amp;lt;code&amp;gt;/var/www/mw146/extensions/&amp;lt;/code&amp;gt;  &lt;br /&gt;
# Keep the same configuration lines in &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Vector‑2022 is bundled in 1.46 → no action needed.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 4: Run the database upgrade ==&lt;br /&gt;
On the web VM:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www/mw146&lt;br /&gt;
php maintenance/update.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This upgrades the schema &#039;&#039;&#039;in place&#039;&#039;&#039;.  &lt;br /&gt;
No data is lost.  &lt;br /&gt;
No new database is created.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 5: Local testing before switching reverse proxy ==&lt;br /&gt;
Access the new installation directly via the web VM’s IP:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://&amp;amp;lt;web-vm-ip&amp;amp;gt;/mw146/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
* Login  &lt;br /&gt;
* Namespaces and subpages  &lt;br /&gt;
* Uploads  &lt;br /&gt;
* SMTP  &lt;br /&gt;
* Dark mode  &lt;br /&gt;
* Vector‑2022 behaviour  &lt;br /&gt;
* Special pages (filter box present)  &lt;br /&gt;
* Search  &lt;br /&gt;
* Logo  &lt;br /&gt;
&lt;br /&gt;
Proceed only when everything is correct.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 6: Switch reverse proxy ==&lt;br /&gt;
On the &#039;&#039;&#039;reverse‑proxy VM&#039;&#039;&#039;, update the root path.&lt;br /&gt;
&lt;br /&gt;
Example (Nginx):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
root /var/www/mw146;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The wiki now runs on &#039;&#039;&#039;1.46 LTS&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Rollback is instant: point back to &amp;lt;code&amp;gt;/var/www/mw143&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 7: Post‑upgrade checks ==&lt;br /&gt;
* Check error logs on web VM  &lt;br /&gt;
* Check reverse‑proxy logs  &lt;br /&gt;
* Verify job queue  &lt;br /&gt;
* Verify uploads  &lt;br /&gt;
* Verify Special pages  &lt;br /&gt;
* Verify dark mode  &lt;br /&gt;
* Verify email notifications  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Step 8: Cleanup ==&lt;br /&gt;
After several days of stable operation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm -rf /var/www/mw143&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or archive it for long‑term reference.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Rollback Procedure ==&lt;br /&gt;
If any issue occurs after switching:&lt;br /&gt;
&lt;br /&gt;
# Edit reverse‑proxy config  &lt;br /&gt;
# Point root back to &amp;lt;code&amp;gt;/var/www/mw143&amp;lt;/code&amp;gt;  &lt;br /&gt;
# Reload proxy  &lt;br /&gt;
# Wiki is instantly restored  &lt;br /&gt;
&lt;br /&gt;
Database remains compatible.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
* MediaWiki 1.46 includes native dark mode  &lt;br /&gt;
* Vector‑2022 settings may be simplified  &lt;br /&gt;
* The Special pages filter box is available in 1.46  &lt;br /&gt;
* No database recreation is required for upgrades&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1618</id>
		<title>ICT:MW Installation procedure 1.43 LTS -v2</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1618"/>
		<updated>2026-04-03T16:56:35Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Procedure for a New MediaWiki Instance (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible workflow for deploying a new MediaWiki instance on the existing 3‑VM infrastructure.&lt;br /&gt;
&lt;br /&gt;
The installation is intentionally split into two phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and testing on VM1 (Apache on port 8080)&lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 (nginx reverse‑proxy + HTTPS)&lt;br /&gt;
&lt;br /&gt;
This staged approach ensures safe testing before the wiki becomes accessible from the internet.&lt;br /&gt;
&lt;br /&gt;
== VM Overview ==&lt;br /&gt;
* &#039;&#039;&#039;VM1 (Web Layer):&#039;&#039;&#039; 192.168.33.231  &lt;br /&gt;
* &#039;&#039;&#039;VM2 (Database Layer):&#039;&#039;&#039; 192.168.33.232  &lt;br /&gt;
* &#039;&#039;&#039;VM3 (Reverse‑Proxy Layer):&#039;&#039;&#039; 192.168.33.233  &lt;br /&gt;
* &#039;&#039;&#039;DB user host address (VM1 → VM2):&#039;&#039;&#039; 10.10.10.1  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 1. Create the Database (VM2 – MariaDB) =&lt;br /&gt;
All commands in this section run on VM2 (192.168.33.232).&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
VM1 connects to MariaDB using its internal DB‑facing address: &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;10.10.10.1&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;10.10.10.1&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 2. Prepare the Installation Directory (VM1 – Web Layer) =&lt;br /&gt;
All commands below run on VM1 (192.168.33.231).&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into /var/www ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 3. Download MediaWiki =&lt;br /&gt;
Example: MediaWiki 1.43.8 LTS.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 4. Extract MediaWiki =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 5. Move Extracted Files into newMW =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 6. Ownership and Permissions =&lt;br /&gt;
Allows editing via VS Code while keeping Apache functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Directory/file permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 7. Apache Configuration on VM1 (Port 8080) =&lt;br /&gt;
&lt;br /&gt;
== 7.1 Enable Apache to listen on port 8080 ==&lt;br /&gt;
Edit:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/httpd/conf/httpd.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.2 Validate and restart ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apachectl configtest&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.3 Verify Apache is listening ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ss -tlnp | grep httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.0.0.0:80&lt;br /&gt;
0.0.0.0:8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.4 Firewall rule (VM1) ==&lt;br /&gt;
Allow port 8080:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
firewall-cmd --add-port=8080/tcp --permanent&lt;br /&gt;
firewall-cmd --reload&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.5 Local‑only Apache VirtualHost ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newmw.local&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newmw-local-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newmw-local-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 8. Run the Installer Locally =&lt;br /&gt;
Access:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;http://192.168.33.231:8080&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;http://newmw.local:8080&amp;lt;/code&amp;gt; (if added to /etc/hosts)&lt;br /&gt;
&lt;br /&gt;
== Internal DB Network Logic (10.10.10.x) ==&lt;br /&gt;
The internal network between VM1 and VM2 uses dedicated addresses:&lt;br /&gt;
&lt;br /&gt;
* VM1 (Web Layer): &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;&lt;br /&gt;
* VM2 (Database Layer): &#039;&#039;&#039;10.10.10.2&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When MediaWiki (running on VM1) connects to MariaDB on VM2, the connection originates from VM1’s internal NIC.  &lt;br /&gt;
Therefore:&lt;br /&gt;
&lt;br /&gt;
* VM1 connects **to** MariaDB at:  &lt;br /&gt;
  &amp;lt;code&amp;gt;10.10.10.2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VM2 sees VM1 **coming from**:  &lt;br /&gt;
  &amp;lt;code&amp;gt;10.10.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because MariaDB authorizes users based on the client’s source address, database users must be created as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&#039;wikiuser&#039;@&#039;10.10.10.1&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is why all MediaWiki instances on VM1 use the same host restriction.  &lt;br /&gt;
It ensures that only VM1 can authenticate to MariaDB over the internal network.&lt;br /&gt;
&lt;br /&gt;
== Result after installation flow ==&lt;br /&gt;
&lt;br /&gt;
Installer will generate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;http://192.168.33.231:8080&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Place &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 9. Local Testing =&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
* Page creation  &lt;br /&gt;
* Editing  &lt;br /&gt;
* File uploads  &lt;br /&gt;
* User accounts  &lt;br /&gt;
* Extensions  &lt;br /&gt;
* Permissions  &lt;br /&gt;
* Logging  &lt;br /&gt;
&lt;br /&gt;
Only proceed when everything works locally.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 10. Public Exposure via VM3 (Reverse‑Proxy Layer) =&lt;br /&gt;
&lt;br /&gt;
== 10.1 Create minimal HTTP‑only nginx config (VM3) ==&lt;br /&gt;
File:&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/nginx/conf.d/kb.costasano.club.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTP only)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto http;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 11. Issue the Certificate (VM3) =&lt;br /&gt;
Use the nginx plugin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo certbot --nginx -d kb.costasano.club&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certbot will:&lt;br /&gt;
&lt;br /&gt;
* inject temporary ACME config  &lt;br /&gt;
* validate the domain  &lt;br /&gt;
* obtain the certificate  &lt;br /&gt;
* install it  &lt;br /&gt;
* register it for renewal  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 12. Replace with Full HTTPS Reverse‑Proxy (VM3) =&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTPS)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
# --- HTTP (redirect + ACME) ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 301 https://$host$request_uri;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# --- HTTPS ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 443 ssl;&lt;br /&gt;
    listen [::]:443 ssl;&lt;br /&gt;
    http2 on;&lt;br /&gt;
&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    ssl_certificate     /etc/letsencrypt/live/kb.costasano.club/fullchain.pem;&lt;br /&gt;
    ssl_certificate_key /etc/letsencrypt/live/kb.costasano.club/privkey.pem;&lt;br /&gt;
&lt;br /&gt;
    ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
    ssl_prefer_server_ciphers on;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
&lt;br /&gt;
        proxy_buffering on;&lt;br /&gt;
        proxy_buffers 16 16k;&lt;br /&gt;
        proxy_buffer_size 16k;&lt;br /&gt;
&lt;br /&gt;
        proxy_connect_timeout 60s;&lt;br /&gt;
        proxy_send_timeout 60s;&lt;br /&gt;
        proxy_read_timeout 60s;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 13. Update LocalSettings.php for Public Access =&lt;br /&gt;
Change:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optional:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgCanonicalServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 14. Final Verification =&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -I https://kb.costasano.club&amp;lt;/code&amp;gt; returns 200 or 301  &lt;br /&gt;
* Browser loads the wiki  &lt;br /&gt;
* Editing works  &lt;br /&gt;
* Uploads work  &lt;br /&gt;
* No rewrite errors  &lt;br /&gt;
* nginx proxies correctly  &lt;br /&gt;
* MariaDB connections succeed  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 15. Login Issues After Changing LocalSettings.php =&lt;br /&gt;
MediaWiki is very sensitive to stale cookies and cached sessions, especially&lt;br /&gt;
after changing settings such as:&lt;br /&gt;
&lt;br /&gt;
* $wgServer&lt;br /&gt;
* $wgCookieSecure&lt;br /&gt;
* $wgCookieSameSite&lt;br /&gt;
* $wgUseReverseProxy&lt;br /&gt;
* $wgUseCdn&lt;br /&gt;
&lt;br /&gt;
If login suddenly fails or a Captcha appears even though no Captcha extension&lt;br /&gt;
is enabled, the cause is usually old browser cookies.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fix:&#039;&#039;&#039; open the wiki in a private/incognito window or clear cookies for the&lt;br /&gt;
domain. This forces MediaWiki to create a fresh session and resolves the issue.&lt;br /&gt;
&lt;br /&gt;
=== Differences Between MediaWiki 1.43 and 1.45 (Login, Captcha, Reverse‑Proxy) ===&lt;br /&gt;
MediaWiki 1.43 and 1.45 behave differently when installed behind a reverse‑proxy&lt;br /&gt;
such as nginx. This affects login, session cookies, and the appearance of the&lt;br /&gt;
“phantom Captcha” (a throttle challenge that cannot be solved).&lt;br /&gt;
&lt;br /&gt;
==== MediaWiki 1.45 (more tolerant) ====&lt;br /&gt;
MediaWiki 1.45 includes improved session and cookie handling. It automatically:&lt;br /&gt;
&lt;br /&gt;
* detects HTTPS behind a reverse‑proxy&lt;br /&gt;
* regenerates session cookies when needed&lt;br /&gt;
* accepts SameSite=None cookies more reliably&lt;br /&gt;
* avoids triggering login throttling on fresh installs&lt;br /&gt;
&lt;br /&gt;
As a result, MediaWiki 1.45 usually works immediately behind nginx without&lt;br /&gt;
showing any Captcha or blocking logins.&lt;br /&gt;
&lt;br /&gt;
==== MediaWiki 1.43 (stricter behaviour) ====&lt;br /&gt;
MediaWiki 1.43 uses older, stricter session logic. If any of the following are&lt;br /&gt;
misconfigured:&lt;br /&gt;
&lt;br /&gt;
* $wgServer&lt;br /&gt;
* $wgCookieSecure&lt;br /&gt;
* $wgCookieSameSite&lt;br /&gt;
* $wgUseReverseProxy&lt;br /&gt;
* $wgUseCdn&lt;br /&gt;
* missing $wgCdnServers entry&lt;br /&gt;
&lt;br /&gt;
…MediaWiki may fail to create a valid login session. When this happens, it&lt;br /&gt;
displays a Captcha-like box even though no Captcha extension is enabled. This is&lt;br /&gt;
not a real Captcha but the built‑in login throttle, and it always fails.&lt;br /&gt;
&lt;br /&gt;
==== Why this did not happen on the previous install ====&lt;br /&gt;
The earlier wiki was installed on MediaWiki 1.45, which is more forgiving of&lt;br /&gt;
reverse‑proxy setups. MediaWiki 1.43 requires explicit configuration to trust&lt;br /&gt;
the proxy and accept secure cookies.&lt;br /&gt;
&lt;br /&gt;
==== Fix ====&lt;br /&gt;
Add the following lines to LocalSettings.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgUseCdn = true;&lt;br /&gt;
$wgUseReverseProxy = true;&lt;br /&gt;
$wgCdnServers = [ &amp;quot;192.168.33.233&amp;quot; ];  # nginx reverse-proxy&lt;br /&gt;
$wgCookieSecure = true;&lt;br /&gt;
$wgCookieSameSite = &amp;quot;None&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If login still fails, clear browser cookies or open the wiki in a private window&lt;br /&gt;
to force a fresh session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= 16. Summary =&lt;br /&gt;
This procedure installs MediaWiki in two safe phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and validation on VM1  &lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 with HTTPS  &lt;br /&gt;
&lt;br /&gt;
This ensures a clean, reproducible, low‑risk deployment workflow.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1617</id>
		<title>ICT:MW Installation procedure 1.43 LTS -v2</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1617"/>
		<updated>2026-04-03T16:44:41Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Procedure for a New MediaWiki Instance (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible workflow for deploying a new MediaWiki instance on the existing 3‑VM infrastructure.&lt;br /&gt;
&lt;br /&gt;
The installation is intentionally split into two phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and testing on VM1 (Apache on port 8080)&lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 (nginx reverse‑proxy + HTTPS)&lt;br /&gt;
&lt;br /&gt;
This staged approach ensures safe testing before the wiki becomes accessible from the internet.&lt;br /&gt;
&lt;br /&gt;
== VM Overview ==&lt;br /&gt;
* &#039;&#039;&#039;VM1 (Web Layer):&#039;&#039;&#039; 192.168.33.231  &lt;br /&gt;
* &#039;&#039;&#039;VM2 (Database Layer):&#039;&#039;&#039; 192.168.33.232  &lt;br /&gt;
* &#039;&#039;&#039;VM3 (Reverse‑Proxy Layer):&#039;&#039;&#039; 192.168.33.233  &lt;br /&gt;
* &#039;&#039;&#039;DB user host address (VM1 → VM2):&#039;&#039;&#039; 10.10.10.1  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 1. Create the Database (VM2 – MariaDB) =&lt;br /&gt;
All commands in this section run on VM2 (192.168.33.232).&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
VM1 connects to MariaDB using its internal DB‑facing address: &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;10.10.10.1&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;10.10.10.1&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 2. Prepare the Installation Directory (VM1 – Web Layer) =&lt;br /&gt;
All commands below run on VM1 (192.168.33.231).&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into /var/www ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 3. Download MediaWiki =&lt;br /&gt;
Example: MediaWiki 1.43.8 LTS.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 4. Extract MediaWiki =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 5. Move Extracted Files into newMW =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 6. Ownership and Permissions =&lt;br /&gt;
Allows editing via VS Code while keeping Apache functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Directory/file permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 7. Apache Configuration on VM1 (Port 8080) =&lt;br /&gt;
&lt;br /&gt;
== 7.1 Enable Apache to listen on port 8080 ==&lt;br /&gt;
Edit:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/httpd/conf/httpd.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.2 Validate and restart ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apachectl configtest&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.3 Verify Apache is listening ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ss -tlnp | grep httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.0.0.0:80&lt;br /&gt;
0.0.0.0:8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.4 Firewall rule (VM1) ==&lt;br /&gt;
Allow port 8080:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
firewall-cmd --add-port=8080/tcp --permanent&lt;br /&gt;
firewall-cmd --reload&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.5 Local‑only Apache VirtualHost ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newmw.local&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newmw-local-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newmw-local-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 8. Run the Installer Locally =&lt;br /&gt;
Access:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;http://192.168.33.231:8080&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;http://newmw.local:8080&amp;lt;/code&amp;gt; (if added to /etc/hosts)&lt;br /&gt;
&lt;br /&gt;
== Internal DB Network Logic (10.10.10.x) ==&lt;br /&gt;
The internal network between VM1 and VM2 uses dedicated addresses:&lt;br /&gt;
&lt;br /&gt;
* VM1 (Web Layer): &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;&lt;br /&gt;
* VM2 (Database Layer): &#039;&#039;&#039;10.10.10.2&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When MediaWiki (running on VM1) connects to MariaDB on VM2, the connection originates from VM1’s internal NIC.  &lt;br /&gt;
Therefore:&lt;br /&gt;
&lt;br /&gt;
* VM1 connects **to** MariaDB at:  &lt;br /&gt;
  &amp;lt;code&amp;gt;10.10.10.2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VM2 sees VM1 **coming from**:  &lt;br /&gt;
  &amp;lt;code&amp;gt;10.10.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because MariaDB authorizes users based on the client’s source address, database users must be created as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&#039;wikiuser&#039;@&#039;10.10.10.1&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is why all MediaWiki instances on VM1 use the same host restriction.  &lt;br /&gt;
It ensures that only VM1 can authenticate to MariaDB over the internal network.&lt;br /&gt;
&lt;br /&gt;
== Result after installation flow ==&lt;br /&gt;
&lt;br /&gt;
Installer will generate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;http://192.168.33.231:8080&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Place &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 9. Local Testing =&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
* Page creation  &lt;br /&gt;
* Editing  &lt;br /&gt;
* File uploads  &lt;br /&gt;
* User accounts  &lt;br /&gt;
* Extensions  &lt;br /&gt;
* Permissions  &lt;br /&gt;
* Logging  &lt;br /&gt;
&lt;br /&gt;
Only proceed when everything works locally.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 10. Public Exposure via VM3 (Reverse‑Proxy Layer) =&lt;br /&gt;
&lt;br /&gt;
== 10.1 Create minimal HTTP‑only nginx config (VM3) ==&lt;br /&gt;
File:&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/nginx/conf.d/kb.costasano.club.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTP only)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto http;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 11. Issue the Certificate (VM3) =&lt;br /&gt;
Use the nginx plugin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo certbot --nginx -d kb.costasano.club&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certbot will:&lt;br /&gt;
&lt;br /&gt;
* inject temporary ACME config  &lt;br /&gt;
* validate the domain  &lt;br /&gt;
* obtain the certificate  &lt;br /&gt;
* install it  &lt;br /&gt;
* register it for renewal  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 12. Replace with Full HTTPS Reverse‑Proxy (VM3) =&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTPS)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
# --- HTTP (redirect + ACME) ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 301 https://$host$request_uri;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# --- HTTPS ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 443 ssl;&lt;br /&gt;
    listen [::]:443 ssl;&lt;br /&gt;
    http2 on;&lt;br /&gt;
&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    ssl_certificate     /etc/letsencrypt/live/kb.costasano.club/fullchain.pem;&lt;br /&gt;
    ssl_certificate_key /etc/letsencrypt/live/kb.costasano.club/privkey.pem;&lt;br /&gt;
&lt;br /&gt;
    ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
    ssl_prefer_server_ciphers on;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
&lt;br /&gt;
        proxy_buffering on;&lt;br /&gt;
        proxy_buffers 16 16k;&lt;br /&gt;
        proxy_buffer_size 16k;&lt;br /&gt;
&lt;br /&gt;
        proxy_connect_timeout 60s;&lt;br /&gt;
        proxy_send_timeout 60s;&lt;br /&gt;
        proxy_read_timeout 60s;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 13. Update LocalSettings.php for Public Access =&lt;br /&gt;
Change:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optional:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgCanonicalServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 14. Final Verification =&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -I https://kb.costasano.club&amp;lt;/code&amp;gt; returns 200 or 301  &lt;br /&gt;
* Browser loads the wiki  &lt;br /&gt;
* Editing works  &lt;br /&gt;
* Uploads work  &lt;br /&gt;
* No rewrite errors  &lt;br /&gt;
* nginx proxies correctly  &lt;br /&gt;
* MariaDB connections succeed  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 15. Login Issues After Changing LocalSettings.php =&lt;br /&gt;
MediaWiki is very sensitive to stale cookies and cached sessions, especially&lt;br /&gt;
after changing settings such as:&lt;br /&gt;
&lt;br /&gt;
* $wgServer&lt;br /&gt;
* $wgCookieSecure&lt;br /&gt;
* $wgCookieSameSite&lt;br /&gt;
* $wgUseReverseProxy&lt;br /&gt;
* $wgUseCdn&lt;br /&gt;
&lt;br /&gt;
If login suddenly fails or a Captcha appears even though no Captcha extension&lt;br /&gt;
is enabled, the cause is usually old browser cookies.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fix:&#039;&#039;&#039; open the wiki in a private/incognito window or clear cookies for the&lt;br /&gt;
domain. This forces MediaWiki to create a fresh session and resolves the issue.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= 16. Summary =&lt;br /&gt;
This procedure installs MediaWiki in two safe phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and validation on VM1  &lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 with HTTPS  &lt;br /&gt;
&lt;br /&gt;
This ensures a clean, reproducible, low‑risk deployment workflow.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1616</id>
		<title>ICT:MW Installation procedure 1.43 LTS -v2</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1616"/>
		<updated>2026-04-03T16:13:08Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Procedure for a New MediaWiki Instance (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible workflow for deploying a new MediaWiki instance on the existing 3‑VM infrastructure.&lt;br /&gt;
&lt;br /&gt;
The installation is intentionally split into two phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and testing on VM1 (Apache on port 8080)&lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 (nginx reverse‑proxy + HTTPS)&lt;br /&gt;
&lt;br /&gt;
This staged approach ensures safe testing before the wiki becomes accessible from the internet.&lt;br /&gt;
&lt;br /&gt;
== VM Overview ==&lt;br /&gt;
* &#039;&#039;&#039;VM1 (Web Layer):&#039;&#039;&#039; 192.168.33.231  &lt;br /&gt;
* &#039;&#039;&#039;VM2 (Database Layer):&#039;&#039;&#039; 192.168.33.232  &lt;br /&gt;
* &#039;&#039;&#039;VM3 (Reverse‑Proxy Layer):&#039;&#039;&#039; 192.168.33.233  &lt;br /&gt;
* &#039;&#039;&#039;DB user host address (VM1 → VM2):&#039;&#039;&#039; 10.10.10.1  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 1. Create the Database (VM2 – MariaDB) =&lt;br /&gt;
All commands in this section run on VM2 (192.168.33.232).&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
VM1 connects to MariaDB using its internal DB‑facing address: &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;10.10.10.1&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;10.10.10.1&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 2. Prepare the Installation Directory (VM1 – Web Layer) =&lt;br /&gt;
All commands below run on VM1 (192.168.33.231).&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into /var/www ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 3. Download MediaWiki =&lt;br /&gt;
Example: MediaWiki 1.43.8 LTS.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 4. Extract MediaWiki =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 5. Move Extracted Files into newMW =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 6. Ownership and Permissions =&lt;br /&gt;
Allows editing via VS Code while keeping Apache functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Directory/file permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 7. Apache Configuration on VM1 (Port 8080) =&lt;br /&gt;
&lt;br /&gt;
== 7.1 Enable Apache to listen on port 8080 ==&lt;br /&gt;
Edit:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/httpd/conf/httpd.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.2 Validate and restart ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apachectl configtest&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.3 Verify Apache is listening ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ss -tlnp | grep httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.0.0.0:80&lt;br /&gt;
0.0.0.0:8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.4 Firewall rule (VM1) ==&lt;br /&gt;
Allow port 8080:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
firewall-cmd --add-port=8080/tcp --permanent&lt;br /&gt;
firewall-cmd --reload&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.5 Local‑only Apache VirtualHost ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newmw.local&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newmw-local-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newmw-local-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 8. Run the Installer Locally =&lt;br /&gt;
Access:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;http://192.168.33.231:8080&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;http://newmw.local:8080&amp;lt;/code&amp;gt; (if added to /etc/hosts)&lt;br /&gt;
&lt;br /&gt;
== Internal DB Network Logic (10.10.10.x) ==&lt;br /&gt;
The internal network between VM1 and VM2 uses dedicated addresses:&lt;br /&gt;
&lt;br /&gt;
* VM1 (Web Layer): &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;&lt;br /&gt;
* VM2 (Database Layer): &#039;&#039;&#039;10.10.10.2&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When MediaWiki (running on VM1) connects to MariaDB on VM2, the connection originates from VM1’s internal NIC.  &lt;br /&gt;
Therefore:&lt;br /&gt;
&lt;br /&gt;
* VM1 connects **to** MariaDB at:  &lt;br /&gt;
  &amp;lt;code&amp;gt;10.10.10.2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VM2 sees VM1 **coming from**:  &lt;br /&gt;
  &amp;lt;code&amp;gt;10.10.10.1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because MariaDB authorizes users based on the client’s source address, database users must be created as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&#039;wikiuser&#039;@&#039;10.10.10.1&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is why all MediaWiki instances on VM1 use the same host restriction.  &lt;br /&gt;
It ensures that only VM1 can authenticate to MariaDB over the internal network.&lt;br /&gt;
&lt;br /&gt;
== Result after installation flow ==&lt;br /&gt;
&lt;br /&gt;
Installer will generate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;http://192.168.33.231:8080&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Place &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 9. Local Testing =&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
* Page creation  &lt;br /&gt;
* Editing  &lt;br /&gt;
* File uploads  &lt;br /&gt;
* User accounts  &lt;br /&gt;
* Extensions  &lt;br /&gt;
* Permissions  &lt;br /&gt;
* Logging  &lt;br /&gt;
&lt;br /&gt;
Only proceed when everything works locally.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 10. Public Exposure via VM3 (Reverse‑Proxy Layer) =&lt;br /&gt;
&lt;br /&gt;
== 10.1 Create minimal HTTP‑only nginx config (VM3) ==&lt;br /&gt;
File:&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/nginx/conf.d/kb.costasano.club.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTP only)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto http;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 11. Issue the Certificate (VM3) =&lt;br /&gt;
Use the nginx plugin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo certbot --nginx -d kb.costasano.club&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certbot will:&lt;br /&gt;
&lt;br /&gt;
* inject temporary ACME config  &lt;br /&gt;
* validate the domain  &lt;br /&gt;
* obtain the certificate  &lt;br /&gt;
* install it  &lt;br /&gt;
* register it for renewal  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 12. Replace with Full HTTPS Reverse‑Proxy (VM3) =&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTPS)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
# --- HTTP (redirect + ACME) ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 301 https://$host$request_uri;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# --- HTTPS ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 443 ssl;&lt;br /&gt;
    listen [::]:443 ssl;&lt;br /&gt;
    http2 on;&lt;br /&gt;
&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    ssl_certificate     /etc/letsencrypt/live/kb.costasano.club/fullchain.pem;&lt;br /&gt;
    ssl_certificate_key /etc/letsencrypt/live/kb.costasano.club/privkey.pem;&lt;br /&gt;
&lt;br /&gt;
    ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
    ssl_prefer_server_ciphers on;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
&lt;br /&gt;
        proxy_buffering on;&lt;br /&gt;
        proxy_buffers 16 16k;&lt;br /&gt;
        proxy_buffer_size 16k;&lt;br /&gt;
&lt;br /&gt;
        proxy_connect_timeout 60s;&lt;br /&gt;
        proxy_send_timeout 60s;&lt;br /&gt;
        proxy_read_timeout 60s;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 13. Update LocalSettings.php for Public Access =&lt;br /&gt;
Change:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optional:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgCanonicalServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 14. Final Verification =&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -I https://kb.costasano.club&amp;lt;/code&amp;gt; returns 200 or 301  &lt;br /&gt;
* Browser loads the wiki  &lt;br /&gt;
* Editing works  &lt;br /&gt;
* Uploads work  &lt;br /&gt;
* No rewrite errors  &lt;br /&gt;
* nginx proxies correctly  &lt;br /&gt;
* MariaDB connections succeed  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 15. Summary =&lt;br /&gt;
This procedure installs MediaWiki in two safe phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and validation on VM1  &lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 with HTTPS  &lt;br /&gt;
&lt;br /&gt;
This ensures a clean, reproducible, low‑risk deployment workflow.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1615</id>
		<title>ICT:MW Installation procedure 1.43 LTS -v2</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS_-v2&amp;diff=1615"/>
		<updated>2026-04-03T16:04:05Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;= Installation Procedure for a New MediaWiki Instance (MediaWiki 1.43 LTS) = This document describes the clean, reproducible workflow for deploying a new MediaWiki instance on the existing 3‑VM infrastructure.  The installation is intentionally split into two phases:  * &amp;#039;&amp;#039;&amp;#039;Phase 1:&amp;#039;&amp;#039;&amp;#039; Local installation and testing on VM1 (Apache on port 8080) * &amp;#039;&amp;#039;&amp;#039;Phase 2:&amp;#039;&amp;#039;&amp;#039; Public exposure through VM3 (nginx reverse‑proxy + HTTPS)  This staged approach ensures safe testing before...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Procedure for a New MediaWiki Instance (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible workflow for deploying a new MediaWiki instance on the existing 3‑VM infrastructure.&lt;br /&gt;
&lt;br /&gt;
The installation is intentionally split into two phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and testing on VM1 (Apache on port 8080)&lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 (nginx reverse‑proxy + HTTPS)&lt;br /&gt;
&lt;br /&gt;
This staged approach ensures safe testing before the wiki becomes accessible from the internet.&lt;br /&gt;
&lt;br /&gt;
== VM Overview ==&lt;br /&gt;
* &#039;&#039;&#039;VM1 (Web Layer):&#039;&#039;&#039; 192.168.33.231  &lt;br /&gt;
* &#039;&#039;&#039;VM2 (Database Layer):&#039;&#039;&#039; 192.168.33.232  &lt;br /&gt;
* &#039;&#039;&#039;VM3 (Reverse‑Proxy Layer):&#039;&#039;&#039; 192.168.33.233  &lt;br /&gt;
* &#039;&#039;&#039;DB user host address (VM1 → VM2):&#039;&#039;&#039; 10.10.10.1  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 1. Create the Database (VM2 – MariaDB) =&lt;br /&gt;
All commands in this section run on VM2 (192.168.33.232).&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
VM1 connects to MariaDB using its internal DB‑facing address: &#039;&#039;&#039;10.10.10.1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;10.10.10.1&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;10.10.10.1&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 2. Prepare the Installation Directory (VM1 – Web Layer) =&lt;br /&gt;
All commands below run on VM1 (192.168.33.231).&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into /var/www ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 3. Download MediaWiki =&lt;br /&gt;
Example: MediaWiki 1.43.8 LTS.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 4. Extract MediaWiki =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 5. Move Extracted Files into newMW =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 6. Ownership and Permissions =&lt;br /&gt;
Allows editing via VS Code while keeping Apache functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Directory/file permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 7. Apache Configuration on VM1 (Port 8080) =&lt;br /&gt;
&lt;br /&gt;
== 7.1 Enable Apache to listen on port 8080 ==&lt;br /&gt;
Edit:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/httpd/conf/httpd.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.2 Validate and restart ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apachectl configtest&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.3 Verify Apache is listening ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ss -tlnp | grep httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.0.0.0:80&lt;br /&gt;
0.0.0.0:8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.4 Firewall rule (VM1) ==&lt;br /&gt;
Allow port 8080:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
firewall-cmd --add-port=8080/tcp --permanent&lt;br /&gt;
firewall-cmd --reload&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.5 Local‑only Apache VirtualHost ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newmw.local&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newmw-local-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newmw-local-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 8. Run the Installer Locally =&lt;br /&gt;
Access:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;http://192.168.33.231:8080&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;http://newmw.local:8080&amp;lt;/code&amp;gt; (if added to /etc/hosts)&lt;br /&gt;
&lt;br /&gt;
Installer will generate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;http://192.168.33.231:8080&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Place &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 9. Local Testing =&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
* Page creation  &lt;br /&gt;
* Editing  &lt;br /&gt;
* File uploads  &lt;br /&gt;
* User accounts  &lt;br /&gt;
* Extensions  &lt;br /&gt;
* Permissions  &lt;br /&gt;
* Logging  &lt;br /&gt;
&lt;br /&gt;
Only proceed when everything works locally.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 10. Public Exposure via VM3 (Reverse‑Proxy Layer) =&lt;br /&gt;
&lt;br /&gt;
== 10.1 Create minimal HTTP‑only nginx config (VM3) ==&lt;br /&gt;
File:&lt;br /&gt;
&amp;lt;code&amp;gt;/etc/nginx/conf.d/kb.costasano.club.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTP only)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto http;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 11. Issue the Certificate (VM3) =&lt;br /&gt;
Use the nginx plugin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo certbot --nginx -d kb.costasano.club&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certbot will:&lt;br /&gt;
&lt;br /&gt;
* inject temporary ACME config  &lt;br /&gt;
* validate the domain  &lt;br /&gt;
* obtain the certificate  &lt;br /&gt;
* install it  &lt;br /&gt;
* register it for renewal  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 12. Replace with Full HTTPS Reverse‑Proxy (VM3) =&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTPS)&lt;br /&gt;
#  kb.costasano.club&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
# --- HTTP (redirect + ACME) ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 301 https://$host$request_uri;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# --- HTTPS ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 443 ssl;&lt;br /&gt;
    listen [::]:443 ssl;&lt;br /&gt;
    http2 on;&lt;br /&gt;
&lt;br /&gt;
    server_name kb.costasano.club;&lt;br /&gt;
&lt;br /&gt;
    ssl_certificate     /etc/letsencrypt/live/kb.costasano.club/fullchain.pem;&lt;br /&gt;
    ssl_certificate_key /etc/letsencrypt/live/kb.costasano.club/privkey.pem;&lt;br /&gt;
&lt;br /&gt;
    ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
    ssl_prefer_server_ciphers on;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://192.168.33.231:8080;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host kb.costasano.club;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
&lt;br /&gt;
        proxy_buffering on;&lt;br /&gt;
        proxy_buffers 16 16k;&lt;br /&gt;
        proxy_buffer_size 16k;&lt;br /&gt;
&lt;br /&gt;
        proxy_connect_timeout 60s;&lt;br /&gt;
        proxy_send_timeout 60s;&lt;br /&gt;
        proxy_read_timeout 60s;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 13. Update LocalSettings.php for Public Access =&lt;br /&gt;
Change:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optional:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgCanonicalServer = &amp;quot;https://kb.costasano.club&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 14. Final Verification =&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -I https://kb.costasano.club&amp;lt;/code&amp;gt; returns 200 or 301  &lt;br /&gt;
* Browser loads the wiki  &lt;br /&gt;
* Editing works  &lt;br /&gt;
* Uploads work  &lt;br /&gt;
* No rewrite errors  &lt;br /&gt;
* nginx proxies correctly  &lt;br /&gt;
* MariaDB connections succeed  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= 15. Summary =&lt;br /&gt;
This procedure installs MediaWiki in two safe phases:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Phase 1:&#039;&#039;&#039; Local installation and validation on VM1  &lt;br /&gt;
* &#039;&#039;&#039;Phase 2:&#039;&#039;&#039; Public exposure through VM3 with HTTPS  &lt;br /&gt;
&lt;br /&gt;
This ensures a clean, reproducible, low‑risk deployment workflow.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1614</id>
		<title>ICT:MW Installation procedure 1.43 LTS</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1614"/>
		<updated>2026-04-03T15:50:58Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Installation Procedure for newMW (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible installation workflow for&lt;br /&gt;
deploying a new MediaWiki instance (newMW) on the existing 3‑VM infrastructure.&lt;br /&gt;
The installation is intentionally split into two phases:&lt;br /&gt;
&lt;br /&gt;
* Phase 1: Local installation and testing on VM1 (no reverse‑proxy required)&lt;br /&gt;
* Phase 2: Public exposure through VM3 (nginx reverse‑proxy)&lt;br /&gt;
&lt;br /&gt;
This staged approach allows safe testing before the wiki becomes accessible&lt;br /&gt;
from the internet.&lt;br /&gt;
&lt;br /&gt;
== 1. Create the newwiki Database (VM2 – Database Layer) ==&lt;br /&gt;
All commands in this section are executed on VM2.&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
Replace &amp;lt;code&amp;gt;VM1-IP&amp;lt;/code&amp;gt; with the internal Hyper‑V IP of the web server.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;VM1-IP&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;VM1-IP&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Prepare the Installation Directory (VM1 – Web Layer) ==&lt;br /&gt;
All commands below are executed on VM1.&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into the working directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Download MediaWiki ==&lt;br /&gt;
Download the latest LTS tarball (example: 1.43.8):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 4. Extract MediaWiki ==&lt;br /&gt;
Extract the archive. This creates a directory such as &amp;lt;code&amp;gt;mediawiki-1.43.8/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. Move Extracted Files into newMW ==&lt;br /&gt;
Move normal files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move hidden files (e.g. &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the now‑empty extraction directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the tarball:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Ownership and Permissions ==&lt;br /&gt;
Use the preferred ownership model to allow editing via VS Code while keeping&lt;br /&gt;
Apache fully functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Apply clean directory/file permissions ===&lt;br /&gt;
Directories:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
Ensures new files created inside inherit the &amp;lt;code&amp;gt;apache&amp;lt;/code&amp;gt; group.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7. Enable Apache to Listen on Port 8080 (VM1) &amp;amp; Virtual Host file ==&lt;br /&gt;
Apache does not automatically listen on new ports defined in VirtualHost&lt;br /&gt;
blocks. The port must be explicitly enabled in the main configuration.&lt;br /&gt;
&lt;br /&gt;
=== 7.1 Edit the main Apache configuration ===&lt;br /&gt;
Open the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/httpd/conf/httpd.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Locate the existing Listen directive:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 80&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the following line directly below it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.2 Validate the configuration ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apachectl configtest&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Syntax OK&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.3 Restart Apache ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.4 Verify Apache is listening on port 8080 ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ss -tlnp | grep httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.0.0.0:80&lt;br /&gt;
0.0.0.0:8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apache is now ready to serve the temporary local-only vhost on port 8080.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.5 Local‑Only Apache Virtual Host (VM1) ===&lt;br /&gt;
This vhost allows installation and testing without involving the reverse‑proxy.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newmw.local&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newmw-local-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newmw-local-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Run the Installer Locally ==&lt;br /&gt;
Access the installer using one of:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;http://VM1-IP:8080&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;http://newmw.local:8080&amp;lt;/code&amp;gt; (if added to /etc/hosts)&lt;br /&gt;
&lt;br /&gt;
Complete the installation.&lt;br /&gt;
&lt;br /&gt;
The installer will generate a &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;http://VM1-IP:8080&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Place the file in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 9. Local Testing ==&lt;br /&gt;
Before exposing the wiki publicly, verify:&lt;br /&gt;
&lt;br /&gt;
* Page creation&lt;br /&gt;
* Editing&lt;br /&gt;
* File uploads (if enabled)&lt;br /&gt;
* User accounts&lt;br /&gt;
* Extensions&lt;br /&gt;
* Permissions&lt;br /&gt;
* Logging&lt;br /&gt;
&lt;br /&gt;
This phase is isolated and safe.&lt;br /&gt;
&lt;br /&gt;
== 10. Prepare for Public Access (VM3 – Reverse‑Proxy Layer) ==&lt;br /&gt;
Only after local testing is complete, add the nginx server block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    server_name newwiki.example.com;&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://VM1-IP:8080;&lt;br /&gt;
        proxy_set_header Host $host;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 11. Update LocalSettings.php for Public Access ==&lt;br /&gt;
Change:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgCanonicalServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 12. Final Verification ==&lt;br /&gt;
* Public URL loads correctly&lt;br /&gt;
* &amp;lt;code&amp;gt;/wiki/Main_Page&amp;lt;/code&amp;gt; resolves&lt;br /&gt;
* Editing works&lt;br /&gt;
* Uploads work&lt;br /&gt;
* No rewrite errors in Apache logs&lt;br /&gt;
* nginx proxies correctly&lt;br /&gt;
* MariaDB connections succeed&lt;br /&gt;
&lt;br /&gt;
== 13. Summary ==&lt;br /&gt;
This procedure installs MediaWiki in two safe phases:&lt;br /&gt;
&lt;br /&gt;
* Phase 1: Local installation and validation on VM1&lt;br /&gt;
* Phase 2: Public exposure through VM3&lt;br /&gt;
&lt;br /&gt;
This staged approach avoids dependency on the reverse‑proxy during installation&lt;br /&gt;
and allows controlled, low‑risk rollout.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Addendum =&lt;br /&gt;
&lt;br /&gt;
== Adding a New Domain + Certificate on VM3 (nginx + Certbot) ==&lt;br /&gt;
This procedure is used when onboarding a new subdomain to the reverse‑proxy layer on VM3.  &lt;br /&gt;
It avoids the nginx/Certbot “missing certificate” failure by always starting with a minimal HTTP‑only configuration, issuing the certificate, and then enabling HTTPS.&lt;br /&gt;
&lt;br /&gt;
=== 1. Create a minimal HTTP‑only reverse‑proxy config ===&lt;br /&gt;
Create &amp;lt;code&amp;gt;/etc/nginx/conf.d/&amp;amp;lt;domain&amp;amp;gt;.conf&amp;lt;/code&amp;gt; with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTP only)&lt;br /&gt;
#  &amp;lt;domain&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name &amp;lt;domain&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
    # ACME challenge (Certbot uses this)&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    # Temporary: no HTTPS redirect until certificate exists&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://&amp;lt;backend-ip&amp;gt;:&amp;lt;backend-port&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host &amp;lt;domain&amp;gt;;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto http;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point the domain resolves over HTTP and Certbot can validate it.&lt;br /&gt;
&lt;br /&gt;
=== 2. Issue the certificate using the nginx plugin ===&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo certbot --nginx -d &amp;lt;domain&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certbot will:&lt;br /&gt;
* inject a temporary ACME location  &lt;br /&gt;
* validate the domain  &lt;br /&gt;
* obtain the certificate  &lt;br /&gt;
* install it  &lt;br /&gt;
* register it for automatic renewal  &lt;br /&gt;
&lt;br /&gt;
This step only works if nginx is running without SSL errors.&lt;br /&gt;
&lt;br /&gt;
=== 3. Replace the config with the full HTTPS reverse‑proxy ===&lt;br /&gt;
After the certificate exists, replace the file with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
#  Reverse proxy (HTTPS)&lt;br /&gt;
#  &amp;lt;domain&amp;gt;&lt;br /&gt;
# ============================================&lt;br /&gt;
&lt;br /&gt;
# --- HTTP (redirect + ACME) ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    listen [::]:80;&lt;br /&gt;
    server_name &amp;lt;domain&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 301 https://$host$request_uri;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# --- HTTPS ---&lt;br /&gt;
server {&lt;br /&gt;
    listen 443 ssl;&lt;br /&gt;
    listen [::]:443 ssl;&lt;br /&gt;
    http2 on;&lt;br /&gt;
&lt;br /&gt;
    server_name &amp;lt;domain&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
    ssl_certificate     /etc/letsencrypt/live/&amp;lt;domain&amp;gt;/fullchain.pem;&lt;br /&gt;
    ssl_certificate_key /etc/letsencrypt/live/&amp;lt;domain&amp;gt;/privkey.pem;&lt;br /&gt;
&lt;br /&gt;
    ssl_protocols TLSv1.2 TLSv1.3;&lt;br /&gt;
    ssl_prefer_server_ciphers on;&lt;br /&gt;
&lt;br /&gt;
    location /.well-known/acme-challenge/ {&lt;br /&gt;
        root /usr/share/nginx/html;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://&amp;lt;backend-ip&amp;gt;:&amp;lt;backend-port&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
        proxy_set_header Host &amp;lt;domain&amp;gt;;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
        proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
&lt;br /&gt;
        proxy_buffering on;&lt;br /&gt;
        proxy_buffers 16 16k;&lt;br /&gt;
        proxy_buffer_size 16k;&lt;br /&gt;
&lt;br /&gt;
        proxy_connect_timeout 60s;&lt;br /&gt;
        proxy_send_timeout 60s;&lt;br /&gt;
        proxy_read_timeout 60s;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx again:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo nginx -t&lt;br /&gt;
sudo systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 4. Verification checklist ===&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -I https://&amp;amp;lt;domain&amp;amp;gt;&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;200&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;301&amp;lt;/code&amp;gt;  &lt;br /&gt;
* Browser loads the site over HTTPS  &lt;br /&gt;
* Login works  &lt;br /&gt;
* File uploads work  &lt;br /&gt;
* Optional: &amp;lt;code&amp;gt;certbot renew --dry-run&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1613</id>
		<title>ICT:MW Installation procedure 1.43 LTS</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1613"/>
		<updated>2026-04-03T14:38:58Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Installation Procedure for newMW (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible installation workflow for&lt;br /&gt;
deploying a new MediaWiki instance (newMW) on the existing 3‑VM infrastructure.&lt;br /&gt;
The installation is intentionally split into two phases:&lt;br /&gt;
&lt;br /&gt;
* Phase 1: Local installation and testing on VM1 (no reverse‑proxy required)&lt;br /&gt;
* Phase 2: Public exposure through VM3 (nginx reverse‑proxy)&lt;br /&gt;
&lt;br /&gt;
This staged approach allows safe testing before the wiki becomes accessible&lt;br /&gt;
from the internet.&lt;br /&gt;
&lt;br /&gt;
== 1. Create the newwiki Database (VM2 – Database Layer) ==&lt;br /&gt;
All commands in this section are executed on VM2.&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
Replace &amp;lt;code&amp;gt;VM1-IP&amp;lt;/code&amp;gt; with the internal Hyper‑V IP of the web server.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;VM1-IP&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;VM1-IP&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Prepare the Installation Directory (VM1 – Web Layer) ==&lt;br /&gt;
All commands below are executed on VM1.&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into the working directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Download MediaWiki ==&lt;br /&gt;
Download the latest LTS tarball (example: 1.43.8):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 4. Extract MediaWiki ==&lt;br /&gt;
Extract the archive. This creates a directory such as &amp;lt;code&amp;gt;mediawiki-1.43.8/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. Move Extracted Files into newMW ==&lt;br /&gt;
Move normal files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move hidden files (e.g. &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the now‑empty extraction directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the tarball:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Ownership and Permissions ==&lt;br /&gt;
Use the preferred ownership model to allow editing via VS Code while keeping&lt;br /&gt;
Apache fully functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Apply clean directory/file permissions ===&lt;br /&gt;
Directories:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
Ensures new files created inside inherit the &amp;lt;code&amp;gt;apache&amp;lt;/code&amp;gt; group.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7. Enable Apache to Listen on Port 8080 (VM1) &amp;amp; Virtual Host file ==&lt;br /&gt;
Apache does not automatically listen on new ports defined in VirtualHost&lt;br /&gt;
blocks. The port must be explicitly enabled in the main configuration.&lt;br /&gt;
&lt;br /&gt;
=== 7.1 Edit the main Apache configuration ===&lt;br /&gt;
Open the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/httpd/conf/httpd.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Locate the existing Listen directive:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 80&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the following line directly below it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Listen 8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.2 Validate the configuration ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
apachectl configtest&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Syntax OK&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.3 Restart Apache ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.4 Verify Apache is listening on port 8080 ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ss -tlnp | grep httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Expected result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.0.0.0:80&lt;br /&gt;
0.0.0.0:8080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apache is now ready to serve the temporary local-only vhost on port 8080.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.5 Local‑Only Apache Virtual Host (VM1) ===&lt;br /&gt;
This vhost allows installation and testing without involving the reverse‑proxy.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newmw.local&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newmw-local-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newmw-local-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Run the Installer Locally ==&lt;br /&gt;
Access the installer using one of:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;http://VM1-IP:8080&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;http://newmw.local:8080&amp;lt;/code&amp;gt; (if added to /etc/hosts)&lt;br /&gt;
&lt;br /&gt;
Complete the installation.&lt;br /&gt;
&lt;br /&gt;
The installer will generate a &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;http://VM1-IP:8080&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Place the file in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 9. Local Testing ==&lt;br /&gt;
Before exposing the wiki publicly, verify:&lt;br /&gt;
&lt;br /&gt;
* Page creation&lt;br /&gt;
* Editing&lt;br /&gt;
* File uploads (if enabled)&lt;br /&gt;
* User accounts&lt;br /&gt;
* Extensions&lt;br /&gt;
* Permissions&lt;br /&gt;
* Logging&lt;br /&gt;
&lt;br /&gt;
This phase is isolated and safe.&lt;br /&gt;
&lt;br /&gt;
== 10. Prepare for Public Access (VM3 – Reverse‑Proxy Layer) ==&lt;br /&gt;
Only after local testing is complete, add the nginx server block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    server_name newwiki.example.com;&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://VM1-IP:8080;&lt;br /&gt;
        proxy_set_header Host $host;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 11. Update LocalSettings.php for Public Access ==&lt;br /&gt;
Change:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgCanonicalServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 12. Final Verification ==&lt;br /&gt;
* Public URL loads correctly&lt;br /&gt;
* &amp;lt;code&amp;gt;/wiki/Main_Page&amp;lt;/code&amp;gt; resolves&lt;br /&gt;
* Editing works&lt;br /&gt;
* Uploads work&lt;br /&gt;
* No rewrite errors in Apache logs&lt;br /&gt;
* nginx proxies correctly&lt;br /&gt;
* MariaDB connections succeed&lt;br /&gt;
&lt;br /&gt;
== 13. Summary ==&lt;br /&gt;
This procedure installs MediaWiki in two safe phases:&lt;br /&gt;
&lt;br /&gt;
* Phase 1: Local installation and validation on VM1&lt;br /&gt;
* Phase 2: Public exposure through VM3&lt;br /&gt;
&lt;br /&gt;
This staged approach avoids dependency on the reverse‑proxy during installation&lt;br /&gt;
and allows controlled, low‑risk rollout.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1612</id>
		<title>ICT:MW Installation procedure 1.43 LTS</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1612"/>
		<updated>2026-04-03T13:36:33Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Installation Procedure for newMW (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible installation workflow for&lt;br /&gt;
deploying a new MediaWiki instance (newMW) on the existing 3‑VM infrastructure.&lt;br /&gt;
The installation is intentionally split into two phases:&lt;br /&gt;
&lt;br /&gt;
* Phase 1: Local installation and testing on VM1 (no reverse‑proxy required)&lt;br /&gt;
* Phase 2: Public exposure through VM3 (nginx reverse‑proxy)&lt;br /&gt;
&lt;br /&gt;
This staged approach allows safe testing before the wiki becomes accessible&lt;br /&gt;
from the internet.&lt;br /&gt;
&lt;br /&gt;
== 1. Create the newwiki Database (VM2 – Database Layer) ==&lt;br /&gt;
All commands in this section are executed on VM2.&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
Replace &amp;lt;code&amp;gt;VM1-IP&amp;lt;/code&amp;gt; with the internal Hyper‑V IP of the web server.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;VM1-IP&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;VM1-IP&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Prepare the Installation Directory (VM1 – Web Layer) ==&lt;br /&gt;
All commands below are executed on VM1.&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into the working directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Download MediaWiki ==&lt;br /&gt;
Download the latest LTS tarball (example: 1.43.8):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 4. Extract MediaWiki ==&lt;br /&gt;
Extract the archive. This creates a directory such as &amp;lt;code&amp;gt;mediawiki-1.43.8/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. Move Extracted Files into newMW ==&lt;br /&gt;
Move normal files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move hidden files (e.g. &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the now‑empty extraction directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the tarball:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Ownership and Permissions ==&lt;br /&gt;
Use the preferred ownership model to allow editing via VS Code while keeping&lt;br /&gt;
Apache fully functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Apply clean directory/file permissions ===&lt;br /&gt;
Directories:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
Ensures new files created inside inherit the &amp;lt;code&amp;gt;apache&amp;lt;/code&amp;gt; group.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7. Local‑Only Apache Virtual Host (VM1) ==&lt;br /&gt;
This vhost allows installation and testing without involving the reverse‑proxy.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newmw.local&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newmw-local-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newmw-local-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Run the Installer Locally ==&lt;br /&gt;
Access the installer using one of:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;http://VM1-IP:8080&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;http://newmw.local:8080&amp;lt;/code&amp;gt; (if added to /etc/hosts)&lt;br /&gt;
&lt;br /&gt;
Complete the installation.&lt;br /&gt;
&lt;br /&gt;
The installer will generate a &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;http://VM1-IP:8080&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Place the file in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 9. Local Testing ==&lt;br /&gt;
Before exposing the wiki publicly, verify:&lt;br /&gt;
&lt;br /&gt;
* Page creation&lt;br /&gt;
* Editing&lt;br /&gt;
* File uploads (if enabled)&lt;br /&gt;
* User accounts&lt;br /&gt;
* Extensions&lt;br /&gt;
* Permissions&lt;br /&gt;
* Logging&lt;br /&gt;
&lt;br /&gt;
This phase is isolated and safe.&lt;br /&gt;
&lt;br /&gt;
== 10. Prepare for Public Access (VM3 – Reverse‑Proxy Layer) ==&lt;br /&gt;
Only after local testing is complete, add the nginx server block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    server_name newwiki.example.com;&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://VM1-IP:8080;&lt;br /&gt;
        proxy_set_header Host $host;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 11. Update LocalSettings.php for Public Access ==&lt;br /&gt;
Change:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgCanonicalServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 12. Final Verification ==&lt;br /&gt;
* Public URL loads correctly&lt;br /&gt;
* &amp;lt;code&amp;gt;/wiki/Main_Page&amp;lt;/code&amp;gt; resolves&lt;br /&gt;
* Editing works&lt;br /&gt;
* Uploads work&lt;br /&gt;
* No rewrite errors in Apache logs&lt;br /&gt;
* nginx proxies correctly&lt;br /&gt;
* MariaDB connections succeed&lt;br /&gt;
&lt;br /&gt;
== 13. Summary ==&lt;br /&gt;
This procedure installs MediaWiki in two safe phases:&lt;br /&gt;
&lt;br /&gt;
* Phase 1: Local installation and validation on VM1&lt;br /&gt;
* Phase 2: Public exposure through VM3&lt;br /&gt;
&lt;br /&gt;
This staged approach avoids dependency on the reverse‑proxy during installation&lt;br /&gt;
and allows controlled, low‑risk rollout.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1611</id>
		<title>ICT:MW Installation procedure 1.43 LTS</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1611"/>
		<updated>2026-04-03T13:31:41Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Procedure for newMW (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible installation workflow for&lt;br /&gt;
deploying a new MediaWiki instance (newMW) on the existing 3‑VM infrastructure.&lt;br /&gt;
It includes directory preparation, file extraction, permissions, database&lt;br /&gt;
creation, and the preferred ownership model for VS Code access.&lt;br /&gt;
&lt;br /&gt;
== 1. Create the newwiki Database (VM2 – Database Layer) ==&lt;br /&gt;
All commands in this section are executed on VM2.&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Connect to MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Create the database ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki&lt;br /&gt;
  CHARACTER SET utf8mb4&lt;br /&gt;
  COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.3 Create the database user ===&lt;br /&gt;
Replace &amp;lt;code&amp;gt;VM1-IP&amp;lt;/code&amp;gt; with the internal Hyper‑V IP of the web server.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;VM1-IP&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.4 Grant privileges ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;VM1-IP&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.5 Exit MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Prepare the Installation Directory (VM1 – Web Layer) ==&lt;br /&gt;
All commands below are executed on VM1.&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Move into the working directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Download MediaWiki ==&lt;br /&gt;
Download the latest LTS tarball (example: 1.43.8):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 4. Extract MediaWiki ==&lt;br /&gt;
Extract the archive. This creates a directory such as &amp;lt;code&amp;gt;mediawiki-1.43.8/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. Move Extracted Files into newMW ==&lt;br /&gt;
Move normal files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move hidden files (e.g. &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the now‑empty extraction directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the tarball:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Ownership and Permissions ==&lt;br /&gt;
Use the preferred ownership model to allow editing via VS Code while keeping&lt;br /&gt;
Apache fully functional.&lt;br /&gt;
&lt;br /&gt;
=== 6.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.3 Apply clean directory/file permissions ===&lt;br /&gt;
Directories:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 6.4 Enable group inheritance (setgid) ===&lt;br /&gt;
Ensures new files created inside inherit the &amp;lt;code&amp;gt;apache&amp;lt;/code&amp;gt; group.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7. Apache Virtual Host (VM1) ==&lt;br /&gt;
Create a vhost:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newwiki.example.com&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newwiki-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newwiki-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. nginx Reverse‑Proxy (VM3) ==&lt;br /&gt;
Add a server block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    server_name newwiki.example.com;&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://VM1-IP:8080;&lt;br /&gt;
        proxy_set_header Host $host;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 9. Run the MediaWiki Installer ==&lt;br /&gt;
Navigate to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://newwiki.example.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Provide:&lt;br /&gt;
* Database: &amp;lt;code&amp;gt;newwiki&amp;lt;/code&amp;gt;&lt;br /&gt;
* User: &amp;lt;code&amp;gt;newwikiuser&amp;lt;/code&amp;gt;&lt;br /&gt;
* Password: (as created on VM2)&lt;br /&gt;
* Site name&lt;br /&gt;
* Admin account&lt;br /&gt;
&lt;br /&gt;
Download &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; and place it in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 10. Minimal Post‑Install Configuration ==&lt;br /&gt;
Add or verify:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
$wgScriptPath = &amp;quot;&amp;quot;;&lt;br /&gt;
$wgArticlePath = &amp;quot;/wiki/$1&amp;quot;;&lt;br /&gt;
$wgUsePathInfo = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Enable uploads (optional):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgEnableUploads = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Enable SyntaxHighlight:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;SyntaxHighlight_GeSHi&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 11. Verification Checklist ==&lt;br /&gt;
* Site loads correctly&lt;br /&gt;
* &amp;lt;code&amp;gt;/wiki/Main_Page&amp;lt;/code&amp;gt; resolves&lt;br /&gt;
* Editing works&lt;br /&gt;
* File uploads work (if enabled)&lt;br /&gt;
* No rewrite errors in Apache logs&lt;br /&gt;
* nginx proxies correctly&lt;br /&gt;
* MariaDB connections succeed&lt;br /&gt;
&lt;br /&gt;
== 12. Summary ==&lt;br /&gt;
This procedure provides a clean, repeatable installation workflow for MediaWiki&lt;br /&gt;
1.43 LTS using the preferred ownership model (&amp;lt;code&amp;gt;mngr:apache&amp;lt;/code&amp;gt;) and the&lt;br /&gt;
existing 3‑VM architecture. It ensures clarity, maintainability, and&lt;br /&gt;
successor‑friendly operation.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1610</id>
		<title>ICT:MW Installation procedure 1.43 LTS</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Installation_procedure_1.43_LTS&amp;diff=1610"/>
		<updated>2026-04-03T13:29:43Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;= Installation Procedure for newMW (MediaWiki 1.43 LTS) = This document describes the clean, reproducible installation workflow for deploying a new MediaWiki instance (newMW) on the existing 3‑VM infrastructure. It includes directory preparation, file extraction, permissions, and the preferred ownership model for VS Code access.  == 1. Preparation == All commands are executed on VM1 (Web Layer).  === 1.1 Create the target directory === &amp;lt;pre&amp;gt; mkdir /var/www/newMW &amp;lt;/pre&amp;gt;...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Procedure for newMW (MediaWiki 1.43 LTS) =&lt;br /&gt;
This document describes the clean, reproducible installation workflow for&lt;br /&gt;
deploying a new MediaWiki instance (newMW) on the existing 3‑VM infrastructure.&lt;br /&gt;
It includes directory preparation, file extraction, permissions, and the&lt;br /&gt;
preferred ownership model for VS Code access.&lt;br /&gt;
&lt;br /&gt;
== 1. Preparation ==&lt;br /&gt;
All commands are executed on VM1 (Web Layer).&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Create the target directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Move into the working directory ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Download MediaWiki ==&lt;br /&gt;
Download the latest LTS tarball (example: 1.43.8):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Extract MediaWiki ==&lt;br /&gt;
Extract the archive. This creates a directory such as &amp;lt;code&amp;gt;mediawiki-1.43.8/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -xvzf mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 4. Move Extracted Files into newMW ==&lt;br /&gt;
Move normal files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/* newMW/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move hidden files (e.g. &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mv mediawiki-1.43.8/.* newMW/ 2&amp;gt;/dev/null&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the now‑empty extraction directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rmdir mediawiki-1.43.8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remove the tarball:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rm mediawiki-1.43.8.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. Ownership and Permissions ==&lt;br /&gt;
Use the preferred ownership model to allow editing via VS Code while keeping&lt;br /&gt;
Apache fully functional.&lt;br /&gt;
&lt;br /&gt;
=== 5.1 Set owner and group ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R mngr:apache /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5.2 Ensure group write permissions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod -R g+w /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5.3 Apply clean directory/file permissions ===&lt;br /&gt;
Directories:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type d -exec chmod 775 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /var/www/newMW -type f -exec chmod 664 {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5.4 Enable group inheritance (setgid) ===&lt;br /&gt;
Ensures new files created inside inherit the &amp;lt;code&amp;gt;apache&amp;lt;/code&amp;gt; group.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chmod g+s /var/www/newMW&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Apache Virtual Host ==&lt;br /&gt;
Create a vhost on VM1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newwiki.example.com&lt;br /&gt;
    DocumentRoot /var/www/newMW&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newMW&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newwiki-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newwiki-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restart Apache:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7. nginx Reverse‑Proxy (VM3) ==&lt;br /&gt;
Add a server block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    server_name newwiki.example.com;&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://VM1-IP:8080;&lt;br /&gt;
        proxy_set_header Host $host;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Run the MediaWiki Installer ==&lt;br /&gt;
Navigate to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://newwiki.example.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Provide:&lt;br /&gt;
* Database: &amp;lt;code&amp;gt;newwiki&amp;lt;/code&amp;gt;&lt;br /&gt;
* User: &amp;lt;code&amp;gt;newwikiuser&amp;lt;/code&amp;gt;&lt;br /&gt;
* Password: (as created on VM2)&lt;br /&gt;
* Site name&lt;br /&gt;
* Admin account&lt;br /&gt;
&lt;br /&gt;
Download &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; and place it in:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newMW/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 9. Minimal Post‑Install Configuration ==&lt;br /&gt;
Add or verify:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
$wgScriptPath = &amp;quot;&amp;quot;;&lt;br /&gt;
$wgArticlePath = &amp;quot;/wiki/$1&amp;quot;;&lt;br /&gt;
$wgUsePathInfo = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Enable uploads (optional):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgEnableUploads = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Enable SyntaxHighlight:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;SyntaxHighlight_GeSHi&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 10. Verification Checklist ==&lt;br /&gt;
* Site loads correctly&lt;br /&gt;
* &amp;lt;code&amp;gt;/wiki/Main_Page&amp;lt;/code&amp;gt; resolves&lt;br /&gt;
* Editing works&lt;br /&gt;
* File uploads work (if enabled)&lt;br /&gt;
* No rewrite errors in Apache logs&lt;br /&gt;
* nginx proxies correctly&lt;br /&gt;
* MariaDB connections succeed&lt;br /&gt;
&lt;br /&gt;
== 11. Summary ==&lt;br /&gt;
This procedure provides a clean, repeatable installation workflow for MediaWiki&lt;br /&gt;
1.43 LTS using the preferred ownership model (&amp;lt;code&amp;gt;mngr:apache&amp;lt;/code&amp;gt;) and the&lt;br /&gt;
existing 3‑VM architecture. It ensures clarity, maintainability, and&lt;br /&gt;
successor‑friendly operation.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Clean_installation_checklist_version_1.43_LTS&amp;diff=1609</id>
		<title>ICT:MW Clean installation checklist version 1.43 LTS</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Clean_installation_checklist_version_1.43_LTS&amp;diff=1609"/>
		<updated>2026-04-03T11:37:52Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page ICT:MW Clean installaiton checklist version 1.43 LTS to ICT:MW Clean installation checklist version 1.43 LTS without leaving a redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Checklist – MediaWiki 1.43 LTS =&lt;br /&gt;
This document provides a clean, reproducible installation procedure for&lt;br /&gt;
MediaWiki 1.43 LTS on AlmaLinux with Apache, PHP, MariaDB, and an nginx&lt;br /&gt;
reverse-proxy. It is designed for long-term stability and successor-friendly&lt;br /&gt;
maintenance.&lt;br /&gt;
&lt;br /&gt;
== 1. Preparation ==&lt;br /&gt;
Before installing MediaWiki, ensure the server environment is ready.&lt;br /&gt;
&lt;br /&gt;
=== 1.1 System Requirements ===&lt;br /&gt;
* AlmaLinux (or compatible RHEL-based system)&lt;br /&gt;
* Apache (httpd)&lt;br /&gt;
* PHP 8.1 or later&lt;br /&gt;
* MariaDB 10.5 or later&lt;br /&gt;
* nginx reverse-proxy (optional but recommended)&lt;br /&gt;
* SELinux/AppArmor configured or disabled as needed&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Install Required Packages ===&lt;br /&gt;
Install PHP and required extensions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dnf install php php-mbstring php-xml php-intl php-mysqlnd php-gd php-json php-cli php-opcache php-apcu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install Apache and MariaDB:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dnf install httpd mariadb-server&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Enable and start services:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl enable --now httpd mariadb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Database Setup ==&lt;br /&gt;
Create a clean database for the new wiki.&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Secure MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql_secure_installation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Create Database and User ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;localhost&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;localhost&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Download MediaWiki 1.43 LTS ==&lt;br /&gt;
Download and extract the LTS release.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.0.tar.gz&lt;br /&gt;
tar -xvzf mediawiki-1.43.0.tar.gz&lt;br /&gt;
mv mediawiki-1.43.0 newwiki&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set permissions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R apache:apache /var/www/newwiki&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 4. Apache Virtual Host ==&lt;br /&gt;
Create a dedicated vhost for the new wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newwiki.example.com&lt;br /&gt;
    DocumentRoot /var/www/newwiki&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newwiki&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newwiki-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newwiki-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Enable the site and restart Apache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. nginx Reverse-Proxy ==&lt;br /&gt;
Duplicate the working configuration from the old wiki.&lt;br /&gt;
&lt;br /&gt;
Only change:&lt;br /&gt;
* &amp;lt;code&amp;gt;server_name&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;proxy_pass&amp;lt;/code&amp;gt; target&lt;br /&gt;
* SSL certificate paths&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    server_name newwiki.example.com;&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://127.0.0.1:8080;&lt;br /&gt;
        proxy_set_header Host $host;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Run the MediaWiki Installer ==&lt;br /&gt;
Navigate to:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://newwiki.example.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Provide:&lt;br /&gt;
* Database name: &amp;lt;code&amp;gt;newwiki&amp;lt;/code&amp;gt;&lt;br /&gt;
* Database user: &amp;lt;code&amp;gt;newwikiuser&amp;lt;/code&amp;gt;&lt;br /&gt;
* Database password&lt;br /&gt;
* Site name&lt;br /&gt;
* Admin account&lt;br /&gt;
&lt;br /&gt;
Download the generated &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; and place it in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newwiki/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7. Minimal Post-Install Configuration ==&lt;br /&gt;
Add only the essential customizations.&lt;br /&gt;
&lt;br /&gt;
=== 7.1 URL Structure ===&lt;br /&gt;
Ensure these lines exist:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
$wgScriptPath = &amp;quot;&amp;quot;;&lt;br /&gt;
$wgArticlePath = &amp;quot;/wiki/$1&amp;quot;;&lt;br /&gt;
$wgUsePathInfo = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.2 Enable File Uploads (optional) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgEnableUploads = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.3 Install SyntaxHighlight (recommended) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;SyntaxHighlight_GeSHi&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.4 Create Custom Namespaces (optional) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define(&amp;quot;NS_TECH&amp;quot;, 3000);&lt;br /&gt;
define(&amp;quot;NS_TECH_TALK&amp;quot;, 3001);&lt;br /&gt;
$wgExtraNamespaces[NS_TECH] = &amp;quot;Tech&amp;quot;;&lt;br /&gt;
$wgNamespacesWithSubpages[NS_TECH] = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Testing Checklist ==&lt;br /&gt;
Verify:&lt;br /&gt;
* &amp;lt;code&amp;gt;/wiki/Main_Page&amp;lt;/code&amp;gt; loads correctly&lt;br /&gt;
* Editing works&lt;br /&gt;
* File uploads work (if enabled)&lt;br /&gt;
* Categories work&lt;br /&gt;
* Subpages work in custom namespaces&lt;br /&gt;
* Reverse-proxy preserves Host header&lt;br /&gt;
* No rewrite errors in Apache logs&lt;br /&gt;
&lt;br /&gt;
== 9. Backup Checklist ==&lt;br /&gt;
Create a backup routine for:&lt;br /&gt;
* &amp;lt;code&amp;gt;/var/www/newwiki&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt;&lt;br /&gt;
* MariaDB database &amp;lt;code&amp;gt;newwiki&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 10. Maintenance Notes ==&lt;br /&gt;
* MediaWiki 1.43 is LTS until December 2027.&lt;br /&gt;
* Apply security updates within the 1.43 branch.&lt;br /&gt;
* Avoid unnecessary extensions to keep the system stable.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:MW_Clean_installation_checklist_version_1.43_LTS&amp;diff=1605</id>
		<title>ICT:MW Clean installation checklist version 1.43 LTS</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:MW_Clean_installation_checklist_version_1.43_LTS&amp;diff=1605"/>
		<updated>2026-04-03T11:07:58Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;= Installation Checklist – MediaWiki 1.43 LTS = This document provides a clean, reproducible installation procedure for MediaWiki 1.43 LTS on AlmaLinux with Apache, PHP, MariaDB, and an nginx reverse-proxy. It is designed for long-term stability and successor-friendly maintenance.  == 1. Preparation == Before installing MediaWiki, ensure the server environment is ready.  === 1.1 System Requirements === * AlmaLinux (or compatible RHEL-based system) * Apache (httpd) * PH...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation Checklist – MediaWiki 1.43 LTS =&lt;br /&gt;
This document provides a clean, reproducible installation procedure for&lt;br /&gt;
MediaWiki 1.43 LTS on AlmaLinux with Apache, PHP, MariaDB, and an nginx&lt;br /&gt;
reverse-proxy. It is designed for long-term stability and successor-friendly&lt;br /&gt;
maintenance.&lt;br /&gt;
&lt;br /&gt;
== 1. Preparation ==&lt;br /&gt;
Before installing MediaWiki, ensure the server environment is ready.&lt;br /&gt;
&lt;br /&gt;
=== 1.1 System Requirements ===&lt;br /&gt;
* AlmaLinux (or compatible RHEL-based system)&lt;br /&gt;
* Apache (httpd)&lt;br /&gt;
* PHP 8.1 or later&lt;br /&gt;
* MariaDB 10.5 or later&lt;br /&gt;
* nginx reverse-proxy (optional but recommended)&lt;br /&gt;
* SELinux/AppArmor configured or disabled as needed&lt;br /&gt;
&lt;br /&gt;
=== 1.2 Install Required Packages ===&lt;br /&gt;
Install PHP and required extensions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dnf install php php-mbstring php-xml php-intl php-mysqlnd php-gd php-json php-cli php-opcache php-apcu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install Apache and MariaDB:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dnf install httpd mariadb-server&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Enable and start services:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl enable --now httpd mariadb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Database Setup ==&lt;br /&gt;
Create a clean database for the new wiki.&lt;br /&gt;
&lt;br /&gt;
=== 2.1 Secure MariaDB ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql_secure_installation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2.2 Create Database and User ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE DATABASE newwiki CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;&lt;br /&gt;
CREATE USER &#039;newwikiuser&#039;@&#039;localhost&#039; IDENTIFIED BY &#039;strongpassword&#039;;&lt;br /&gt;
GRANT ALL PRIVILEGES ON newwiki.* TO &#039;newwikiuser&#039;@&#039;localhost&#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Download MediaWiki 1.43 LTS ==&lt;br /&gt;
Download and extract the LTS release.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /var/www&lt;br /&gt;
wget https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.0.tar.gz&lt;br /&gt;
tar -xvzf mediawiki-1.43.0.tar.gz&lt;br /&gt;
mv mediawiki-1.43.0 newwiki&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set permissions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chown -R apache:apache /var/www/newwiki&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 4. Apache Virtual Host ==&lt;br /&gt;
Create a dedicated vhost for the new wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;VirtualHost *:8080&amp;gt;&lt;br /&gt;
    ServerName newwiki.example.com&lt;br /&gt;
    DocumentRoot /var/www/newwiki&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Directory /var/www/newwiki&amp;gt;&lt;br /&gt;
        AllowOverride All&lt;br /&gt;
        Require all granted&lt;br /&gt;
    &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    ErrorLog /var/log/httpd/newwiki-error.log&lt;br /&gt;
    CustomLog /var/log/httpd/newwiki-access.log combined&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Enable the site and restart Apache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl restart httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. nginx Reverse-Proxy ==&lt;br /&gt;
Duplicate the working configuration from the old wiki.&lt;br /&gt;
&lt;br /&gt;
Only change:&lt;br /&gt;
* &amp;lt;code&amp;gt;server_name&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;proxy_pass&amp;lt;/code&amp;gt; target&lt;br /&gt;
* SSL certificate paths&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
    listen 80;&lt;br /&gt;
    server_name newwiki.example.com;&lt;br /&gt;
&lt;br /&gt;
    location / {&lt;br /&gt;
        proxy_pass http://127.0.0.1:8080;&lt;br /&gt;
        proxy_set_header Host $host;&lt;br /&gt;
        proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reload nginx:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Run the MediaWiki Installer ==&lt;br /&gt;
Navigate to:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://newwiki.example.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Provide:&lt;br /&gt;
* Database name: &amp;lt;code&amp;gt;newwiki&amp;lt;/code&amp;gt;&lt;br /&gt;
* Database user: &amp;lt;code&amp;gt;newwikiuser&amp;lt;/code&amp;gt;&lt;br /&gt;
* Database password&lt;br /&gt;
* Site name&lt;br /&gt;
* Admin account&lt;br /&gt;
&lt;br /&gt;
Download the generated &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt; and place it in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/www/newwiki/LocalSettings.php&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7. Minimal Post-Install Configuration ==&lt;br /&gt;
Add only the essential customizations.&lt;br /&gt;
&lt;br /&gt;
=== 7.1 URL Structure ===&lt;br /&gt;
Ensure these lines exist:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgServer = &amp;quot;https://newwiki.example.com&amp;quot;;&lt;br /&gt;
$wgScriptPath = &amp;quot;&amp;quot;;&lt;br /&gt;
$wgArticlePath = &amp;quot;/wiki/$1&amp;quot;;&lt;br /&gt;
$wgUsePathInfo = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.2 Enable File Uploads (optional) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$wgEnableUploads = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.3 Install SyntaxHighlight (recommended) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;SyntaxHighlight_GeSHi&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7.4 Create Custom Namespaces (optional) ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define(&amp;quot;NS_TECH&amp;quot;, 3000);&lt;br /&gt;
define(&amp;quot;NS_TECH_TALK&amp;quot;, 3001);&lt;br /&gt;
$wgExtraNamespaces[NS_TECH] = &amp;quot;Tech&amp;quot;;&lt;br /&gt;
$wgNamespacesWithSubpages[NS_TECH] = true;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Testing Checklist ==&lt;br /&gt;
Verify:&lt;br /&gt;
* &amp;lt;code&amp;gt;/wiki/Main_Page&amp;lt;/code&amp;gt; loads correctly&lt;br /&gt;
* Editing works&lt;br /&gt;
* File uploads work (if enabled)&lt;br /&gt;
* Categories work&lt;br /&gt;
* Subpages work in custom namespaces&lt;br /&gt;
* Reverse-proxy preserves Host header&lt;br /&gt;
* No rewrite errors in Apache logs&lt;br /&gt;
&lt;br /&gt;
== 9. Backup Checklist ==&lt;br /&gt;
Create a backup routine for:&lt;br /&gt;
* &amp;lt;code&amp;gt;/var/www/newwiki&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;LocalSettings.php&amp;lt;/code&amp;gt;&lt;br /&gt;
* MariaDB database &amp;lt;code&amp;gt;newwiki&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 10. Maintenance Notes ==&lt;br /&gt;
* MediaWiki 1.43 is LTS until December 2027.&lt;br /&gt;
* Apply security updates within the 1.43 branch.&lt;br /&gt;
* Avoid unnecessary extensions to keep the system stable.&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=File:drupal_flow_0_reverse.gif&amp;diff=1426</id>
		<title>File:drupal flow 0 reverse.gif</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=File:drupal_flow_0_reverse.gif&amp;diff=1426"/>
		<updated>2026-02-27T20:46:33Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Drupal Flow in Layers&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Drupal Flow in Layers&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:FinalConfig_-_Asset_-_v2.3_design_proposal&amp;diff=1416</id>
		<title>ICT:FinalConfig - Asset - v2.3 design proposal</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:FinalConfig_-_Asset_-_v2.3_design_proposal&amp;diff=1416"/>
		<updated>2026-02-22T22:42:17Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Asset v2.3 – Lifecycle Proposal =&lt;br /&gt;
&lt;br /&gt;
== 0. Purpose of this Document ==&lt;br /&gt;
This document defines **Asset v2.3**, a stabilization and completion step of the Asset v2.x line.&lt;br /&gt;
&lt;br /&gt;
Its purposes are:&lt;br /&gt;
* Serve as a **conceptual study document**&lt;br /&gt;
* Provide a **clear implementation guide**&lt;br /&gt;
* Act as a **baseline for validation and later fine-tuning**&lt;br /&gt;
&lt;br /&gt;
Asset v2.3 does not introduce new concepts.  &lt;br /&gt;
It reorganizes responsibilities, clarifies lifecycle phases, and resolves ambiguities identified in Asset v2.1.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 1. Locked Runtime Baseline (Unchanged) ==&lt;br /&gt;
The following environment and assumptions are **strictly locked** and MUST NOT change during Asset v2.x development:&lt;br /&gt;
&lt;br /&gt;
* OS: AlmaLinux 10.1&lt;br /&gt;
* PHP: 8.3&lt;br /&gt;
* MediaWiki: 1.45.x&lt;br /&gt;
* Page Forms: 6.x&lt;br /&gt;
* Cargo (external database)&lt;br /&gt;
* Scribunto: Lua 5.1 (Lua 5.4 explicitly excluded)&lt;br /&gt;
* Private MediaWiki installation&lt;br /&gt;
&lt;br /&gt;
Normative constraints:&lt;br /&gt;
* One Asset = exactly one digital file&lt;br /&gt;
* Asset identifier immutability&lt;br /&gt;
* Compatibility with existing Asset v2.1 data&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 2. Core Principle (Reaffirmed) ==&lt;br /&gt;
&#039;&#039;An Asset is immutable after finalization.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Immutability applies to:&lt;br /&gt;
* Asset identifier (page name)&lt;br /&gt;
* Label&lt;br /&gt;
* Chapter&lt;br /&gt;
* Place / Organisation&lt;br /&gt;
* File&lt;br /&gt;
* OriginalFilename&lt;br /&gt;
&lt;br /&gt;
All other descriptive metadata MAY be edited after finalization.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 3. Explicit Asset Lifecycle (Normative) ==&lt;br /&gt;
Asset v2.3 introduces a **three-phase lifecycle**.&lt;br /&gt;
Each phase has a single responsibility and MUST NOT overlap with others.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Phase A – Draft Creation ===&lt;br /&gt;
&#039;&#039;&#039;Goal:&#039;&#039;&#039; Safely persist user input without committing archival identity.&lt;br /&gt;
&lt;br /&gt;
Characteristics:&lt;br /&gt;
* Page name: timestamp-based (e.g. &amp;lt;code&amp;gt;Asset:20260222194733&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Status: &amp;lt;code&amp;gt;DRAFT&amp;lt;/code&amp;gt;&lt;br /&gt;
* Identifier: placeholder (&amp;lt;code&amp;gt;GENERATING…&amp;lt;/code&amp;gt;)&lt;br /&gt;
* File: uploaded under original filename&lt;br /&gt;
&lt;br /&gt;
Allowed actions:&lt;br /&gt;
* Upload file&lt;br /&gt;
* Select Chapter&lt;br /&gt;
* Select Place or Organisation&lt;br /&gt;
* Enter descriptive metadata&lt;br /&gt;
&lt;br /&gt;
Forbidden actions:&lt;br /&gt;
* Identifier generation&lt;br /&gt;
* File renaming&lt;br /&gt;
* Page moving&lt;br /&gt;
&lt;br /&gt;
Rules:&lt;br /&gt;
* Draft pages MUST NOT appear in dashboards&lt;br /&gt;
* Draft pages MUST NOT be queried as Assets&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Phase B – Finalization ===&lt;br /&gt;
&#039;&#039;&#039;Goal:&#039;&#039;&#039; Atomically transform a Draft Asset into a Final Asset.&lt;br /&gt;
&lt;br /&gt;
Phase B is the ONLY phase in which identity is assigned.&lt;br /&gt;
It MUST execute exactly once per Asset.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Preconditions ====&lt;br /&gt;
All of the following MUST be true before Phase B starts:&lt;br /&gt;
&lt;br /&gt;
* Asset page exists&lt;br /&gt;
* &amp;lt;code&amp;gt;Status = DRAFT&amp;lt;/code&amp;gt;&lt;br /&gt;
* Required fields present:&lt;br /&gt;
** Chapter&lt;br /&gt;
** Place OR Organisation&lt;br /&gt;
** File&lt;br /&gt;
* No final identifier has been assigned&lt;br /&gt;
&lt;br /&gt;
If any precondition fails, Phase B MUST NOT start.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Trigger ====&lt;br /&gt;
Phase B is triggered by an explicit user action&lt;br /&gt;
(e.g. a “Finalize Asset” control).&lt;br /&gt;
&lt;br /&gt;
Automatic finalization is forbidden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Atomic Actions (execution order) ====&lt;br /&gt;
The following steps form a single atomic operation:&lt;br /&gt;
&lt;br /&gt;
# Compute next sequence number (contextual)&lt;br /&gt;
# Generate final Asset identifier&lt;br /&gt;
# Rename file to match final identifier&lt;br /&gt;
# Move Asset page to final title&lt;br /&gt;
# Persist final Cargo data&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Status = FINAL&amp;lt;/code&amp;gt;&lt;br /&gt;
# Lock immutable fields&lt;br /&gt;
&lt;br /&gt;
If any step fails:&lt;br /&gt;
* ALL changes MUST be aborted&lt;br /&gt;
* No partial state is allowed&lt;br /&gt;
* The failure MUST be logged&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Rules ====&lt;br /&gt;
* Phase B MUST run exactly once&lt;br /&gt;
* Re-finalization is forbidden&lt;br /&gt;
* Partial finalization is forbidden&lt;br /&gt;
* Identifier and sequence allocation occur ONLY in Phase B&lt;br /&gt;
* Page move and file rename occur ONLY in Phase B&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Resulting State ====&lt;br /&gt;
After successful Phase B:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Status = FINAL&amp;lt;/code&amp;gt;&lt;br /&gt;
* Asset identifier is permanent&lt;br /&gt;
* File name is permanent&lt;br /&gt;
* Asset becomes visible on dashboards&lt;br /&gt;
* Immutable fields are locked&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Explicitly Forbidden ====&lt;br /&gt;
* Running Phase B on a FINAL Asset&lt;br /&gt;
* Changing immutable fields after Phase B&lt;br /&gt;
* Skipping or reordering atomic steps&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Phase C – Post-Final Editing ===&lt;br /&gt;
&#039;&#039;&#039;Goal:&#039;&#039;&#039; Allow safe metadata enrichment without identity corruption.&lt;br /&gt;
&lt;br /&gt;
Allowed:&lt;br /&gt;
* Description updates&lt;br /&gt;
* Notes&lt;br /&gt;
* Parent asset relations&lt;br /&gt;
&lt;br /&gt;
Forbidden:&lt;br /&gt;
* Any change to immutable fields&lt;br /&gt;
* File replacement or rename&lt;br /&gt;
* Page move&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 4. Explicit Status Field (New) ==&lt;br /&gt;
Asset v2.3 introduces a mandatory field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Status = DRAFT | FINAL&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose:&lt;br /&gt;
* Remove implicit draft detection&lt;br /&gt;
* Control lifecycle hook execution&lt;br /&gt;
* Prevent accidental re-finalization&lt;br /&gt;
&lt;br /&gt;
The Status field is authoritative.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 5. Identifier and Sequence Generation (Clarified) ==&lt;br /&gt;
Identifier format remains unchanged:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;ChapterCode&amp;gt;-&amp;lt;ContextCode&amp;gt;-&amp;lt;SequenceNumber&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules:&lt;br /&gt;
* Sequence numbers are allocated ONLY during Phase B&lt;br /&gt;
* Numbers are never reused&lt;br /&gt;
* Gaps are allowed&lt;br /&gt;
* Counter logic is centralized&lt;br /&gt;
&lt;br /&gt;
Sequence allocation MUST be implemented as a single isolated function.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 6. Hook Responsibility Separation ==&lt;br /&gt;
Asset v2.3 enforces strict separation of concerns.&lt;br /&gt;
&lt;br /&gt;
Hooks MUST NOT:&lt;br /&gt;
* Parse wikitext for authoritative decisions&lt;br /&gt;
* Combine extraction, mutation, and page/file movement&lt;br /&gt;
* Decide identity before save completion&lt;br /&gt;
&lt;br /&gt;
Hooks SHOULD:&lt;br /&gt;
* Detect lifecycle phase&lt;br /&gt;
* Validate preconditions&lt;br /&gt;
* Delegate work to dedicated functions&lt;br /&gt;
&lt;br /&gt;
Wikitext inspection MAY be used for diagnostics only.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 7. Page Move Strategy ==&lt;br /&gt;
Page moves are explicitly **post-save operations**.&lt;br /&gt;
&lt;br /&gt;
Rationale:&lt;br /&gt;
* MediaWiki requires stable content before moving pages&lt;br /&gt;
* Page Forms target manipulation is fragile&lt;br /&gt;
&lt;br /&gt;
Rule:&lt;br /&gt;
&#039;&#039;A page MUST exist before it is moved.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 8. File Handling Strategy ==&lt;br /&gt;
* File upload occurs in Phase A&lt;br /&gt;
* File rename occurs only in Phase B&lt;br /&gt;
* Original filename is captured exactly once&lt;br /&gt;
&lt;br /&gt;
After Phase B:&lt;br /&gt;
* File becomes immutable&lt;br /&gt;
* Further file operations are forbidden&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 9. Dashboard Visibility Rules ==&lt;br /&gt;
* &amp;lt;code&amp;gt;Status = DRAFT&amp;lt;/code&amp;gt; → hidden&lt;br /&gt;
* &amp;lt;code&amp;gt;Status = FINAL&amp;lt;/code&amp;gt; → visible&lt;br /&gt;
&lt;br /&gt;
Dashboards MUST display only finalized Assets.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 10. Migration and Compatibility ==&lt;br /&gt;
Asset v2.3:&lt;br /&gt;
* Does NOT invalidate Asset v2.1 Assets&lt;br /&gt;
* Introduces no breaking schema changes&lt;br /&gt;
* Adds lifecycle clarity without requiring data migration&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 11. Status ==&lt;br /&gt;
Asset v2.3 is a **design-level proposal**.&lt;br /&gt;
&lt;br /&gt;
Next steps:&lt;br /&gt;
# Study and validate lifecycle clarity&lt;br /&gt;
# Implement Phase separation in the private extension&lt;br /&gt;
# Test finalization robustness&lt;br /&gt;
# Fine-tune UX only after correctness is proven&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;End of first part of document&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
------Actual status --------------&lt;br /&gt;
&lt;br /&gt;
= Asset v2.3 – Current Working State (Checkpoint) =&lt;br /&gt;
&#039;&#039;Date: 2026-02-22&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This page documents the **last known good state** of the Asset v2.3 system.&lt;br /&gt;
It exists to allow safe recovery if later experiments break functionality.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Scope ==&lt;br /&gt;
This document describes:&lt;br /&gt;
* What is implemented and validated&lt;br /&gt;
* What is intentionally NOT implemented yet&lt;br /&gt;
* Which architectural decisions are locked&lt;br /&gt;
* Where development must resume next&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Environment (Locked) ==&lt;br /&gt;
* MediaWiki 1.45.x&lt;br /&gt;
* Page Forms 6.x&lt;br /&gt;
* Cargo (external database)&lt;br /&gt;
* PHP 8.3&lt;br /&gt;
* AlmaLinux&lt;br /&gt;
* Private MediaWiki installation&lt;br /&gt;
&lt;br /&gt;
These were tested together and MUST NOT be changed mid-development.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. Asset Lifecycle (Current Implementation) ==&lt;br /&gt;
&lt;br /&gt;
=== Phase A – Draft Creation (IMPLEMENTED) ===&lt;br /&gt;
* Assets are created via Dashboard + Form:Asset&lt;br /&gt;
* Page name is timestamp-based (e.g. Asset:20260222222722)&lt;br /&gt;
* File is uploaded under its original filename&lt;br /&gt;
* Identifier is placeholder: &amp;lt;code&amp;gt;GENERATING...&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== READY State (IMPLEMENTED) ===&lt;br /&gt;
READY is a **technical gate**, not a lifecycle phase.&lt;br /&gt;
&lt;br /&gt;
Status transitions:&lt;br /&gt;
* &amp;lt;code&amp;gt;DRAFT&amp;lt;/code&amp;gt; → incomplete&lt;br /&gt;
* &amp;lt;code&amp;gt;READY&amp;lt;/code&amp;gt; → all required fields present&lt;br /&gt;
&lt;br /&gt;
Required fields:&lt;br /&gt;
* Chapter&lt;br /&gt;
* Place OR Organisation&lt;br /&gt;
* File&lt;br /&gt;
&lt;br /&gt;
READY detection is:&lt;br /&gt;
* Automatic&lt;br /&gt;
* Hook-based&lt;br /&gt;
* User-invisible&lt;br /&gt;
* Reversible&lt;br /&gt;
&lt;br /&gt;
READY assets are still hidden from dashboards.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. What Is Explicitly NOT Implemented Yet ==&lt;br /&gt;
* Phase B (Finalization)&lt;br /&gt;
* Identifier generation&lt;br /&gt;
* Sequence allocation&lt;br /&gt;
* File rename&lt;br /&gt;
* Page move&lt;br /&gt;
* Cargo writes during finalization&lt;br /&gt;
* Dashboard visibility of Assets&lt;br /&gt;
&lt;br /&gt;
This is intentional.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5. Dashboard Rules (Locked) ==&lt;br /&gt;
Dashboards show:&lt;br /&gt;
* ONLY &amp;lt;code&amp;gt;Status = FINAL&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dashboards hide:&lt;br /&gt;
* &amp;lt;code&amp;gt;DRAFT&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;READY&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dashboard emptiness at this stage is CORRECT.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 6. Hook Architecture (Critical Knowledge) ==&lt;br /&gt;
&lt;br /&gt;
=== The ONLY Hook Used ===&lt;br /&gt;
&amp;lt;code&amp;gt;PageForms::WritePageData&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Correct and tested signature:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
onPFWritePageData( $formName, $title, &amp;amp;$wikitext )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Important rules:&lt;br /&gt;
* NO type hints in parameters&lt;br /&gt;
* Hook fires BEFORE page creation&lt;br /&gt;
* Hook MUST NOT assume page exists&lt;br /&gt;
&lt;br /&gt;
=== What the Hook Does ===&lt;br /&gt;
* Reads fields from wikitext&lt;br /&gt;
* Computes READY vs DRAFT&lt;br /&gt;
* Writes &amp;lt;code&amp;gt;Status&amp;lt;/code&amp;gt; back into wikitext&lt;br /&gt;
* Writes debug logs&lt;br /&gt;
&lt;br /&gt;
=== What the Hook MUST NOT Do ===&lt;br /&gt;
* Write to Cargo&lt;br /&gt;
* Rename files&lt;br /&gt;
* Move pages&lt;br /&gt;
* Trigger second saves&lt;br /&gt;
* Perform Phase B logic&lt;br /&gt;
&lt;br /&gt;
Violating these rules caused page creation to fail.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 7. Logging ==&lt;br /&gt;
A debug log is used to confirm hook execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/var/www/mediawiki/hook_debug.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typical successful output:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
PF WritePageData fired: Asset:20260222222722&lt;br /&gt;
Fields: Chapter=&#039;CH02&#039;, Place=&#039;BRUG&#039;, Org=&#039;&#039;, File=&#039;Berck-Casino-371-ai.jpg&#039;&lt;br /&gt;
Computed status: READY&lt;br /&gt;
Wikitext Status updated&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If logs stop appearing:&lt;br /&gt;
* The hook signature is wrong&lt;br /&gt;
* Or the extension is not loaded&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 8. Current Stable Code Reference ==&lt;br /&gt;
The current working hook:&lt;br /&gt;
* Updates wikitext only&lt;br /&gt;
* Does not touch Cargo&lt;br /&gt;
* Does not break saves&lt;br /&gt;
&lt;br /&gt;
This state is backed up via full VM disk copies.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 9. Known UX Side Effect ==&lt;br /&gt;
Because wikitext is modified in the Page Forms hook:&lt;br /&gt;
* MediaWiki shows the classic save confirmation screen&lt;br /&gt;
&lt;br /&gt;
This is acceptable for now.&lt;br /&gt;
It will be removed later during Phase B refactoring.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 10. Where to Resume Development ==&lt;br /&gt;
Next work session must start with:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Phase B – Finalization&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Specifically:&lt;br /&gt;
* Trigger from the form (Finalize Asset button)&lt;br /&gt;
* Post-save logic only&lt;br /&gt;
* Atomic operations:&lt;br /&gt;
** sequence allocation&lt;br /&gt;
** identifier generation&lt;br /&gt;
** file rename&lt;br /&gt;
** page move&lt;br /&gt;
** Cargo persistence&lt;br /&gt;
&lt;br /&gt;
Phase A MUST NOT be modified further.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;End of checkpoint document&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=Asset:20260222222722&amp;diff=1415</id>
		<title>Asset:20260222222722</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=Asset:20260222222722&amp;diff=1415"/>
		<updated>2026-02-22T22:28:15Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;{{Asset |Status=READY |Chapter=CH02 |Place=BRUG |Label=GENERATING... |File=Berck-Casino-371-ai.jpg |Description=T |Notes=T }}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Asset&lt;br /&gt;
|Status=READY&lt;br /&gt;
|Chapter=CH02&lt;br /&gt;
|Place=BRUG&lt;br /&gt;
|Label=GENERATING...&lt;br /&gt;
|File=Berck-Casino-371-ai.jpg&lt;br /&gt;
|Description=T&lt;br /&gt;
|Notes=T&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=File:Berck-Casino-371-ai.jpg&amp;diff=1414</id>
		<title>File:Berck-Casino-371-ai.jpg</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=File:Berck-Casino-371-ai.jpg&amp;diff=1414"/>
		<updated>2026-02-22T22:28:06Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=File:Berck-Casino-370-ai.jpg&amp;diff=1413</id>
		<title>File:Berck-Casino-370-ai.jpg</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=File:Berck-Casino-370-ai.jpg&amp;diff=1413"/>
		<updated>2026-02-22T21:15:33Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=File:Berck-553-ai.jpg&amp;diff=1412</id>
		<title>File:Berck-553-ai.jpg</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=File:Berck-553-ai.jpg&amp;diff=1412"/>
		<updated>2026-02-22T21:08:32Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=Asset:20260222203155&amp;diff=1411</id>
		<title>Asset:20260222203155</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=Asset:20260222203155&amp;diff=1411"/>
		<updated>2026-02-22T20:32:30Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;{{Asset |Status=DRAFT |Chapter=CH01 |Place=AMER |Label=GENERATING... |File=Berck-548-ai.jpg }}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Asset&lt;br /&gt;
|Status=DRAFT&lt;br /&gt;
|Chapter=CH01&lt;br /&gt;
|Place=AMER&lt;br /&gt;
|Label=GENERATING...&lt;br /&gt;
|File=Berck-548-ai.jpg&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=File:Berck-548-ai.jpg&amp;diff=1410</id>
		<title>File:Berck-548-ai.jpg</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=File:Berck-548-ai.jpg&amp;diff=1410"/>
		<updated>2026-02-22T20:32:23Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=Asset:20260222202132&amp;diff=1409</id>
		<title>Asset:20260222202132</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=Asset:20260222202132&amp;diff=1409"/>
		<updated>2026-02-22T20:22:24Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;{{Asset |Status=DRAFT |Chapter=CH00 |Place=ALTO |Label=GENERATING... |File=Berck-547-ai.jpg }}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Asset&lt;br /&gt;
|Status=DRAFT&lt;br /&gt;
|Chapter=CH00&lt;br /&gt;
|Place=ALTO&lt;br /&gt;
|Label=GENERATING...&lt;br /&gt;
|File=Berck-547-ai.jpg&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=File:Berck-547-ai.jpg&amp;diff=1408</id>
		<title>File:Berck-547-ai.jpg</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=File:Berck-547-ai.jpg&amp;diff=1408"/>
		<updated>2026-02-22T20:22:03Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=Form:Asset&amp;diff=1407</id>
		<title>Form:Asset</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=Form:Asset&amp;diff=1407"/>
		<updated>2026-02-22T20:04:45Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
Form for creating and editing Asset pages (v2.3 – Phase A, Phase-B-ready)&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{{info&lt;br /&gt;
|page name=Asset:&amp;lt;Asset[Label]&amp;gt;&lt;br /&gt;
|no summary&lt;br /&gt;
|no preview&lt;br /&gt;
|no minor edit&lt;br /&gt;
|no watch&lt;br /&gt;
|no footer&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
{{{for template|Asset}}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;formtable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
! Status&lt;br /&gt;
| {{{field|Status|readonly|default=DRAFT}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Chapter (*)&lt;br /&gt;
| {{{field|Chapter&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Chapter&lt;br /&gt;
 |existing values only&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Place&lt;br /&gt;
| {{{field|Place&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Place&lt;br /&gt;
 |existing values only&lt;br /&gt;
 |placeholder=Use Organisation instead&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Organisation&lt;br /&gt;
| {{{field|Organisation&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Organisation&lt;br /&gt;
 |existing values only&lt;br /&gt;
 |placeholder=Use Place instead&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Identifier&lt;br /&gt;
| {{{field|Label|readonly}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Sequence&lt;br /&gt;
| {{{field|Sequence|readonly}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! File&lt;br /&gt;
| {{{field|File&lt;br /&gt;
 |input type=page&lt;br /&gt;
 |namespace=File&lt;br /&gt;
 |uploadable=yes&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Original filename&lt;br /&gt;
| {{{field|OriginalFilename|readonly}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Asset type&lt;br /&gt;
| {{{field|AssetType&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=AssetType&lt;br /&gt;
 |existing values only&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Parent asset&lt;br /&gt;
| {{{field|Parent&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Asset&lt;br /&gt;
 |existing values only&lt;br /&gt;
 |placeholder=Top level&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Description&lt;br /&gt;
| {{{field|Description|input type=textarea}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Notes&lt;br /&gt;
| {{{field|Notes|input type=textarea}}}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Phase A trigger --&amp;gt;&lt;br /&gt;
{{#ifeq: {{{Status|DRAFT}}} | DRAFT |&lt;br /&gt;
{{{standard input|save|label=Save Draft}}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Phase B trigger (visible only later, logic added in next step) --&amp;gt;&lt;br /&gt;
{{#ifeq: {{{Status|}}} | READY |&lt;br /&gt;
{{{standard input|save|label=🔒 Finalize Asset (irreversible)}}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{{end template}}}&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:FinalConfig_-_Asset_-_v2.3_design_proposal&amp;diff=1406</id>
		<title>ICT:FinalConfig - Asset - v2.3 design proposal</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:FinalConfig_-_Asset_-_v2.3_design_proposal&amp;diff=1406"/>
		<updated>2026-02-22T19:46:51Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Asset v2.3 – Lifecycle Proposal =&lt;br /&gt;
&lt;br /&gt;
== 0. Purpose of this Document ==&lt;br /&gt;
This document defines **Asset v2.3**, a stabilization and completion step of the Asset v2.x line.&lt;br /&gt;
&lt;br /&gt;
Its purposes are:&lt;br /&gt;
* Serve as a **conceptual study document**&lt;br /&gt;
* Provide a **clear implementation guide**&lt;br /&gt;
* Act as a **baseline for validation and later fine-tuning**&lt;br /&gt;
&lt;br /&gt;
Asset v2.3 does not introduce new concepts.  &lt;br /&gt;
It reorganizes responsibilities, clarifies lifecycle phases, and resolves ambiguities identified in Asset v2.1.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 1. Locked Runtime Baseline (Unchanged) ==&lt;br /&gt;
The following environment and assumptions are **strictly locked** and MUST NOT change during Asset v2.x development:&lt;br /&gt;
&lt;br /&gt;
* OS: AlmaLinux 10.1&lt;br /&gt;
* PHP: 8.3&lt;br /&gt;
* MediaWiki: 1.45.x&lt;br /&gt;
* Page Forms: 6.x&lt;br /&gt;
* Cargo (external database)&lt;br /&gt;
* Scribunto: Lua 5.1 (Lua 5.4 explicitly excluded)&lt;br /&gt;
* Private MediaWiki installation&lt;br /&gt;
&lt;br /&gt;
Normative constraints:&lt;br /&gt;
* One Asset = exactly one digital file&lt;br /&gt;
* Asset identifier immutability&lt;br /&gt;
* Compatibility with existing Asset v2.1 data&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 2. Core Principle (Reaffirmed) ==&lt;br /&gt;
&#039;&#039;An Asset is immutable after finalization.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Immutability applies to:&lt;br /&gt;
* Asset identifier (page name)&lt;br /&gt;
* Label&lt;br /&gt;
* Chapter&lt;br /&gt;
* Place / Organisation&lt;br /&gt;
* File&lt;br /&gt;
* OriginalFilename&lt;br /&gt;
&lt;br /&gt;
All other descriptive metadata MAY be edited after finalization.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 3. Explicit Asset Lifecycle (Normative) ==&lt;br /&gt;
Asset v2.3 introduces a **three-phase lifecycle**.&lt;br /&gt;
Each phase has a single responsibility and MUST NOT overlap with others.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Phase A – Draft Creation ===&lt;br /&gt;
&#039;&#039;&#039;Goal:&#039;&#039;&#039; Safely persist user input without committing archival identity.&lt;br /&gt;
&lt;br /&gt;
Characteristics:&lt;br /&gt;
* Page name: timestamp-based (e.g. &amp;lt;code&amp;gt;Asset:20260222194733&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Status: &amp;lt;code&amp;gt;DRAFT&amp;lt;/code&amp;gt;&lt;br /&gt;
* Identifier: placeholder (&amp;lt;code&amp;gt;GENERATING…&amp;lt;/code&amp;gt;)&lt;br /&gt;
* File: uploaded under original filename&lt;br /&gt;
&lt;br /&gt;
Allowed actions:&lt;br /&gt;
* Upload file&lt;br /&gt;
* Select Chapter&lt;br /&gt;
* Select Place or Organisation&lt;br /&gt;
* Enter descriptive metadata&lt;br /&gt;
&lt;br /&gt;
Forbidden actions:&lt;br /&gt;
* Identifier generation&lt;br /&gt;
* File renaming&lt;br /&gt;
* Page moving&lt;br /&gt;
&lt;br /&gt;
Rules:&lt;br /&gt;
* Draft pages MUST NOT appear in dashboards&lt;br /&gt;
* Draft pages MUST NOT be queried as Assets&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Phase B – Finalization ===&lt;br /&gt;
&#039;&#039;&#039;Goal:&#039;&#039;&#039; Atomically transform a Draft Asset into a Final Asset.&lt;br /&gt;
&lt;br /&gt;
Phase B is the ONLY phase in which identity is assigned.&lt;br /&gt;
It MUST execute exactly once per Asset.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Preconditions ====&lt;br /&gt;
All of the following MUST be true before Phase B starts:&lt;br /&gt;
&lt;br /&gt;
* Asset page exists&lt;br /&gt;
* &amp;lt;code&amp;gt;Status = DRAFT&amp;lt;/code&amp;gt;&lt;br /&gt;
* Required fields present:&lt;br /&gt;
** Chapter&lt;br /&gt;
** Place OR Organisation&lt;br /&gt;
** File&lt;br /&gt;
* No final identifier has been assigned&lt;br /&gt;
&lt;br /&gt;
If any precondition fails, Phase B MUST NOT start.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Trigger ====&lt;br /&gt;
Phase B is triggered by an explicit user action&lt;br /&gt;
(e.g. a “Finalize Asset” control).&lt;br /&gt;
&lt;br /&gt;
Automatic finalization is forbidden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Atomic Actions (execution order) ====&lt;br /&gt;
The following steps form a single atomic operation:&lt;br /&gt;
&lt;br /&gt;
# Compute next sequence number (contextual)&lt;br /&gt;
# Generate final Asset identifier&lt;br /&gt;
# Rename file to match final identifier&lt;br /&gt;
# Move Asset page to final title&lt;br /&gt;
# Persist final Cargo data&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Status = FINAL&amp;lt;/code&amp;gt;&lt;br /&gt;
# Lock immutable fields&lt;br /&gt;
&lt;br /&gt;
If any step fails:&lt;br /&gt;
* ALL changes MUST be aborted&lt;br /&gt;
* No partial state is allowed&lt;br /&gt;
* The failure MUST be logged&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Rules ====&lt;br /&gt;
* Phase B MUST run exactly once&lt;br /&gt;
* Re-finalization is forbidden&lt;br /&gt;
* Partial finalization is forbidden&lt;br /&gt;
* Identifier and sequence allocation occur ONLY in Phase B&lt;br /&gt;
* Page move and file rename occur ONLY in Phase B&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Resulting State ====&lt;br /&gt;
After successful Phase B:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Status = FINAL&amp;lt;/code&amp;gt;&lt;br /&gt;
* Asset identifier is permanent&lt;br /&gt;
* File name is permanent&lt;br /&gt;
* Asset becomes visible on dashboards&lt;br /&gt;
* Immutable fields are locked&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== Explicitly Forbidden ====&lt;br /&gt;
* Running Phase B on a FINAL Asset&lt;br /&gt;
* Changing immutable fields after Phase B&lt;br /&gt;
* Skipping or reordering atomic steps&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Phase C – Post-Final Editing ===&lt;br /&gt;
&#039;&#039;&#039;Goal:&#039;&#039;&#039; Allow safe metadata enrichment without identity corruption.&lt;br /&gt;
&lt;br /&gt;
Allowed:&lt;br /&gt;
* Description updates&lt;br /&gt;
* Notes&lt;br /&gt;
* Parent asset relations&lt;br /&gt;
&lt;br /&gt;
Forbidden:&lt;br /&gt;
* Any change to immutable fields&lt;br /&gt;
* File replacement or rename&lt;br /&gt;
* Page move&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 4. Explicit Status Field (New) ==&lt;br /&gt;
Asset v2.3 introduces a mandatory field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Status = DRAFT | FINAL&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Purpose:&lt;br /&gt;
* Remove implicit draft detection&lt;br /&gt;
* Control lifecycle hook execution&lt;br /&gt;
* Prevent accidental re-finalization&lt;br /&gt;
&lt;br /&gt;
The Status field is authoritative.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 5. Identifier and Sequence Generation (Clarified) ==&lt;br /&gt;
Identifier format remains unchanged:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;ChapterCode&amp;gt;-&amp;lt;ContextCode&amp;gt;-&amp;lt;SequenceNumber&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules:&lt;br /&gt;
* Sequence numbers are allocated ONLY during Phase B&lt;br /&gt;
* Numbers are never reused&lt;br /&gt;
* Gaps are allowed&lt;br /&gt;
* Counter logic is centralized&lt;br /&gt;
&lt;br /&gt;
Sequence allocation MUST be implemented as a single isolated function.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 6. Hook Responsibility Separation ==&lt;br /&gt;
Asset v2.3 enforces strict separation of concerns.&lt;br /&gt;
&lt;br /&gt;
Hooks MUST NOT:&lt;br /&gt;
* Parse wikitext for authoritative decisions&lt;br /&gt;
* Combine extraction, mutation, and page/file movement&lt;br /&gt;
* Decide identity before save completion&lt;br /&gt;
&lt;br /&gt;
Hooks SHOULD:&lt;br /&gt;
* Detect lifecycle phase&lt;br /&gt;
* Validate preconditions&lt;br /&gt;
* Delegate work to dedicated functions&lt;br /&gt;
&lt;br /&gt;
Wikitext inspection MAY be used for diagnostics only.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 7. Page Move Strategy ==&lt;br /&gt;
Page moves are explicitly **post-save operations**.&lt;br /&gt;
&lt;br /&gt;
Rationale:&lt;br /&gt;
* MediaWiki requires stable content before moving pages&lt;br /&gt;
* Page Forms target manipulation is fragile&lt;br /&gt;
&lt;br /&gt;
Rule:&lt;br /&gt;
&#039;&#039;A page MUST exist before it is moved.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 8. File Handling Strategy ==&lt;br /&gt;
* File upload occurs in Phase A&lt;br /&gt;
* File rename occurs only in Phase B&lt;br /&gt;
* Original filename is captured exactly once&lt;br /&gt;
&lt;br /&gt;
After Phase B:&lt;br /&gt;
* File becomes immutable&lt;br /&gt;
* Further file operations are forbidden&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 9. Dashboard Visibility Rules ==&lt;br /&gt;
* &amp;lt;code&amp;gt;Status = DRAFT&amp;lt;/code&amp;gt; → hidden&lt;br /&gt;
* &amp;lt;code&amp;gt;Status = FINAL&amp;lt;/code&amp;gt; → visible&lt;br /&gt;
&lt;br /&gt;
Dashboards MUST display only finalized Assets.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 10. Migration and Compatibility ==&lt;br /&gt;
Asset v2.3:&lt;br /&gt;
* Does NOT invalidate Asset v2.1 Assets&lt;br /&gt;
* Introduces no breaking schema changes&lt;br /&gt;
* Adds lifecycle clarity without requiring data migration&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
== 11. Status ==&lt;br /&gt;
Asset v2.3 is a **design-level proposal**.&lt;br /&gt;
&lt;br /&gt;
Next steps:&lt;br /&gt;
# Study and validate lifecycle clarity&lt;br /&gt;
# Implement Phase separation in the private extension&lt;br /&gt;
# Test finalization robustness&lt;br /&gt;
# Fine-tune UX only after correctness is proven&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;End of document&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=Asset:20260222193244&amp;diff=1405</id>
		<title>Asset:20260222193244</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=Asset:20260222193244&amp;diff=1405"/>
		<updated>2026-02-22T19:36:25Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Created page with &amp;quot;{{Asset |Status=DRAFT |Chapter=CH00 |Place=ALTO |Label=CH00-ALTO-0001 |File=CH00-ALTO-0001.jpg |Description=TBD |Notes=TBD }}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Asset&lt;br /&gt;
|Status=DRAFT&lt;br /&gt;
|Chapter=CH00&lt;br /&gt;
|Place=ALTO&lt;br /&gt;
|Label=CH00-ALTO-0001&lt;br /&gt;
|File=CH00-ALTO-0001.jpg&lt;br /&gt;
|Description=TBD&lt;br /&gt;
|Notes=TBD&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=File:CH00-ALTO-0001.jpg&amp;diff=1404</id>
		<title>File:CH00-ALTO-0001.jpg</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=File:CH00-ALTO-0001.jpg&amp;diff=1404"/>
		<updated>2026-02-22T19:36:25Z</updated>

		<summary type="html">&lt;p&gt;Mngr: Mngr moved page File:Berck240-ai.jpg to File:CH00-ALTO-0001.jpg without leaving a redirect: Heritage Auto-Rename&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=File:CH00-ALTO-0001.jpg&amp;diff=1403</id>
		<title>File:CH00-ALTO-0001.jpg</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=File:CH00-ALTO-0001.jpg&amp;diff=1403"/>
		<updated>2026-02-22T19:36:03Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=Form:Asset&amp;diff=1402</id>
		<title>Form:Asset</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=Form:Asset&amp;diff=1402"/>
		<updated>2026-02-22T19:31:35Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
Form for creating and editing Asset pages (v2.3 – Phase A)&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{{info&lt;br /&gt;
|page name=Asset:&amp;lt;Asset[Label]&amp;gt;&lt;br /&gt;
|no summary&lt;br /&gt;
|no preview&lt;br /&gt;
|no minor edit&lt;br /&gt;
|no watch&lt;br /&gt;
|no footer&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
{{{for template|Asset}}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;formtable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
! Status&lt;br /&gt;
| {{{field|Status|readonly|default=DRAFT}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Chapter (*)&lt;br /&gt;
| {{{field|Chapter&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Chapter&lt;br /&gt;
 |existing values only&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Place&lt;br /&gt;
| {{{field|Place&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Place&lt;br /&gt;
 |existing values only&lt;br /&gt;
 |placeholder=Use Organisation instead&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Organisation&lt;br /&gt;
| {{{field|Organisation&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Organisation&lt;br /&gt;
 |existing values only&lt;br /&gt;
 |placeholder=Use Place instead&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Identifier&lt;br /&gt;
| {{{field|Label|readonly}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Sequence&lt;br /&gt;
| {{{field|Sequence|readonly}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! File&lt;br /&gt;
| {{{field|File&lt;br /&gt;
 |input type=page&lt;br /&gt;
 |namespace=File&lt;br /&gt;
 |uploadable=yes&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Original filename&lt;br /&gt;
| {{{field|OriginalFilename|readonly}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Asset type&lt;br /&gt;
| {{{field|AssetType&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=AssetType&lt;br /&gt;
 |existing values only&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Parent asset&lt;br /&gt;
| {{{field|Parent&lt;br /&gt;
 |input type=combobox&lt;br /&gt;
 |values from namespace=Asset&lt;br /&gt;
 |existing values only&lt;br /&gt;
 |placeholder=Top level&lt;br /&gt;
}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Description&lt;br /&gt;
| {{{field|Description|input type=textarea}}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
! Notes&lt;br /&gt;
| {{{field|Notes|input type=textarea}}}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{{{standard input|save}}}&lt;br /&gt;
&lt;br /&gt;
{{{end template}}}&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=Dashboard:Asset&amp;diff=1401</id>
		<title>Dashboard:Asset</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=Dashboard:Asset&amp;diff=1401"/>
		<updated>2026-02-22T19:28:56Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= 🗂️ Asset Dashboard =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Code !! Chapter !! Place !! Organisation !! File !! Type&lt;br /&gt;
{{#cargo_query:&lt;br /&gt;
 tables=Assets&lt;br /&gt;
 |fields=_pageName,_pageTitle,Chapter,Place,Organisation,File,AssetType&lt;br /&gt;
 |where=Status=&#039;FINAL&#039;&lt;br /&gt;
 |order by=_pageTitle&lt;br /&gt;
 |format=template&lt;br /&gt;
 |template=AssetRow&lt;br /&gt;
 |named args=yes&lt;br /&gt;
 |cache=no&lt;br /&gt;
}}&lt;br /&gt;
|}&lt;br /&gt;
{{#formlink:&lt;br /&gt;
 form=Asset&lt;br /&gt;
 |target=Asset:{{#time: YmdHis }}&lt;br /&gt;
 |link text=➕ New Asset&lt;br /&gt;
 |link type=button&lt;br /&gt;
 |query string=Asset[Label]=GENERATING...&amp;amp;Asset[File]=&lt;br /&gt;
 |returnto=Dashboard:Asset&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=Template:Asset&amp;diff=1400</id>
		<title>Template:Asset</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=Template:Asset&amp;diff=1400"/>
		<updated>2026-02-22T19:21:12Z</updated>

		<summary type="html">&lt;p&gt;Mngr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
Asset data template (v2.3 – Phase A)&lt;br /&gt;
&lt;br /&gt;
{{#cargo_declare:&lt;br /&gt;
 |_table=Assets&lt;br /&gt;
 |Code=Page&lt;br /&gt;
 |Status=String&lt;br /&gt;
 |Label=String&lt;br /&gt;
 |Chapter=Page&lt;br /&gt;
 |Place=Page&lt;br /&gt;
 |Organisation=Page&lt;br /&gt;
 |Sequence=Integer&lt;br /&gt;
 |File=String&lt;br /&gt;
 |OriginalFilename=String&lt;br /&gt;
 |Parent=Page&lt;br /&gt;
 |AssetType=Page&lt;br /&gt;
 |Description=Text&lt;br /&gt;
 |Notes=Text&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{#cargo_store:&lt;br /&gt;
 |Code={{FULLPAGENAME}}&lt;br /&gt;
 |Status={{{Status|DRAFT}}}&lt;br /&gt;
 |Label={{{Label|}}}&lt;br /&gt;
 |Chapter={{{Chapter|}}}&lt;br /&gt;
 |Place={{{Place|}}}&lt;br /&gt;
 |Organisation={{{Organisation|}}}&lt;br /&gt;
 |Sequence={{{Sequence|}}}&lt;br /&gt;
 |File={{{File|}}}&lt;br /&gt;
 |OriginalFilename={{{OriginalFilename|}}}&lt;br /&gt;
 |Parent={{{Parent|}}}&lt;br /&gt;
 |AssetType={{{AssetType|}}}&lt;br /&gt;
 |Description={{{Description|}}}&lt;br /&gt;
 |Notes={{{Notes|}}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== {{{Label|}}} ==&lt;br /&gt;
{{DISPLAYTITLE:{{{Label}}}}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Status:&#039;&#039;&#039; {{{Status|DRAFT}}}&lt;br /&gt;
&lt;br /&gt;
{{#if:{{{File|}}}|&#039;&#039;&#039;File:&#039;&#039;&#039; [[{{{File}}}]]}}&lt;br /&gt;
&lt;br /&gt;
{{#if:{{{OriginalFilename|}}}|&#039;&#039;&#039;Original filename:&#039;&#039;&#039; {{{OriginalFilename}}}}}&lt;br /&gt;
&lt;br /&gt;
{{#if:{{{Parent|}}}|&#039;&#039;&#039;Parent asset:&#039;&#039;&#039; [[{{{Parent}}}]]}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039;&lt;br /&gt;
{{{Description|}}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
{{{Notes|}}}&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
</feed>