A bit over a week ago my friend Sam restarted his blog with a post about How [he] built this site. I’d been planning to write my own version of that post in the future, however I decided to do so sooner since our approaches have noticeable differences.

I’m using Hugo as a static site generator for the content so that rebuilding the blog is as easy as deleting the public/ folder then recreating it using the hugo command. I’m not going to go into the full details of my blogging workflow at this time beyond saying I write the posts in Emacs Org-Mode and use ox-hugo to generate the appropriate markdown files for the posts themselves. My Techdocs site uses the exact same process just with a different theme that is better designed to handle documentation.

Hosting Hugo

Hugo can publish to GitHub pages which means all you need is a domain name, and even that can be skipped if you don’t mind using the GitHub branded URL. In my case I have a handful of low cost VPSes that are part of my Homelab environment and already have one running Caddy as the reverse proxy1 for all my exposed services, which makes it perfect for hosting my site.

A small addition to my Caddyfile and I had an easy way to host my sites. The missing portions relate to my exposed homelab services and so are omitted since they are not relevant.

/etc/caddy/Caddyfile

1# [...] other configuration omitted for brevity
2# static sites
3docs.leechpepin.com,
4blog.leechpepin.com {
5        root * /var/www/{host}
6        file_server
7}

Publishing to a private server

Publishing is almost as simple, even though not quite what I want as a long term solution, I have a pre-commit hook2 set up to run pre-push that handles the rsync push to the VPS. A typical workflow might be to use GitHub CI (or the equivalent with your git repository site of choice) to publish the site once the commit reaches the repository. In my case this would require adding appropriate credentials to the CI systeml to allow it to connect to the VPS whereas using a pre-push hook leverages my existing SSH credentials to establish that connection. It also handles all the usual pre-commit linting and validation I want so that my repo stays in a consistent state. All it took was installing the hooks (including pre-push requires explicitly specifying all the desired hook types)

1pre-commit install -t pre-commit -t pre-push

.pre-commit-config.yaml

 1repos:
 2- repo: https://github.com/pre-commit/pre-commit-hooks
 3  rev: v4.4.0
 4  hooks:
 5    - id: trailing-whitespace
 6    - id: end-of-file-fixer
 7    - id: check-yaml
 8    - id: check-added-large-files
 9
10- repo: local
11  hooks:
12    - id: hugo-syntax-check
13      name: Hugo syntax check
14      entry: hugo --logLevel warning --renderToMemory
15      language: system
16      pass_filenames: false
17      types: [file]
18      files: '\.(md|html|toml|yaml)$'
19      stages: [pre-commit]
20    - id: hugo-publish
21      name: Publish Hugo
22      entry: bash -c "hugo && rsync -rlz --delete public/ jlpgreencloud:/var/www/blog.leechpepin.com"
23      language: system
24      pass_filenames: false
25      stages: [pre-push]

With this once a post is in a ready-to-publish state it gets built and uploaded to my blog the next time I push it to a repository.

How my Techdocs differ

As I had mentioned, the majority of the workflow for my Techdocs site is identical to how my blog is handled. The main differences are outlined below:

  • The hugo-publish pre-commit hook points to /var/www/docs.leechpepin.com for the rsync task.
  • Instead of being treated as posts, the pages are stored in a docs/ directory and have a nested structure to leverage the Leaf and Branch bundling functionality to create a structured layout.
  • Comment and Sharing functionality is not added since my intent is for it to be a set of reference documents.

  1. A reverse proxy is a webserver that handles incoming requests by forwarding them to the appropriate server, application or static content. ↩︎

  2. A pre-commit git hook runs before a git commit is made to validate the content being committed. A pre-push hook runs before the push is performed either for further validation or, as in this case, to do extra tasks using the system doing the pushing. ↩︎