Projects 🔸 Articles 🔸 Categories 🔸

Building this blog with Pelican, Github Actions and Caddy

The original, blogless iteration of TVC-16 was hosted on a bog-standard Apache2 server.
My subdomains are all directly linked to Docker containers, so that very basic configuration was enough.

For blog articles though, I wanted to have something easier on the server maintenance than having to copy my html by hand. I originally considered using Ghost in yet another Docker container and doing all my writing in it, but it'd eventually be a pain to export/reimport all the data in case of a server switch.

I decided to use a static site generator like all the nerds instead and went with Pelican.

Classic stuff so far, but I don't think many people are using Github Actions for their deploying yet despite the fact that it's rad! well the fact it's in beta might be a blocker too for some people

Building in Pelican

I didn't do anything out of the ordinary in the Pelican side -- this is a hella standard blog if you ignore the theme. (Which I wholelifted from the previous nonblog version, so I can thank 2018 myself for putting in all the CSS work).

The uptime counter at the end is still generated by a crontab on the server itself and dumped to a textfile, which is just read by the JS of the website:

* * * * * uptime | awk -F'( |,|:)+' '{print $6,$7}' > /var/www/html/uptime
* * * * * uptime | awk -F'( |,|:)+' '{print $6,$7",",$8,"hours,",$9,"minutes."}' > /var/www/html/uptimedetail

Nothing wrong with a bit of Unix philosophy every now and then.

The only thing I did with Pelican that's kinda obscure unless you read the configuration file specs is having a custom template render to a custom page (the Projects):

# custom page generated with a jinja2 template
TEMPLATE_PAGES = {'projects.html': 'projects.html'}

I dropped the entire Pelican sources into a Github repo, and now it's on to the fun part:

Hot Github integrations

I already have some experience in GH Actions from writing the test suite for LANraragi, so I was expecting the setup time for this to be fairly quick. Turns out it went faster than expected!

hot github actions near your town

This building process is triggered on every push to master and is as simple as it looks:

  • Step 1: Run Pelican on the repo to build the website. This is super basic, I'm just grabbing a pelican docker image and building away.
  • Step 2: Force-push the built output folder to the gh-pages branch of the repo.

The output branch is named gh-pages because I conveniently re-used an existing Action to go faster. I don't actually use Github Pages but hey, no harm done!

🔮 Another integration I made is with the comment system: The way Microsoft made its MSDN comment system basically just Github Issues is pretty inspiring.
Utterances is an open source variant I added to my Pelican template in about 5 seconds.

As a result, both articles and comments are backed up on Github. If I ever have to switch to another Git repo provider I'd likely lose the comments, but I'm banking on those not being too important.

Deploying on TVC-16 through Caddy

A friend recently told me that I was being an old fart by still using Apache2 in the current year, so I swapped it out for Caddy.
Caddy's big advantage here lies in its http.git plugin, which automagically pulls the latest built version of the website from Github.

Here's the Caddyfile I use:, {
    root /var/www/html
    git {
        branch   gh-pages
        pull-args --allow-unrelated-histories -s recursive -X theirs
        hook /webhook mywebhooksecret

When adding in the webhook on the Github side, make sure to set the Content-Type to application/json, your hooks will fail otherwise.

The biggest issue I encountered here was that http.git does a git clone when deploying your website for the first time, then only does git pull to update it. Which is very sane if you're pulling the sources, then building the website on the server itself.

What I'm pulling however is the already-built website, which is force-pushed by the Github Actions bot every time. As such, the Git history is getting continuously broken, making regular Git pulls fail instantly.

Adding the pull arguments you see above fixes this, by telling Git to disregard history and always use remote files in case of conflict.

Final thoughts

I found out about the Github Zen endpoint when adding in webhooks. It just spits out fortune cookie sentences on each call.

12/06 Edit: While it's not very well documented, you can add custom metadata to your markdown pages and put it to work in Pelican's templates.
I wanted to change the OpenGraph image for each blogpost to a specific one for better social media presence, so I easily added a HeroImage property to my articles:

Title: Running cool-retro-term in Windows through WSL
Authors: Difegue
HeroImage: images/crt-win.jpg

And used it in my template.

<meta property="og:image" content="{{ SITEURL }}/{{ article.heroimage }}" />

Good stuff all around!