Skip to content

Commit fb8dd62

Browse files
committed
Convert to a multi-site setup
1 parent 6bae48e commit fb8dd62

14 files changed

Lines changed: 285 additions & 141 deletions

Dockerfile

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ RUN docker-php-ext-install calendar pgsql intl zip && \
1414

1515
ARG MEDIAWIKI_VERSION_MAJOR=1.39
1616
ARG MEDIAWIKI_VERSION=1.39.6
17-
ARG URL_PREFIX
1817

1918
RUN curl -s -o /tmp/keys.txt https://www.mediawiki.org/keys/keys.txt && \
2019
curl -s -o /tmp/mediawiki.tar.gz https://releases.wikimedia.org/mediawiki/$MEDIAWIKI_VERSION_MAJOR/mediawiki-$MEDIAWIKI_VERSION.tar.gz && \
@@ -36,15 +35,15 @@ COPY config/composer.local.json /var/www/mediawiki/w/composer.local.json
3635
RUN cd /var/www/mediawiki/w; COMPOSER_ALLOW_SUPERUSER=1 php ./composer.phar update --no-dev
3736

3837
COPY config/php-fpm.conf /usr/local/etc/
39-
COPY config/supervisord.conf /etc/supervisord.conf
40-
COPY config/nginx.conf.template /etc/nginx/nginx.conf.template
41-
COPY docker-entrypoint.sh /docker-entrypoint.sh
38+
COPY config/supervisord.conf /etc/supervisor/supervisord.conf
39+
COPY config/supervisord-wiki.conf.template /etc/supervisor/supervisord-wiki.conf.template
40+
COPY config/nginx.conf /etc/nginx/nginx.conf
41+
COPY devinstall.sh /devinstall.sh
4242
COPY mwjobrunner.sh /mwjobrunner.sh
43-
44-
RUN ln -s /config/LocalSettings.php /var/www/mediawiki/w/LocalSettings.php
45-
RUN ln -s /config/smw.json /var/www/mediawiki/w/extensions/SemanticMediaWiki/.smw.json
43+
COPY docker-entrypoint.sh /docker-entrypoint.sh
44+
COPY config/LocalSettings.php /var/www/mediawiki/w/LocalSettings.php
4645

4746
VOLUME ["/images", "/config"]
4847
EXPOSE 80
4948
ENTRYPOINT ["/docker-entrypoint.sh"]
50-
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
49+
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

README.md

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
Mediawiki in a docker container for EMF. This container bakes in the needed set
22
of Mediawiki plugins using composer.
33

4+
It provides a 'multi-site' installation of MediaWiki, that allows us to host
5+
multiple wikis using a single copy of the MediaWiki codebase. This reduces the
6+
memory and CPU footprint, since we can more easily provide a hot PHP-FPM pool
7+
for multiple wikis.
8+
49
## Development
510

611
* `docker compose up`
7-
* Visit http://localhost:8087 and complete the installation wizard
12+
* Visit http://localhost:8087/2024/ and complete the installation wizard
813

914
The database credentials are: host `db`, db `wiki`, username `wiki`, password `wiki`. Once
1015
you've downloaded the config file, put it in `./data/config`, and add the following at the end:
@@ -34,6 +39,19 @@ get a cryptic error.
3439
To troubleshoot fatal errors, set `$wgShowExceptionDetails = true`.
3540

3641
## Config
42+
43+
There's a bunch of specifics that end up baked into the container,
44+
unfortunately. In particular, `config/LocalSettings.php` contains a copy of
45+
the logic for working out which settings file to load, given a hostname and URL
46+
path, and `nginx.conf` also does routing based on hostname and URL path.
47+
48+
The expectation is that each wiki has a 'short name' (e.g. a year or 'badge')
49+
and that this will be the directory name under the volumes mounted at `/config`
50+
and `/images`, as well as the argument to `--wiki` for the MediaWiki
51+
maintenance scripts. The Docker entrypoint automatically generates a set of
52+
supervisord configs to run the MediaWiki crons for each directory under
53+
`/config`.
54+
3755
### Short URLs
3856

3957
For short URLs, the appropriate config is:
@@ -43,14 +61,7 @@ $wgScriptPath = "/w";
4361
$wgUsePathInfo = true;
4462
```
4563

46-
If you're exposing the wiki under a subdirectory, set `URL_PREFIX` in `docker-compose.yml`, e.g.:
47-
48-
```
49-
environment:
50-
URL_PREFIX: /2018
51-
```
52-
53-
And update the config to:
64+
If you're exposing the wiki under a subdirectory, update the config to:
5465

5566
```
5667
$wgScriptPath = "/2018/w";
@@ -86,17 +97,4 @@ For Postgres, take the latest stable.
8697

8798
For deployment, regenerate the out-of-the-box MediaWiki LocalSettings.php and compare it to the previous version's in `config-history`. Apply changes manually to the live configs.
8899

89-
To quickly reinstall a test instance, use the following commands:
90-
91-
```
92-
$ docker compose down -v
93-
$ rm -f data/config/LocalSettings.php
94-
$ docker compose up --build -d
95-
$ server=http://localhost:8087
96-
$ pass=$(dd if=/dev/random bs=3 count=3 2>/dev/null|base64)
97-
$ docker compose exec mediawiki php /var/www/mediawiki/w/maintenance/install.php --dbtype postgres --dbserver db --dbname wiki --dbuser wiki --dbpass wiki --pass $pass --server $server --scriptpath /w --lang en-gb --with-extensions Test Admin
98-
$ docker compose exec mediawiki php /var/www/mediawiki/w/maintenance/update.php --quick
99-
$ docker compose exec mediawiki bash -c "echo \"enableSemantics( 'localhost:8087' );\" >> /config/LocalSettings.php"
100-
$ echo "Now log into $server/ as user Admin with password $pass"
101-
```
102-
100+
To quickly reinstall a test instance, run `_devsetup.sh` outside the container.

_devsetup.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/sh
2+
3+
set -euxo pipefail
4+
5+
docker compose down -v
6+
rm -f data/config/LocalSettings.php
7+
docker compose up --build -d
8+
server=http://localhost:8087
9+
pass=$(dd if=/dev/random bs=3 count=3 2>/dev/null|base64)
10+
docker compose exec mediawiki /devinstall.sh --confpath /config/2024 --dbtype postgres --dbserver db --dbname wiki --dbuser wiki --dbpass wiki --pass $pass --server $server --scriptpath /2024/w --lang en-gb --with-extensions Test Admin
11+
docker compose exec mediawiki php /var/www/mediawiki/w/maintenance/update.php --quick --wiki 2024
12+
docker compose exec mediawiki bash -c "echo \"enableSemantics( 'localhost:8087' );\" >> /config/2024/LocalSettings.php"
13+
docker compose exec mediawiki sed -i '/^[$]wgScriptPath/i $wgArticlePath = "/2024/wiki/$1";' /config/2024/LocalSettings.php
14+
docker compose exec mediawiki sed -i '/^[$]wgScriptPath/i $wgUsePathInfo = true;' /config/2024/LocalSettings.php
15+
echo "Now log into $server/2024/wiki/ as user Admin with password $pass"
16+

config/LocalSettings.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
4+
// Try to match one of our configured sites.
5+
$conf = '';
6+
if (defined('MW_WIKI_NAME')) {
7+
// This constant is set by the --wiki flag to maintenance scripts.
8+
$conf = MW_WIKI_NAME;
9+
} else if (isset($_SERVER['MW_WIKI_NAME'])) {
10+
$conf = $_SERVER['MW_WIKI_NAME'];
11+
} else if ($_SERVER['HTTP_HOST'] === 'badge.emfcamp.org' || $_SERVER['HTTP_HOST'] === 'badge.localhost' || str_starts_with($_SERVER['HTTP_HOST'], 'badge.localhost:')) {
12+
$conf = 'badge';
13+
} else {
14+
if (preg_match('/^\/([0-9]+)\//', $_SERVER['REQUEST_URI'], $matches) === false) {
15+
die('Unable to figure out which config to use from ' . $_SERVER['REQUEST_URI']);
16+
}
17+
$conf = $matches[1];
18+
}
19+
20+
if ($conf === null || $conf === '') {
21+
die('Unable to figure out which wiki is being accessed');
22+
}
23+
24+
$settings = '/config/' . $conf . '/LocalSettings.php';
25+
if (!file_exists($settings)) {
26+
http_response_code(404);
27+
echo '<h1>404 Not Found</h1>';
28+
die();
29+
}
30+
31+
$wgUploadDirectory = '/images/'. $conf;
32+
$wgFileCacheDirectory = "{$wgUploadDirectory}/cache";
33+
34+
require_once($settings);
35+
36+
$smwgConfigFileDir = '/config/' . $conf;
37+

config/nginx.conf

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
user www-data;
2+
worker_processes 1;
3+
daemon off;
4+
5+
error_log /proc/self/fd/2 warn;
6+
pid /var/run/nginx.pid;
7+
8+
9+
events {
10+
worker_connections 1024;
11+
}
12+
13+
14+
http {
15+
include /etc/nginx/mime.types;
16+
default_type application/octet-stream;
17+
18+
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
19+
'$status $body_bytes_sent "$http_referer" '
20+
'"$http_user_agent" "$http_x_forwarded_for"';
21+
22+
access_log /proc/self/fd/2 main;
23+
24+
sendfile on;
25+
#tcp_nopush on;
26+
27+
keepalive_timeout 65;
28+
29+
server {
30+
listen 80 default_server;
31+
server_name wiki.emfcamp.org;
32+
root /var/www/mediawiki;
33+
client_max_body_size 32M;
34+
client_body_timeout 60;
35+
36+
set_real_ip_from 192.168.0.0/16;
37+
set_real_ip_from 172.16.0.0/12;
38+
set_real_ip_from 10.0.0.0/8;
39+
real_ip_header X-Forwarded-For;
40+
41+
location ~ ^/(?<year>20[0-9][0-9])/ {
42+
alias /var/www/mediawiki/;
43+
index index.php;
44+
45+
if (!-f /config/$year/LocalSettings.php) { return 404; }
46+
47+
location ~ ^/[^/]+/$ {
48+
return 301 /$year/wiki/;
49+
}
50+
51+
location ~ ^/([^/]+)/w/images/(.*)$ {
52+
location ~* \.php$ { return 403; }
53+
location ~ ^/[^/]+/w/images/deleted { return 403; }
54+
alias /images/$1/$2;
55+
}
56+
57+
location ~ ^/[^/]+/w/ {
58+
rewrite ^/[^/]+/w/(.*)$ /w/$1 last;
59+
}
60+
61+
location ~ ^/[^/]+/wiki/ {
62+
rewrite ^/[^/]+/wiki/(.*)$ /w/index.php/$1 last;
63+
}
64+
}
65+
66+
location ~ \.php(/|$) {
67+
# $request_filename takes into account alias, unlike $fastcgi_script_name,
68+
# but isn't affected by $fastcgi_split_path_info. So we rewrite it instead.
69+
# As we're inside a location, no more locations are checked.
70+
rewrite ^/(.+?\.php)(?<path_info>/.*)$ /$1;
71+
72+
# Examples for https://wiki-archive.emfcamp.org/2018/w/test.php/x:
73+
# return 301 $fastcgi_script_name; # /2018/w/test.php
74+
# return 301 $fastcgi_path_info; # would be /x, but is empty because we don't split
75+
# return 301 $request_filename; # /var/www/mediawiki/w/test.php
76+
# return 301 $path_info; # /x
77+
# return 301 $uri; # /2018/w/test.php
78+
# return 301 $request_uri; # /2018/w/test.php/x
79+
80+
if (!-f $request_filename) {
81+
return 404;
82+
}
83+
84+
include fastcgi_params;
85+
fastcgi_param SCRIPT_FILENAME $request_filename;
86+
fastcgi_param PATH_INFO $path_info;
87+
fastcgi_param HTTP_PROXY "";
88+
89+
fastcgi_pass unix:/var/run/mediawiki.sock;
90+
}
91+
}
92+
93+
server {
94+
listen 80;
95+
server_name badge.emfcamp.org badge.localhost;
96+
root /var/www/mediawiki;
97+
client_max_body_size 32M;
98+
client_body_timeout 60;
99+
100+
set_real_ip_from 192.168.0.0/16;
101+
set_real_ip_from 172.16.0.0/12;
102+
set_real_ip_from 10.0.0.0/8;
103+
real_ip_header X-Forwarded-For;
104+
105+
index index.php;
106+
107+
location = / {
108+
return 301 wiki/;
109+
}
110+
111+
location /w/images/ {
112+
location ~* \.php$ { return 403; }
113+
location /w/images/deleted { return 403; }
114+
alias /images/badge/;
115+
}
116+
117+
location /wiki/ {
118+
rewrite ^/wiki/(.*)$ /w/index.php/$1 last;
119+
}
120+
121+
location ~ \.php(/|$) {
122+
# $request_filename takes into account alias, unlike $fastcgi_script_name,
123+
# but isn't affected by $fastcgi_split_path_info. So we rewrite it instead.
124+
# As we're inside a location, no more locations are checked.
125+
rewrite ^/(.+?\.php)(?<path_info>/.*)$ /$1;
126+
127+
# Examples for https://wiki-archive.emfcamp.org/2018/w/test.php/x:
128+
# return 301 $fastcgi_script_name; # /2018/w/test.php
129+
# return 301 $fastcgi_path_info; # would be /x, but is empty because we don't split
130+
# return 301 $request_filename; # /var/www/mediawiki/w/test.php
131+
# return 301 $path_info; # /x
132+
# return 301 $uri; # /2018/w/test.php
133+
# return 301 $request_uri; # /2018/w/test.php/x
134+
135+
if (!-f $request_filename) {
136+
return 404;
137+
}
138+
139+
include fastcgi_params;
140+
fastcgi_param SCRIPT_FILENAME $request_filename;
141+
fastcgi_param PATH_INFO $path_info;
142+
fastcgi_param HTTP_PROXY "";
143+
144+
fastcgi_pass unix:/var/run/mediawiki.sock;
145+
}
146+
}
147+
}

config/nginx.conf.template

Lines changed: 0 additions & 87 deletions
This file was deleted.

0 commit comments

Comments
 (0)