{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/misc/behind-the-blog/",
  "description": "How this blog is built: Hugo static site generator, GitHub Actions deployment, Cloudflare caching, and R2 storage. Simple, stable, and cost-free.",
  "path": "/misc/behind-the-blog/",
  "publishedAt": "2024-09-14T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Essay",
    "Hugo",
    "DevOps"
  ],
  "textContent": "When I started writing here about five years ago, I made a promise to myself that I wouldn't\ngive in to the trend of starting a blog, adding one overly enthusiastic entry about the\nstack behind it, and then vanishing into the ether.\n\nI was somewhat successful at that and wanted to write something I can link to when people\nare curious about the machinery that drives this site. The good thing is that the tech stack\nis simple and has remained stable over the years since I've only made changes when\nabsolutely necessary.\n\nMarkdown\n\nI write plain Markdown files in my editor of choice, which has been VSCode since its launch.\nOnce I'm finished, [pre-commit] runs a fleet of linters like [prettier] and [blacken-docs]\nto fix line length and code formatting.\n\nHugo\n\n[Hugo] is the static site generator that turns the Markdown files into HTML. I chose it\nbecause I needed something that can build the site quickly, even with lots of content. It\nlets me hot reload the server and check my changes as I write. Plus, I don't get to write Go\nat work, so messing with Hugo templates or its source code gives me a reason to play around\nwith Go.\n\nI initially tried some JS-based SSGs but dropped them pretty quickly because I couldn't keep\nup with the constant tooling changes in the JavaScript universe. I use a handrolled theme\nand have tweaked the CSS over time.\n\nGitHub Issues\n\nI use [GitHub Issues] to brainstorm ideas and keep track of my writing. I usually gather\nideas throughout the week, log them in Issues, and then write something over the weekend.\nThis workflow is heavily inspired by [Simon Willison's blog] on his workflow.\n\n![image_1]\n\nGitHub Actions and GitHub Pages\n\nOnce I push content to the main branch, [GitHub Actions] automatically runs, checks the\nlinter, builds the site, and deploys it to [GitHub Pages]. There's nothing to maintain, and\nI don't have to worry about scaling, even if one of my posts hits the front page of Hacker\nNews. Aside from the domain, this site costs me nothing to run, and I plan to keep it that\nway.\n\nCloudflare Cache and R2\n\nI'm a huge fan of Cloudflare and often try to shoehorn their offerings into my projects.\nSince my domain is registered with them, setting up their proxy with my domain's DNS and\nturning on caching took just a few minutes. Their caching layer absorbs most of the traffic,\nand less than 10% of the requests hit the origin server. Plus, having the proxy layer gives\nme access to more accurate analytics.\n\n![image_2]\n\nStatic assets like images, CSS, JS, and other files are stored on [Cloudflare R2]. I used to\nhost my images with GitHub Issues and serve CSS and JS from the origin, but I recently\nswitched everything to R2. Now I can manage it all from one place without worrying about\ncosts. Their free plan is super generous - there's no egress bandwidth fee, and because of\ncaching, I barely use any of the quota. It's fantastic!\n\n![image_3]\n\nOxipng\n\n[Oxipng] is used to compress images before uploading them to the Cloudflare R2 bucket with\nthe [wrangler] CLI. The Makefile in the repo has a single command called upload-image that\nhandles compression and upload in one go.\n\nI just drop the screenshots and images into /static/images/<blog-name>/*.png, update the\nreferences in the Markdown file, and run\nmake upload-image local_path=<file> remote_path=<bucket-path> before pushing the changes\nto the repo.\n\nGoogle Analytics\n\nI'm still using [Google Analytics], even though I'm not a huge fan. Cloudflare already gives\nme better traffic insights, but the free version doesn't show how many hits each page gets.\nAt some point, I might just pay for Cloudflare's upgraded plan so I can get rid of the\nbulky, intrusive analytics scripts for good.\n\nThe [source code] and content for this site are all publicly available on GitHub.\n\n\n\n\n[pre-commit]:\n    https://pre-commit.com/\n\n[prettier]:\n    https://prettier.io/\n\n[blacken-docs]:\n    https://pypi.org/project/blacken-docs/\n\n[hugo]:\n    https://gohugo.io/\n\n\n[github issues]:\n    https://github.com/rednafi/rednafi.com/issues/125\n\n[simon willison's blog]:\n    https://simonwillison.net/2022/Nov/26/productivity/\n\n[github actions]:\n    https://github.com/features/actions\n\n[github pages]:\n    https://pages.github.com/\n\n[cloudflare r2]:\n    https://developers.cloudflare.com/r2/\n\n[oxipng]:\n    https://github.com/shssoichiro/oxipng\n\n\n[wrangler]:\n    https://developers.cloudflare.com/workers/wrangler/\n\n[google analytics]:\n    https://analytics.google.com/\n\n\n[source code]:\n    https://github.com/rednafi/rednafi.com\n\n\n[image_1]:\n    https://blob.rednafi.com/static/images/behind_the_blog/img_1.png\n\n\n[image_2]:\n    https://blob.rednafi.com/static/images/behind_the_blog/img_2.png\n\n\n[image_3]:\n    https://blob.rednafi.com/static/images/behind_the_blog/img_3.png",
  "title": "Behind the blog"
}