Skip to content

Blogging with `mkdocs`

claassen.net was converted from static html and a wordpress site behind nginx on an EC2 instance to a static site generated by mkdocs hosted on S3.

The motivation

For the last ~10 years, I hosted everything on a single EC2 instance behind an ElasticIP. A couple of wordpress sites, some static sites, a couple of node apps, all through nginx. Deploy was git checkouts and some shell scripting. After having my server taken over once because of a wordpress vulnerability, I now ran all my wordpress with read-only files, so that felt decent. Just had to make them read/write for version and plugin updates. Mind you all this is very low traffic hobby sites.

But I really wanted to get to immutable deploys. Run these sites as separate docker containers I could more easily test locally and deploy was a replace. I converted one WP site to docker and figured out how to run it with ECS. Then last month I set out to decommission the EC2 and convert everything left.

My WP deploys were using the default WP container as a base, but claassen.net was structured with the blog as a sub-directory and a bunch of static site elsewhere. I considered reconfiguring the container to serve the existing hierarchy through its nginx, but in the 10 years of not posting, my tastes for authoring had moved distinctly from WYSIWYG to markdown and if I was going to get back to blogging, I wanted to go static. I briefly considered jekyll, but had been using MkDocs at work and really liked it, plus I am far more fluent in python than ruby. Some brief googling later, I found Material for MkDocs which comes out of the box with blogging support and with LoneKorean's WordPress Export to Markdown I was well on my way.

Conversion

  1. Export "All Content" from Wordpress
  2. Run npx wordpress-export-to-markdown
  3. Create virtualenv for mkdocs site project
  4. Install Material for MkDocs
    • pip install mkdocs-material[imaging] mkdocs-rss-plugin
  5. Place existing static site dump in docs
  6. Move wordpress export to expected location in static dump
  7. Start tweaking mkdocs.yml

That last step is rather imprecise, but it's basically different for everyone. The nice thing with mkdocs is that it happily handles plain static html mixed in with markdown, so you only have to convert to markdown the parts you want to be under generative control. For me that was the root and my Iloggable blog, but I also had some old archived blogs that were static exports from blogger.com, so I left them as they were.

While editing, I use mkdocs serve -a localhost:8001 to check. If I want to be sure how the actual static site will look, I build the docs and use python3 -m http.server --directory site --cgi 8001 to quickly serve up the generated files.

Deploy/Hosting

For hosting, the site is simply a public-read bucket in S3. I initially thought I'd be putting this behind the ALB that fronts all the ECS sites, but surprisingly, you can't use an ALB as a proxy to S3 (or if you can I haven't found it), so in order to get HTTPS in front of the bucket, I am using CloudFormation

Build

mkdocs build

This will place all files in site by default.

Deploy

aws s3 sync site s3://claassen.net/ --profile arne --size-only

Now the whole thing is copied to S3. I have CloudFormation set up with a short expiration time, so this is usually sufficient for publishing. If my site was actually busy enough for CloudFormation to be needed for caching rather than being the HTTPS front-end, I'd add another CLI call to invalidate the cache on push.

Future Work

The most pressing need is some kind of comment system. I probably should just use Disqus, but I really want to something along the lines of Mastodon as comment system for your static blog.

The other thing I would love is a simple, no-login Like/Emoticon button. Alternatively, tie a mastodon post directly to a blog post and use its likes. Starting to feel like adding ActivityPub support to the blog rather than subverting my existing mastodon account is the cleaner approach, but it also feels like a rabbit hole I should avoid falling down.