Automating MediaWiki Deployments with Docker Compose and GitHub Actions

Why automate MediaWiki deployments?

MediaWiki powers Wikipedia and thousands of other knowledge bases. When you run it in production you usually need a database, a web server, optional extensions and a repeatable way to bring the whole stack up on a new host. Docker Compose gives you a portable, declarative description of the stack, while GitHub Actions lets you run the same steps automatically on every push – guaranteeing that the version you test locally is the version you ship.

Docker‑Compose foundation

The official MediaWiki‑Docker page ships a ready‑made docker‑compose.yml that runs MediaWiki with a MariaDB container. The file is deliberately minimal so you can extend it with your own overrides.

version: "3.8"
services:
  mediawiki:
    image: mediawiki:latest            # official MediaWiki image
    ports:
      - "8080:80"                    # expose on host port 8080
    environment:
      MEDIAWIKI_DB_HOST: db
      MEDIAWIKI_DB_USER: wikiuser
      MEDIAWIKI_DB_PASSWORD: secret
      MEDIAWIKI_DB_NAME: wikidb
    depends_on:
      - db
    volumes:
      - ./images:/var/www/html/images   # persistent uploads
      # Uncomment after the first ./LocalSettings.php:/var/www/html/LocalSettings.php
  db:
    image: mariadb:10.11
    environment:
      MYSQL_ROOT_PASSWORD: rootsecret
      MYSQL_DATABASE: wikidb
      MYSQL_USER: wikiuser
      MYSQL_PASSWORD: secret
    volumes:
      - ./db:/var/lib/mysql

Steps to get a working instance:

  1. Copy the snippet above into a new directory as docker-compose.yml.
  2. Run docker compose up -d. MediaWiki will start on http://localhost:8080 and present the web installer.
  3. Complete the installer, download the generated LocalSettings.php and place it next to the compose file.
  4. Un‑comment the LocalSettings.php volume line and restart the stack with docker compose down && docker compose up -d.

At this point you have a fully functional wiki that you can extend with extensions, skins or custom PHP settings.

Extending the stack with docker‑compose.override.yml

The MediaWiki‑Docker page mentions a recipe system that works by adding an override file. This file merges with the base definition and lets you:

  • Swap the base image (e.g. mediawiki:lts for a long‑term‑support tag).
  • Add a php container for custom extensions or XDebug.
  • Mount a local extensions/ directory so you can develop extensions without rebuilding the image.

Example that mounts a local extensions/ folder and disables XDebug for better performance:

services:
  mediawiki:
    volumes:
      - ./extensions:/var/www/html/extensions   # host‑side extensions
    environment:
      XDEBUG_MODE: off                       # turn off XDebug in prod

After saving the file, simply run docker compose up -d again – Docker will pick up the new configuration automatically.

Continuous deployment with GitHub Actions

GitHub Actions provides three building blocks that match our needs:

  • Jobs and steps – define a series of commands that run on a fresh runner.
  • Environments – mark a job as a production deployment and optionally require manual approval.
  • Secrets – store the database password, SSH key and any other credentials securely.

The workflow below ties everything together. It runs on every push to main, builds the Docker image, pushes it to Docker Hub, copies the updated LocalSettings.php to the server via SSH and finally restarts the compose stack.

name: Deploy MediaWiki
on:
  push:
    branches: [main]

permissions:
  contents: read
  packages: write   # needed for Docker Hub login

environment:
  name: production   # shows up in the repo UI
  url: ${{ steps.deploy.outputs.page_url }}

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_HUB_USER }}
          password: ${{ secrets.DOCKER_HUB_TOKEN }}

      - name: Build and push image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ secrets.DOCKER_HUB_USER }}/mediawiki:latest
            ${{ secrets.DOCKER_HUB_USER }}/mediawiki:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Checkout code (for LocalSettings.php)
        uses: actions/checkout@v4
        with:
          sparse-checkout: LocalSettings.php

      - name: Install SSH client
        run: sudo apt-get update && sudo apt-get install -y openssh-client

      - name: Add server to known hosts
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SERVER_SSH_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts

      - name: Copy LocalSettings.php to server
        run: |
          scp -o StrictHostKeyChecking=no \
            LocalSettings.php ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:/opt/wiki/mediawiki_data/LocalSettings.php

      - name: Restart Docker Compose on server
        run: |
          ssh ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} \
            "cd /opt/wiki && docker compose pull && docker compose up -d"

      - name: Export page URL (optional)
        id: deploy
        run: echo "::set-output name=page_url::http://${{ secrets.SERVER_HOST }}:8080"

Key points:

  • The build job uses the official Docker actions – no need to install Docker manually.
  • All secrets (Docker Hub credentials, SSH private key, server address) are stored in the repository’s Settings → Secrets → Actions and never appear in logs.
  • The environment: production line makes the deployment visible in the UI and lets you add a manual approval rule if you prefer a “push‑to‑prod after review” workflow.
  • After the image is pushed, the remote host simply pulls the newest tag and runs docker compose up -d, which updates MediaWiki without downtime (thanks to Docker’s zero‑downtime restart).

Security hardening checklist

AspectRecommendation
SecretsStore only the minimal values needed – e.g. a short‑lived Docker Hub token and a read‑only SSH key that can only run docker compose on the host.
SSH accessRestrict the key’s authorized_keys entry to the command docker compose pull && docker compose up -d using the command= option.
Database credentialsPass them via environment in the compose file, but keep the docker‑compose.yml out of the repository (add it to .gitignore) and mount it as a secret on the host.
Image provenanceAlways pull from the official mediawiki image or from a private registry that you control. Verify the digest if you need absolute certainty.

Putting it all together

1. Clone the repository that contains the compose files.
2. Add the workflow file under .github/workflows/deploy.yml.
3. Populate the required secrets: DOCKER_HUB_USER, DOCKER_HUB_TOKEN, SERVER_HOST, SERVER_USER, SERVER_SSH_KEY. 4. Push to main. GitHub Actions will build the image, push it, copy the updated settings and restart the stack on the target host. 5. Verify the live wiki at http://<SERVER_HOST>:8080. Any further change – new extensions, skin updates or core upgrades – follows the same pipeline, guaranteeing reproducibility.

Conclusion

By combining the official MediaWiki‑Docker development environment with a small docker‑compose.override.yml and a concise GitHub Actions workflow, you get a repeatable, version‑controlled deployment pipeline. The approach works equally well for a single‑server wiki or for a small farm of MediaWiki instances, and it scales naturally as you add more extensions, custom PHP, or even a full‑blown Kubernetes front‑end later on.

Subscribe to MediaWiki Tips and Tricks

Don’t miss out on the latest articles. Sign up now to get access to the library of members-only articles.
jamie@example.com
Subscribe