MediaWiki¶
Production-ready NGINX configuration for MediaWiki with short URLs and security hardening.
Basic Configuration¶
server {
listen 443 ssl;
http2 on;
server_name wiki.example.com;
root /var/www/mediawiki;
index index.php;
# SSL
ssl_certificate /etc/letsencrypt/live/wiki.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wiki.example.com/privkey.pem;
# Upload limits
client_max_body_size 50m;
client_body_timeout 60;
# Short URLs
location / {
try_files $uri $uri/ @rewrite;
}
location @rewrite {
rewrite ^/(.*)$ /index.php?title=$1&$args;
}
# REST API (MediaWiki 1.35+)
location /rest.php {
try_files $uri $uri/ /rest.php?$args;
}
# Block sensitive directories
location ^~ /maintenance/ { return 403; }
location ^~ /cache/ { deny all; }
location ^~ /includes/ { deny all; }
location ^~ /languages/ { deny all; }
location ^~ /serialized/ { deny all; }
# Block sensitive files
location ~* ^/(LocalSettings|AdminSettings|\.htaccess) { deny all; }
# PHP handling
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_PROXY "";
fastcgi_read_timeout 300;
}
# Static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|webp|woff|woff2)$ {
try_files $uri /index.php;
expires 30d;
add_header Cache-Control "public";
log_not_found off;
access_log off;
}
# 1x1 pixel tracking gif
location = /_.gif {
expires max;
empty_gif;
}
# Image thumbnails
location ~ ^/images/thumb/ {
try_files $uri $uri/ @thumb;
}
location @thumb {
rewrite ^/images/thumb/[0-9a-f]/[0-9a-f][0-9a-f]/([^/]+)/([0-9]+)px-.*$ /thumb.php?f=$1&width=$2;
rewrite ^/images/thumb/archive/[0-9a-f]/[0-9a-f][0-9a-f]/([^/]+)/([0-9]+)px-.*$ /thumb.php?f=$1&width=$2&archived=1;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/thumb.php;
}
}
Short URL Setup¶
NGINX Configuration¶
The configuration above enables short URLs (e.g., /wiki/Page instead of /index.php?title=Page).
LocalSettings.php¶
# Article path (short URLs)
$wgArticlePath = "/wiki/$1";
$wgUsePathInfo = true;
# Script path
$wgScriptPath = "";
$wgScript = "/index.php";
$wgRedirectScript = "/redirect.php";
Visual Editor Support¶
For VisualEditor with Parsoid:
# Parsoid REST API (internal)
location /api/rest_v1/ {
proxy_pass http://127.0.0.1:8142/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Or if using built-in Parsoid (MW 1.35+)
location ^~ /rest.php/v1/page/ {
try_files $uri /rest.php?$args;
}
Security Hardening¶
Restrict Image Uploads¶
# Only allow specific image types in uploads
location ^~ /images/ {
location ~* \.(php|phtml|php3|php4|php5|phps)$ {
deny all;
}
}
Rate Limiting¶
limit_req_zone $binary_remote_addr zone=mw_login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=mw_api:10m rate=10r/s;
location = /index.php {
# Rate limit login attempts
if ($arg_title = "Special:UserLogin") {
limit_req zone=mw_login burst=5 nodelay;
}
}
location = /api.php {
limit_req zone=mw_api burst=50 nodelay;
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
Performance Tips¶
Enable Object Caching¶
In LocalSettings.php:
# APCu caching (recommended)
$wgMainCacheType = CACHE_ACCEL;
$wgSessionCacheType = CACHE_DB;
# Or use Redis
$wgMainCacheType = CACHE_REDIS;
$wgRedisServers = ['127.0.0.1'];
Static File Caching¶
# Aggressive caching for resources
location /resources/ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location /extensions/ {
location ~* \.(js|css|png|jpg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public";
access_log off;
}
}
Common Issues¶
| Issue | Solution |
|---|---|
| Short URLs not working | Ensure $wgUsePathInfo = true; in LocalSettings.php |
| 404 on wiki pages | Check location @rewrite block |
| Image uploads fail | Increase client_max_body_size |
| Slow page renders | Enable object caching (APCu or Redis) |