Skip to content

πŸ“˜ Installing MkDocs-Material

MkDocs

Material is a custom theme for the MkDocs static site generator that's geared towards building project documentation. Documentation source files are written in Markdown, and configured with a single YAML configuration file

Info

Both projects are open-source and can be downloaded here: https://github.com/squidfunk/mkdocs-material.


πŸ“₯ Installation

πŸ“‹ Requirements

Info

MkDocs requires the installation of


🐳 Install MkDocs

The use of Docker Compose will automate the installation of MkDocs container.

πŸ”§ Setup MkDocs Parameters

Before deploying, you need to define a few environment variables that will be used throughout the setup process.

  • HOST_PORT: external port used by NGINX to route traffic to the service
  • GIT_REPOS: path to the local git repository
# example of configuration for environment parameters
GIT_REPOS=/path/to/git-repos.git
HOST_PORT=10000
βš™οΈ Configure MkDocs for Docker Compose

MkDocs can be deployed using Docker Compose. The compose.yml file will automatically incorporate the environment variables configured in the previous step. You can copy, paste, and run all of the following commands directly in your terminal.

# create docker directory
mkdir mkdocs && cd mkdocs
mkdir build
# setup of compose.yml
tee compose.yml > /dev/null <<EOF
services:
  mkdocs-docs:
    build: .
    image: mkdocs-docs
    container_name: mkdocs-docs
    user: "\${PUID}:\${PGID}"
    volumes:
      - \${GIT_REPOS}:/git:ro
    ports:
      - \${HOST_PORT}:8000
    healthcheck:
      test: ["CMD", "curl", "-fsS", "-o", "/dev/null", "http://localhost:8000/"]
      start_period: 60s
      start_interval: 5s
      interval: 60s
      timeout: 1s
      retries: 3
    restart: unless-stopped
EOF
# setup of .env file
tee .env > /dev/null <<EOF
###################################################################################
# Run as non-root user
###################################################################################
PUID=`id -u`
PGID=`id -g`

###################################################################################
# NGINX Proxy Configuration
###################################################################################
HOST_PORT=${HOST_PORT}

###################################################################################
# MkDocs Configuration
###################################################################################
GIT_REPOS=${GIT_REPOS}
EOF

Keep the .env file

All the secret informations will be stored in the .env file.

🐳 Create the custom MkDocs-Material docker container

To create a custom Docker container for Mkdocs-Material based on python, follow these steps:

  1. Configure the requirements.txt File
    Modify the requirements.txt file to specify the required MkDocs plugins that will be installed in the Docker container.

    # setup requirements.txt file
    tee build/requirements.txt > /dev/null <<EOF
    mkdocs-material
    mkdocs-awesome-pages-plugin
    mkdocs-minify-plugin
    mkdocs-macros-plugin
    mkdocs-mermaid2-plugin
    EOF
    
  2. Create the run.sh Script
    Develop a run.sh script that will be executed upon container startup.
    This script should perform the following actions:

    • πŸ“ Check if a Git repository needs to be cloned.
    • ⬇️ Fetch the latest commits from the Git repository.
    • 🧹 Use git reset --hard to navigate to the latest commits, handling cases where the commit history has been rewritten.
    • βš™οΈ Build the MkDocs-material documentation if necessary.
    • 🌐 Launch a Python HTTP server to serve the static website created.
    # create run.sh script
    tee build/run.sh > /dev/null <<EOF
    #!/bin/sh
    # define the script default parameters
    LOGS=/tmp/update-logs.log
    RETRY_DELAY=60
    
    # fix git safe.directory warnings
    git config --global --add safe.directory /git
    
    # check if repository has been cloned
    if [ ! -d ".git" ]; then
      echo -n "=== git clone /git: "
      git clone /git . > "\${LOGS}" 2>&1
      if [ "\$?" -ne "0" ]; then
        echo "failed ===" && cat "\${LOGS}" && sleep \${RETRY_DELAY} && exit 1
      else
        echo "succeed ===" && echo ""
      fi
    fi
    
    # pull commits - handle the case when git history has been rewritten
    echo -n "=== git pull: "
    git pull origin master --rebase > "\${LOGS}" 2>&1
    if [ "\$?" -ne "0" ]; then
      echo "failed ===" && cat "\${LOGS}" && sleep \${RETRY_DELAY} && exit 1
    else
      echo "succeed ===" && echo ""
    fi
    
    # build the mkdocs-material documentation
    if [ ! -d "./site" ] || ! grep -Fq "Already up to date." "\${LOGS}"; then
      echo -n "=== building mkdocs-material documentation: "
      rm -rf ./site
      sync
      mkdocs build --no-directory-urls > "\${LOGS}" 2>&1
      if [ "\$?" -ne "0" ]; then
          echo "failed ===" && cat "\${LOGS}" && sleep \${RETRY_DELAY} && exit 1
      else
          echo "succeed ===" && echo ""
      fi
    fi
    
    # launch python simple http server
    echo "running python http-server on mkdocs-material site directory..."
    python -m http.server 8000 -d ./site > "\${LOGS}" 2>&1
    if [ "\$?" -ne "0" ]; then
        echo "=> python http-server failure" && cat "\${LOGS}" && sleep \${RETRY_DELAY} && exit 1
    fi
    EOF
    
  3. Create the Dockerfile:
    Create a Dockerfile that includes the following steps:

    • Copy the requirements.txt file into the Docker container.
    • Copy the run.sh script into the Docker container.
    # setup of Dockerfile
    tee Dockerfile > /dev/null <<EOF
    #############################################
    ##### Builder stage: install Python deps
    #############################################
    FROM python:3.12-slim AS builder
    
    # work dir for building Python dependencies
    WORKDIR /tmp
    
    # install required MkDocs plugins and extensions
    COPY build/requirements.txt ./requirements.txt
    RUN pip install --no-cache-dir --upgrade pip \\
      && pip install --no-cache-dir \\
            --prefix=/install \\
            -r requirements.txt
    
    #############################################
    ##### Final stage: runtime image
    #############################################
    FROM python:3.12-slim
    
    # build-time user/group IDs
    ARG PUID=1000
    ARG PGID=1000
    
    # install runtime tools
    RUN apt-get update \\
      && apt-get install -y --no-install-recommends git curl \\
      && rm -rf /var/lib/apt/lists/*
    
    # Create group 'git' and user 'debian' with matching IDs
    RUN groupadd -g "\${PGID}" git \\
      && useradd -u "\${PUID}" -g git -m debian
    
    # Create docs directory and set ownership
    RUN mkdir -p /docs && chown -R debian:git /docs
    
    # Copy installed Python packages from builder stage
    COPY --from=builder /install /usr/local
    
    # Copy the runtime script that updates repos, builds docs, and starts the server
    COPY --chown=debian:git build/run.sh /usr/src/app/run.sh
    RUN chmod +x /usr/src/app/run.sh
    
    # run the script which update repos, build docs and start server
    USER debian
    WORKDIR /docs
    ENTRYPOINT ["/usr/src/app/run.sh"]
    EOF
    
🐳 Install MkDocs with Docker Compose

Now that the compose.yml file has been generated, it's time to install all the containers.

# install and start the container
docker compose up -d

πŸš€ Deploy MkDocs

Install NGINX

NGINX needs to be installed, follow the NGINX section.

Configure NGINX

NGINX needs to be configured using a file in /etc/nginx/sites-available directory.
This configuration file specify the documentation path:

server {
  server_name mkdocs.domain.fr;

  # setup 404 error_page
  error_page 404 /404.html;
  include snippets/error-404.conf;

  # reverse proxy
  location / {
    proxy_pass http://127.0.0.1:10000;

    # keep it HTTP/1.1
    proxy_http_version 1.1;

    # forwarded headers
    include proxy_params;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;

    # timeouts for long-running sessions
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;
  }
}
# enable site for production
sudo ln -s /etc/nginx/sites-available/mkdocs.domain.fr /etc/nginx/sites-enabled/mkdocs.domain.fr

# restart nginx
sudo nginx -t && sudo service nginx restart

Replace mkdocs.domain.fr by the name of your website.

Activate HTTPS

To activate HTTPS protocol, follow theΒ Let's Encrypt section.


πŸͺ Create Git hook script

The following git hook script automatically generates the MkDocs static site whenever a git push is made.

# create post-update hook in git repository
tee post-update > /dev/null <<EOF
echo "=== restarting docker container: mkdocs-docs ==="
docker restart mkdocs-docs
echo "=== done ===\n"
exit 0
EOF

Important

Follow the Git Hook section and add this content in the script section.

Add the git user to docker group

To enable the ability to restart the mkdocs-docs container using the docker command, it is essential for the post-update script to access the file located at /var/run/docker.sock. This necessitates the inclusion of the user git to the docker group.

# add git user to the docker group
sudo usermod -aG docker git