11 KiB
GPLX – Deployment Runbook: IONOS VPS (native Apache)
This document records the exact steps taken to deploy GPLX on an IONOS VPS on 2026-06-05. It replaces a broken Docker-based MediaWiki install with a native Apache + PHP + MariaDB stack. Use it verbatim for a repeat deployment or hand it to another AI assistant.
Environment
| Item | Value |
|---|---|
| Server IP | 31.70.94.35 |
| OS | Ubuntu 24.04 LTS |
| Web root | /var/www/gplx/mediawiki |
| Git bare repo | /var/repo/gplx.git |
| DB name/user | gplx / gplx |
| MW admin user | Gxplex_admin |
| MW admin pass | TempAdmin123 ← change this |
| HTTP Basic Auth user | testUser |
Starting situation
- Two Docker containers were running on the server:
mediawiki:1.41on0.0.0.0:8080->80mysql:8.0on3306/tcp
nginxwas running on port 80 (served something else, now disabled)/var/www/gplxdid not exist- Git remote
ionospointed atssh://root@31.70.94.35/var/www/gplx(wrong — no bare repo)
Step 1 – Create bare git repo on the server
Run locally:
ssh root@31.70.94.35 "git init --bare /var/repo/gplx.git && mkdir -p /var/www/gplx && printf '#!/bin/bash\nGIT_WORK_TREE=/var/www/gplx git checkout -f main\n' > /var/repo/gplx.git/hooks/post-receive && chmod +x /var/repo/gplx.git/hooks/post-receive && echo 'Done'"
This creates a bare repo at /var/repo/gplx.git and a post-receive hook that checks out
the code into /var/www/gplx on every push.
Step 2 – Fix local git remote and push
git remote set-url ionos ssh://root@31.70.94.35/var/repo/gplx.git
git push ionos main
The hook fires automatically: output shows Switched to branch 'main'.
Step 3 – Install system packages
All packages were already present on this server. If doing a fresh install:
ssh root@<ip>
apt update && apt install -y apache2 php8.3 php8.3-mysql php8.3-xml \
php8.3-mbstring php8.3-intl php8.3-curl php8.3-gd php8.3-zip \
mariadb-server git apache2-utils
Step 4 – Stop nginx (was holding port 80)
systemctl stop nginx
systemctl disable nginx
Step 5 – Create database and user
mysql -u root <<'SQL'
CREATE DATABASE IF NOT EXISTS gplx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'gplx'@'localhost' IDENTIFIED BY 'YOUR_DB_PASSWORD';
GRANT ALL PRIVILEGES ON gplx.* TO 'gplx'@'localhost';
FLUSH PRIVILEGES;
SQL
If the user already exists with a different password, reset it:
mysql -u root <<'SQL'
ALTER USER 'gplx'@'localhost' IDENTIFIED BY 'YOUR_DB_PASSWORD';
FLUSH PRIVILEGES;
SQL
Step 6 – Configure Apache vhost with HTTP Basic Auth
cat > /etc/apache2/sites-available/gplx.conf << 'EOF'
<VirtualHost *:80>
ServerName 31.70.94.35
DocumentRoot /var/www/gplx/mediawiki
<Directory /var/www/gplx/mediawiki>
AllowOverride All
AuthType Basic
AuthName "GxPlex – restricted access"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Directory>
</VirtualHost>
EOF
a2enmod rewrite
a2ensite gplx
a2dissite 000-default
systemctl start apache2
Important: Do NOT include
Require all grantedalongsideRequire valid-user— they act as OR, which lets anonymous traffic through.
Create the htpasswd file:
htpasswd -c /etc/apache2/.htpasswd testUser
# enter password at the prompt
Step 7 – Install Composer dependencies
MediaWiki core:
cd /var/www/gplx/mediawiki
composer install --no-dev
SemanticMediaWiki (has its own vendor tree):
composer install --no-dev -d extensions/SemanticMediaWiki
Step 8 – Deploy LocalSettings.php
LocalSettings.php is gitignored and must be transferred separately.
On your local machine, edit mediawiki/LocalSettings.php and set:
$wgServer = "http://31.70.94.35"; // or https://yourdomain.de once TLS is live
$wgDBserver = "localhost";
$wgDBname = "gplx";
$wgDBuser = "gplx";
$wgDBpassword = "YOUR_DB_PASSWORD";
$wgSecretKey = "<output of: openssl rand -hex 32>";
$wgShowExceptionDetails = false;
// in the ExtensionFunctions hook:
enableSemantics( '31.70.94.35' ); // change to domain once live
Then copy to the server:
scp mediawiki/LocalSettings.php root@31.70.94.35:/var/www/gplx/mediawiki/LocalSettings.php
Or patch it in-place on the server with sed:
sed -i \
-e 's|$wgServer = "http://127.0.0.1:8080";|$wgServer = "http://31.70.94.35";|' \
-e 's|$wgDBserver = "127.0.0.1";|$wgDBserver = "localhost";|' \
-e 's|$wgDBname = "gflex_test";|$wgDBname = "gplx";|' \
-e 's|$wgDBuser = "root";|$wgDBuser = "gplx";|' \
-e "s|\$wgDBpassword = \"\";|\$wgDBpassword = \"YOUR_DB_PASSWORD\";|" \
-e "s|enableSemantics( '127.0.0.1:8080' );|enableSemantics( '31.70.94.35' );|" \
-e 's|$wgShowExceptionDetails = true;|$wgShowExceptionDetails = false;|' \
/var/www/gplx/mediawiki/LocalSettings.php
Step 9 – Create images directory
mkdir -p /var/www/gplx/mediawiki/images
chown -R www-data:www-data /var/www/gplx/mediawiki/images
Step 10 – Install MediaWiki database tables
Because the database is empty, update.php fails with "Can not upgrade from versions older
than 1.35". Use install.php instead, temporarily hiding LocalSettings.php:
cd /var/www/gplx/mediawiki
mv LocalSettings.php LocalSettings.php.bak
php maintenance/run.php install \
--dbuser gplx \
--dbpass YOUR_DB_PASSWORD \
--dbname gplx \
--dbserver localhost \
--server 'http://31.70.94.35' \
--scriptpath '' \
--lang en \
--pass TempAdmin123 \
'GxPlex' 'Gxplex_admin'
mv LocalSettings.php.bak LocalSettings.php
Then run update to pick up extension schema changes:
php maintenance/run.php update --quick
Step 11 – Set up SMW tables
php extensions/SemanticMediaWiki/maintenance/setupStore.php --nochecks
Step 12 – Smoke test
# Should return 401 (Basic Auth gate)
curl -s -o /dev/null -w '%{http_code}' http://31.70.94.35/
# Should return 200 with correct credentials
curl -sL -o /dev/null -w '%{http_code}' -u testUser:YOUR_HTPASSWD_PASSWORD http://31.70.94.35/
Open in browser: http://31.70.94.35 → login prompt → MediaWiki main page.
Step 13 – Import local database dump
The local MediaWiki DB was exported as gflex_test.sql (≈280 MB) and contains all user
accounts, pages, and content from the dev instance.
Upload the dump to the server:
scp D:\Work\Projekte\gplx\gflex_test.sql root@31.70.94.35:/root/gflex_test.sql
The gplx DB already had tables from the fresh install (Step 10), so drop and recreate it
before importing — otherwise MySQL errors with "Table already exists":
mysql -u root <<'SQL'
DROP DATABASE gplx;
CREATE DATABASE gplx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL PRIVILEGES ON gplx.* TO 'gplx'@'localhost';
FLUSH PRIVILEGES;
SQL
Import the dump:
mysql -ugplx -pYOUR_DB_PASSWORD gplx < /root/gflex_test.sql
Run update to apply any schema differences between the dump and the current MW version:
cd /var/www/gplx/mediawiki
php maintenance/run.php update --quick
All local user accounts and wiki content are now available on the server.
Step 14 – Nutzeraccounts
Die Accounts aus dem SQL-Import (Step 13) sind direkt nutzbar — lokale Zugangsdaten funktionieren ohne weitere Schritte.
Vorhandene User prüfen:
mysql -ugplx -pYOUR_DB_PASSWORD gplx \
-e 'SELECT user_name, user_registration FROM user ORDER BY user_registration DESC LIMIT 20;'
Neuen Account anlegen (Passwort wird interaktiv abgefragt):
cd /var/www/gplx/mediawiki
php maintenance/run.php createAndPromote NeuUser
# mit Bureaucrat-Rechten:
php maintenance/run.php createAndPromote --bureaucrat NeuUser
Passwort zurücksetzen:
php maintenance/run.php changePassword --user="Benutzername" --password="NeuesPasswort"
Account im Browser anlegen: http://31.70.94.35/index.php/Special:CreateAccount
(nur sichtbar wenn $wgGroupPermissions['*']['createaccount'] = true, was der Standard ist).
Next steps (not yet done)
- Change
Gxplex_adminpassword viaSpecial:ChangePassword - Point domain DNS A-record to
31.70.94.35 - Add TLS via Certbot:
certbot --apache -d yourdomain.de - Update
$wgServerandenableSemantics()to use the domain - Push wiki page templates:
Get-Content scripts/templates/<file>.wiki -Raw | php mediawiki/maintenance/run.php edit ... - Run
npm run a11y:allagainst the live URL
Gotchas encountered
| Problem | Cause | Fix |
|---|---|---|
git push ionos main failed (exit 1) |
Remote pointed at non-bare working dir | Created bare repo at /var/repo/gplx.git with post-receive hook |
/var/www/gplx/mediawiki not found after push |
Directory was checked out by hook — actually worked, just needed to look again | ls /var/www/gplx/mediawiki confirmed it was there |
SMW fatal: Class "Onoi\Cache\NullCache" not found |
SMW vendor deps not installed | composer install --no-dev -d extensions/SemanticMediaWiki |
update.php: "Can not upgrade from versions older than 1.35" |
Completely empty DB — MW misreads it | Use install.php with LocalSettings.php temporarily moved away |
install.php: "A LocalSettings.php file has been detected" |
Installer refuses when file exists | mv LocalSettings.php LocalSettings.php.bak before install, restore after |
| Apache won't start | nginx was holding port 80 | systemctl stop nginx && systemctl disable nginx |
| Basic Auth not blocking (returns 200 for anonymous) | Require all granted + Require valid-user = OR logic |
Remove Require all granted; only keep Require valid-user |
| DB "Access denied for user gplx" | Password in LocalSettings.php didn't match DB | ALTER USER 'gplx'@'localhost' IDENTIFIED BY '...' to sync them |
ERROR 1050: Table 'actor' already exists on SQL import |
Fresh MW install already created tables; importing on top fails | DROP DATABASE gplx + recreate, then import |