Building My Blog with Obsidian, MkDocs, GitHub Pages, and a Custom Domain¶
I finally built the personal blog I’ve been putting off for years—no CMS, no server, no overengineering. Just Markdown files, a clean static site generator, and a custom domain. In this post, I walk through how I used Obsidian, MkDocs, and GitHub Pages to get everything up and running with as little friction as possible.
I don't care about the fluff, get to the good stuff!
Make it Real, Then Make it Pretty¶
I’ve been meaning to set up a personal blog for… longer than I’d like to admit. A common pitfall is to overthink or overengineer every aspect until you have a perfect outline of your project. However, this can lead to another pitfall: scope creep. The project ballooned to such a scale that starting it became overwhelming and I felt that if I can't make it perfect from the start, it's just not worth pursuing in the first place.
Cut to me about a month ago when I was surfing the internet and I stumbled upon an elegant phrase, "Make it Real, then Make it Pretty". It reminds me of another phrase from Silicon Valley, "Move fast and break things", but it doesn't carry this undertone of disregarding quality to plant your flag as the "first". So let's make something that's nice to start, and can be improved later.
To start, I needed a setup that removed as much friction as possible. I didn't want to mess around with databases, plugins, or managing a server just to publish a blog post. I also didn't want to give up control by committing to a locked-in platform or bloated CMS.
So I looked at what I already had:
- I'm already familiar with Obsidian and use it for my personal notes. Why not keep it there?
- MkDocs turns Markdown into clean, static HTML with minimal fuss. I'm using mkdocs-material to get a theme that users would likely already be familiar with.
- GitHub Pages handles hosting for free, which is great for now and we can always move it if the traffic gets to be too much.
- A custom domain ties it all together and makes it feel like a real website instead of a weekend experiment.
No JavaScript frameworks. No dark magic. Just Markdown, version control, and a simple build pipeline.
In the rest of this post, I’ll break down how I set it all up—from writing in Obsidian to pointing my domain at GitHub Pages. If you’re looking for a lightweight way to publish your notes or projects, maybe this approach will work for you too.
Writing in Obsidian¶
Obsidian is already where I do most of my writing—whether it's jotting down guitar maintenance notes, organizing my D&D campaign, or keeping track of random ideas that may or may not turn into real projects. There's a time and place for learning and using new tools but given the small scope of the project, Obsidian will work well.
For this blog, I spun up a separate vault to keep things tidy. Posts are just Markdown files in folders—no database, no proprietary format, no special syntax. Just text, which is exactly how I like it. Here's the file structure I'm going with:
blog/
├─ .git/
├─ .github/
├─ .obsidian/
├─ docs/
│ ├─ posts/
│ │ ├─ hello-world.md
│ │ ├─ this-blog-post.md
│ ├─ index.md
├─ .gitignore
├─ mkdocs.yml
Because I’m already comfortable in Obsidian, writing posts feels no different from taking notes. That lowered the friction even more. I don’t have to shift mental gears to switch between “note-taking mode” and “blog-writing mode.” It’s all the same habit, just pointed at a slightly different output.
Anything that I write in the docs/posts
folder will be published, unless it's been tagged as a draft
. At the top of the document I can establish some tags that work in Obsidian and can be read by MkDocs to add metadata.
---
draft: true
date: 2025-04-24
slug: obsidian-blog
categories:
- Web Development
tags:
- how-to
---
Once I'm happy with a post, I just flip draft
to false
and push the changes to Github where automation takes care of the rest.
Setting Up MkDocs¶
With the writing side handled in Obsidian, the next step was turning those Markdown files into a real website. For that, I used MkDocs, a static site generator built for Markdown-based documentation.
Rather than start from scratch, I used obsidian-publish-mkdocs, a ready-to-go template that handles a lot of the initial setup: folder structure, theme, and sensible defaults. After cloning the repo, I just updated a few fields in the mkdocs.yml
file to match my project.
Here’s a look at the main config:
site_name: Nanda's Adventures in Everything
theme:
name: 'material'
palette:
# Light mode
- media: '(prefers-color-scheme: light)'
scheme: default
primary: light blue
accent: orange
toggle:
icon: material/weather-night
name: Switch to dark mode
# Dark mode
- media: '(prefers-color-scheme: dark)'
scheme: slate
primary: light blue
accent: orange
toggle:
icon: material/weather-sunny
name: Switch to light mode
# Extensions
markdown_extensions:
- nl2br
- admonition
- footnotes
# - attr_list
- pymdownx.arithmatex:
generic: true
- pymdownx.superfences
- pymdownx.details
# - pymdownx.magiclink
- pymdownx.tasklist:
custom_checkbox: true
- def_list
- pymdownx.critic
- pymdownx.caret
- pymdownx.keys
- pymdownx.mark
- pymdownx.tilde
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
- toc:
permalink: true
plugins:
- callouts
- search
- roamlinks
- blog:
blog_dir: .
- rss:
site_url: nandascott.me
match_path: blog/posts/.*
date_from_meta:
as_creation: date
categories:
- categories
- tags
extra_javascript:
- javascripts/mathjax.js
- https://polyfill.io/v3/polyfill.min.js?features=es6
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
- https://unpkg.com/mermaid/dist/mermaid.min.js
The main tweaks are updating the site_name
, changing the palette
colors and light/dark mode icons, and setting the plugins.blog
and plugins.rss.site_url
to my custom domain name.
Quick Tip
If you ever add a new plugin you'll need to add the pip install
command to your .github/workflows/ci.yml
As of writing we can set up local testing as follows, but as always reference the official docs in case that changes.
Install:
pip install mkdocs-material
Serve:
mkdocs serve
Build:
mkdocs build
Quick Tips
You may want to make sure you've got the right packages installed first. You can run mkdocs get-deps
to install them with pip install
. For this project I needed to run:
pip install mkdocs mkdocs-material mkdocs-roamlinks-plugin mkdocs-rss-plugin pymdown-extensions
I also needed to add this folder to my
PATH
export PATH="$PATH:$HOME/.local/bin"
At this point, everything’s ready to deploy—which brings us to GitHub Pages.
Deploying with GitHub Pages¶
With the site built and ready, the last step was getting it online. I’m using GitHub Pages to host the site because:
- It’s free.
- It works well with static sites.
- I’m already using GitHub for version control, so deployment is just a push away.
The obsidian-publish-mkdocs
template came with GitHub Actions already set up. Anytime I push to the main
branch, it runs mkdocs build
and publishes the contents of the site/
folder. No extra CI/CD setup needed.
To enable GitHub Pages:
- Go to your repo’s Settings → Pages.
- Under Build and deployment, make sure the Source is set to "Deploy from a branch" and that the
gh-pages
branch is set, and the folder is/ (root)
. - Under Custom domain, I added my domain
nandascott.me
.
I also needed to add a CNAME
file under docs/
which tells Github to serve the site at your domain instead of the default <username>.github.io
.
Info
Be sure to double check that the RSS plugin also has your site_name
or else it won't build correctly.
Setting Up the Custom Domain¶
I moved my domain (nandascott.me
) to Squarespace Domains after Google Domains got sunsetted. The DNS setup was pretty painless.
I bought the domain initially on Google Domains, but after that got sunsetted and added to the pile it was transferred to Squarespace Domains. Still the DNS setup was pretty standard and painless.
After navigating to the DNS Settings section I added these under the custom records section:
Host | Type | Priority | TTL | Data |
---|---|---|---|---|
@ | A | N/A | 30 mins | 185.199.108.153 |
@ | A | N/A | 30 mins | 185.199.109.153 |
@ | A | N/A | 30 mins | 185.199.110.153 |
@ | A | N/A | 30 mins | 185.199.111.153 |
www | CNAME | N/A | 30 mins | nandascott.github.io |
I set the TTL to 30 minutes because I was impatient with seeing if my changes worked, there's not really a reason to have it set that aggressive. I also want to use this domain for other things, so maybe later I'll look at having this blog hosted at blog.nandascott.me
. This works well enough for now though.
Back on GitHub, I enabled the “Enforce HTTPS” option under Pages once the DNS changes propagated. Github does also have a DNS check button to make sure you've set it up correctly.
DNS propagation can take a little while—mine kicked in within an hour, but YMMV.
Wrapping Up¶
This setup isn’t groundbreaking, but that’s kind of the point. It’s simple, reliable, and gets out of the way so I can focus on writing. No CMS to manage, no servers to maintain, and no need to learn a new stack just to post a few thoughts on the internet.
Could it be prettier? Sure, I already have plans to tweak the theme or just write my own. Could it be more powerful? Definitely, but I'm not expecting an audience of millions to read this blog. But for now, it’s real—and that’s what matters. I can always tweak the design later, add more automation, or split things out into subdomains if this grows beyond a handful of posts.
If you’ve been meaning to spin up a blog and keep finding ways to overcomplicate it, maybe try something like this. Use tools you already know, don’t sweat the details up front, and just get the thing online. Make it real. Make it pretty later.
Quickstart Summary¶
- Clone the template
Use obsidian-publish-mkdocs as your starting point. - Write in Obsidian
- Use a dedicated vault.
- Save posts as Markdown in
docs/posts/
.
- Update
mkdocs.yml
- Set
site_name
, theme colors, and plugin settings. - Add your custom domain under
plugins.rss.site_url
.
- Set
- Install dependencies and build locally
pip install mkdocs-material
mkdocs serve
mkdocs build
- Deploy to GitHub Pages
- Push to GitHub.
- In repo settings → Pages, select
gh-pages
branch, root folder. - Add
CNAME
file underdocs/
with your domain name.
- Point your domain
- In Squarespace DNS settings, add the following records:
- Enable “Enforce HTTPS” in GitHub Pages settings once DNS changes propagate.
Host | Type | Priority | TTL | Data |
---|---|---|---|---|
@ | A | N/A | 30 mins | 185.199.108.153 |
@ | A | N/A | 30 mins | 185.199.109.153 |
@ | A | N/A | 30 mins | 185.199.110.153 |
@ | A | N/A | 30 mins | 185.199.111.153 |
www | CNAME | N/A | 30 mins | nandascott.github.io |
Done. You now have a fast, Markdown-based blog that lives on your domain.