Creating your own documentation with Mkdocs and Obsidian
Creating your own documentation with Mkdocs and Obsidian
Overview
One of the most important parts of being in any highly technical profession is documentation.
There are many products centered around doing this, even plenty that are free and open source as I prefer.
However, many of these products rely on databases and force me to use editors that are not my preference.
I like keeping my notes in Markdown format, so that they are both portable and can be manipulated with common tools on the Linux command line like grep, awk, sed.
This also allows me to keep them in version control.
However, I also enjoy the convenience of having a web portal that’s easily accessible from any device, and searchable even from my phone.
Full disclosure, this guide assumes at least some knowledge about Docker and Git - if I tried to get into those too, this post would be miles long.
The Tools
These are the tools that I use to do my documentation:
The Static Site Generator
- Material for Mkdocs - This takes in Markdown files and generates HTML from them, allowing you to serve that content as a website.
- You’ll also need the Mkdocs Obsidian Bridge plugin so that Mkdocs can understand the Obsidian-style wikilinks. Links like this -
[[My Note]]are Obsidian style links.
Editors
I enjoy the ideas behind the Obsidian project, but my issues with it are:
- It’s closed source.
- I like doing all my writing in Neovim. You’ll want to install the Obsidian.nvim plugin to allow it to interact more natively with Obsidian vaults.
You can apply all of these ideas using the actual Obsidian editor (or any other editor with Markdown support) if you so choose.
I do, however, use the Obsidian mobile app when I need to write notes on mobile. The GitSync Android app allows me to keep the remote repository in sync.
Continuous Deployment Workflow
I’m accomplishing this with Forgejo and an Nginx webserver.
The Workflow
- I edit all of my notes in Markdown using Neovim.
- I push the changes to my Forgejo repository.
- Forgejo has a configured Action that builds the site using a Runner and then copies it to Docker webserver.
The reason I like this so much is that it reduces friction for entering notes significantly, and also allows me to link notes together logically.
Setting It Up
If you want to get this set up yourself you can follow these steps.
-
Install the Obsidian official app and create the vault. There’s probably a way to do this without installing it, but to make sure that it’s formatted correctly and has the correct directory structure, this is the easiest way.
-
Install the
obsidian.nvimplugin (optional, only if you’re using Neovim). -
Create a .gitignore file to exclude some files that are problematic or unnecessary to keep in git.
cd $VAULT vim .gitignoreThe file should have the following contents:
.obsidian/workspace*.json .obsidian/plugins/recent-files-obsidian/data.json site/ # This is where Material for Mkdocs will build your site by default. There's no need to include this in Git version control. -
Create a new git repository in the same directory as your Obsidian vault.
git init git switch -c main git add . # Or add only a subset of files if you wish git commit -m "initial commit" git remote add origin ssh://[email protected]/example/docs.git # Add an existing remote git push -u origin main # Push your local changes to the remoteAt this point if you log into the repository you created, you should see the raw markdown files from your Obsidian vault.
-
Now, we’ll create a new file at the root of your repository called
mkdocs.yml. This file is how you configure the mkdocs site. Here’s mine with some information redacted.--- site_name: Documentation site site_url: https://wiki.example.tld repo_name: ssbtech/wiki repo_url: https://git.example.tld/ssbtech/wiki edit_uri: 'docs/' theme: name: material features: - navigation.indexes - navigation.instant - content.code.copy language: en favicon: assets/images/homer.png icon: repo: fontawesome/brands/git-alt logo: fontawesome/regular/folder-open palette: # Palette toggle for light mode - media: "(prefers-color-scheme: light)" scheme: default primary: blue accent: teal toggle: icon: material/brightness-7 name: Switch to dark mode # Palette toggle for dark mode - media: "(prefers-color-scheme: dark)" scheme: slate accent: teal primary: black toggle: icon: material/brightness-4 name: Switch to light mode markdown_extensions: - admonition - attr_list - md_in_html - mdx_truly_sane_lists - toc: permalink: true - def_list - pymdownx.tasklist: custom_checkbox: true plugins: - search - obsidian-bridge - tags: -
Install mkdocs and its plugins.
pip install mkdocs-material mkdocs-obsidian-bridge mdx_truly_sane_lists -
You can test the site by running
mkdocs serve. It will build the site and expose it on port 8000, so you can see what it looks like. -
Every git forge is a little different on how you can configure your Actions, but this is how I have mine configured on Forgejo:
name: Build and Deploy Wiki on: [push] enable-email-notifications: true jobs: deploy: runs-on: wiki container: image: squidfunk/mkdocs-material:9.7.6 steps: - name: Install dependencies run: | apk add --no-cache nodejs # needed for the Forgejo checkout action apk add rsync openssh-client pip install mkdocs-obsidian-bridge mdx_truly_sane_lists - uses: actions/checkout@v4 - name: Build site run: mkdocs build - name: Deploy via rsync run: | eval $(ssh-agent -s) mkdir -p ~/.ssh chmod 700 ~/.ssh echo "${{ secrets.SSH_PRIVATE_KEY }}" | tr -d '\r' | ssh-add - > /dev/null rsync -az --delete -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" site/ ${{ secrets.USERNAME }}@${{ secrets.HOST }}:/srv/mkdocs-wiki/html/ - name: Upload artifacts uses: https://github.com/christopherHX/gitea-upload-artifact@v4 with: name: site path: site/ -
The last step is to set up Nginx to point and serve that directory, preferably with a valid SSL certificate.
The end result looks something like this:

Slick, clean, easily searchable, and trivially easy to move elsewhere.