MkDocs in a Docker container

For an internal presentation “Text-based tools, not just for nerds” (presentation is mostly in Dutch) I wanted to demo MkDocs with the material theme.

The creator of the mkdocs-material theme already created the Docker image as an alternative way to try the theme.

I wanted to run it with a minimal configuration but no errors and no extra’s. The result is this simple bash script.

MkDocs in a Docker container
'docs' and 'site' directory on the local disk to seperate content and configuration from the application

Quick Setup or TL;DR version

  • Download/copy and create the script ''
  • Make it executable: chmod +x
  • Run the setup script: ./
  • Run the just created start script: ./start
  • Open a browser and go to: 'localhost:8001'

Create new content:

  • Add a new ‘.md’ file and add it to the ‘nav’ section in ‘mkdocs.yml’

It will automagically show up in the browser in the left sidebar.

A running Docker environment is a requirement.

#!/usr/bin/env bash

# Create docs directory
if [ ! -e docs ]; then
  mkdir docs

# Create images directory
if [ ! -e docs/images ]; then
  mkdir docs/images

# Create site directory
if [ ! -e site ]; then
  mkdir site

# Create the first document 
if [ ! -e docs/ ]; then
  printf "# Hello material world!\n" >> docs/

# Create mkdocs.yml
if [ ! -e mkdocs.yml ]; then
  printf "site_name: '[site name here]'\nsite_url: http://localhost\nsite_dir: '/site'\n\nnav:\n  - Home:\n\ntheme:\n  name: 'material'\n" >> mkdocs.yml

# start file
printf \
"#!/usr/bin/env bash\n
echo 'Connect your browser to'\${EXPOSED_PORT}\n  
docker run --rm --name mkdocs-material -it -p \${EXPOSED_PORT}:8000 -v \${PWD}:/docs -v \${PWD}/site:/site squidfunk/mkdocs-material" > start
chmod +x ./start

# build-file
printf "#!/usr/bin/env bash\n\ndocker exec -it mkdocs-material mkdocs build" > build
chmod +x ./build

What the script does

The script creates the following:

  • ‘docs’ and ‘site’ directories, required
  • ‘’, the first content
  • ‘mkdocs.yml’, minimal configuration file
  • ‘start’, bash script that runs the container if the image is present otherwise it first downloads the Docker image (standard Docker behaviour)
  • ‘build’, bash script that builds the site and copies it to the 'site' directory

Additionally the ‘start’ and ‘build’ scripts are made executable.

Start script

You can configure the Docker exposed port in the ‘start’ script. For my demo I used Reveal.js which runs by default on port 8000.
By default the container uses port 8001, you can change it by changing the value of the 'EXPOSED_PORT' variable.

WARNING: Do not change the name of the container, build script uses the name to find the running container.

Build script

The build script only works when the Docker container ‘mkdocs-material’ is running. The easiest way is to run it in a different terminal.

MkDocs requirements

MkDocs expects:
- ‘docs’ directory with a file named ‘’.
- ‘mkdocs.yml’ in the root of the ‘mkdocs’ directory

Required for the build step:
- ‘site’ directory at the same level as the “docs” directory.

 └── [for the build output]

These minimal requirements are handled by the ‘’ script.

Full configuration

The setup above is the bare minimum. No customized logo, a site_url that directs to the local machine, no markdown extensions etc. etc.

Examples of a full setup with the file structure and anonimized configuration files can be found below:

file structure

 └── [your .md content]
 └── images
      └── [your logo].png
      └── [your logo]-192.png
      └── [your logo]-512.png
 └── [build output]


site_name: '[your site name]'
site_description: '[your site description]'
site_author: '[your name]'
copyright: 'Copyright © 2019 [your name]'
site_url: http://[your site location]
# Location where the output HTML and other files are created,
# the path is local in the Docker container but redirected to the 'site' directory.
site_dir: '/site'

  - Home:

  name: 'material'
  language: 'en'
  logo: 'images/[your logo]'
    tabs: false
    primary: 'indigo'
    accent: 'indigo'
  font: false

  manifest: 'manifest.webmanifest'
    - type: 'github'
      link: '[your GitHub account]'
    - type: 'twitter'
      link: '[your Twitter handle]'
    - type: 'linkedin'
      link: '[your LinkedIn shortname]/'

# Extensions
  - admonition
  - codehilite:
      guess_lang: true
  - toc:
      permalink: true
  - nl2br
  - sane_lists
  - footnotes
  - pymdownx.betterem
  - pymdownx.details
  - pymdownx.escapeall
  - pymdownx.keys
  - pymdownx.mark
  - pymdownx.smartsymbols
  - pymdownx.tasklist
  - pymdownx.tilde


  "short_name": "[short name]",
  "name": "[name]",
  "icons": [
      "src": "/images/[your logo]-192.png",
      "type": "image/png",
      "sizes": "192x192"
      "src": "/images/[your logo]-512.png",
      "type": "image/png",
      "sizes": "512x512"
  "start_url": "/",
  "background_color": "#3367D6",
  "display": "browser",
  "scope": "/",
  "theme_color": "#3367D6"

Kudos go to the MkDocs community and SquidFunk for the Material theme.