post: 0001-hello-friend
All checks were successful
Build and deploy website / Build and Push Hugo Site (push) Successful in 47s
All checks were successful
Build and deploy website / Build and Push Hugo Site (push) Successful in 47s
This commit is contained in:
parent
132263b938
commit
5cb1e60fc3
2 changed files with 241 additions and 72 deletions
241
content/post/0001-hello-friend/index.md
Normal file
241
content/post/0001-hello-friend/index.md
Normal file
|
@ -0,0 +1,241 @@
|
|||
---
|
||||
title: Hello, Friend
|
||||
description: So I've decided to have a blog
|
||||
slug: hello-friend
|
||||
date: 2025-04-20 22:28:00+0200
|
||||
categories:
|
||||
- Technology
|
||||
- Projects
|
||||
tags:
|
||||
- homelab
|
||||
- self-hosting
|
||||
- docker-compose
|
||||
- Hugo
|
||||
---
|
||||
|
||||
## Introduction
|
||||
This is -- technically -- not my first time hosting a blog, but it *is* the
|
||||
first time this decade.
|
||||
|
||||
The first time I tried hosting a blog was in 2009, the year I got my domain.
|
||||
The domain came with an introductory offer of free web hosting for a year. So I
|
||||
figured out just enough MySQL and FTP to yeet a WordPress installation on there
|
||||
and make it run. As I remember it, I got as far as installing a custom theme I
|
||||
really liked and writing maybe three posts, all within the first month. Then
|
||||
the blog just sat there until the hosting expired, untouched.
|
||||
|
||||
The second time was a bit later, after I got into self-hosting. The Internet
|
||||
Archive says it was 2018 [[1]], so it must be true. That time, I never
|
||||
actually posted anything—I was mainly just interested in deploying the site.
|
||||
|
||||
Which brings us to now: the third attempt. This time, the marginal cost of
|
||||
setting up a blog is negligible since I’m already self-hosting plenty of
|
||||
services for personal use. That doesn’t mean I’ll be more active than before,
|
||||
but the blog will probably stay up longer than a few months.
|
||||
|
||||
## Why a blog?
|
||||
What reasons do I have for keeping a blog, aside from the challenge of setting
|
||||
up the infrastructure and implementation?
|
||||
|
||||
I guess I have a confession to make. Though maybe it’s not really a
|
||||
confession—because I think it’s true for pretty much every technically inclined
|
||||
person in a technical field for the love of it: I have way too many personal
|
||||
projects. Some of them I finish, but most never get touched.
|
||||
|
||||
I see the blog as a way of keeping myself accountable: keep projects small
|
||||
enough to fit in a blog post (or make them blog-post-divisible), and prioritize
|
||||
the ones that are interesting enough to write about.
|
||||
|
||||
Also, finishing a personal project with a blog post gives it a sense of
|
||||
closure. It’s like informal documentation or a post-mortem analysis. There’s
|
||||
always stuff I’d like to improve, but if I keep focusing on the same thing
|
||||
forever, the list of things I want to do will never shrink.
|
||||
|
||||
Another benefit of writing everything down: it’ll serve as a reference for
|
||||
future-me when I inevitably forget what I did or how I did it. Thinking of
|
||||
future-me using this as a reference also forces present-me to be a bit more
|
||||
thorough, even if I don’t expect many people to read it.
|
||||
|
||||
And finally, as always, it’s about the journey, not the destination. I’m not
|
||||
expecting every post here to be about a completed project—but they will all be
|
||||
about something I found interesting enough to write down.
|
||||
|
||||
### Yes, but why a **blog**?
|
||||
All those reasons are fine, but none of them actually require a blog. I could
|
||||
write tweets (lol), Facebook posts, TikToks. Even if I want to self-host, I
|
||||
could use Mastodon instead of a blog.
|
||||
|
||||
A blog is… *old people media*. And I’m not *old people*, right?
|
||||
|
||||
In this case (and not only… *womp womp*) I am old people. I still prefer the idea
|
||||
of smaller, distributed, simple sites and services like in the old internet,
|
||||
rather than the centralized, data-mining, attention-grabbing mess we have now.
|
||||
Also, Mastodon just doesn’t feel like the right format. It’s definitely what
|
||||
I’d use instead of Twitter, but not for “documentation.”
|
||||
|
||||
A blog feels more fitting. It’s extremely free-form, no size limits either way.
|
||||
I can define groups, filters, organize stuff with labels…
|
||||
|
||||
## How a blog
|
||||
Now that I'm settled on the *why*, let's take a look at the *how*.
|
||||
|
||||
### Different concepts (CMS vs static websites)
|
||||
Keeping with the “old internet” spirit, one of the first requirements I nailed
|
||||
down—besides self-hosting—was that the blog should be statically generated. I
|
||||
did try deploying Ghost [[2]], and I appreciated its polish (everything looks
|
||||
great on that platform). But I quickly realized any CMS would be overkill for
|
||||
what I’m trying to do, and it’d diverge from the simple, GitOps-style
|
||||
deployment I want.
|
||||
|
||||
So on one hand, CMSs are polished but come with way too many features I won’t
|
||||
use. On the other hand, using a static site generator lets me write posts in
|
||||
Markdown, push them to git, and have them deployed automatically with CI/CD.
|
||||
EZ.
|
||||
|
||||
### The vast world of static website generators
|
||||
Once I decided to go with a static site generator, I discovered—of course—there
|
||||
are a lot of them. There’s even an `awesome` GitHub page [[3]] listing a bunch,
|
||||
but it was honestly overwhelming.
|
||||
|
||||
After some browsing, mostly through Google and Reddit, I narrowed it down to
|
||||
two main contenders: Jekyll and Hugo.
|
||||
|
||||
Jekyll is the older, more established option. Tons of GitHub stars, tons of
|
||||
themes.
|
||||
|
||||
Hugo is the newer option—fewer stars, but written in Go and supposedly much
|
||||
faster. Looked solid, too.
|
||||
|
||||
#### Decision
|
||||
For my use case, the differences weren’t that important. Faster compilation
|
||||
doesn’t matter when deploying via CI/CD. The language it’s written in doesn’t
|
||||
make a real difference.
|
||||
|
||||
In the end, I just looked for themes. I stumbled on this one called Chirpy
|
||||
[[4]] and liked it best. So: Jekyll it is.
|
||||
|
||||
#### Decision, revisited
|
||||
Or… is it?
|
||||
|
||||
One thing I kept noticing when looking up “Jekyll vs Hugo” was how everyone
|
||||
wrote blog posts about migrating from Jekyll to Hugo. I found none going the
|
||||
other way. And everyone mentioned how annoying the migration was.
|
||||
|
||||
So I figured, why not try Hugo before committing? I quickly deployed a Hugo
|
||||
site and… yeah, it compiled much faster, even with just three articles. Went
|
||||
from four seconds to under one. Not a big deal now, but it scales.
|
||||
|
||||
Plus: Hugo auto-refreshes the page on save (nice), and it’s more
|
||||
self-contained—easier to install and maintain, which is great for CI.
|
||||
|
||||
Long story short: I found a Hugo theme similar to Chirpy and migrated
|
||||
everything over even before the blog technically went live. Win-win?
|
||||
|
||||
### Infrastructure Both of the themes I looked at are designed for easy GitHub
|
||||
Pages deployment. Fork the theme, add your content, push—CI/CD handles the
|
||||
rest.
|
||||
|
||||
But where’s the fun in that? Hosting it on GitHub isn't very “old internet”,
|
||||
and I’m already self-hosting my own git forge, so everything’s ready to go.
|
||||
|
||||
#### Self-Hosting I had a few options for deployment. My first idea was to go
|
||||
self-contained: after the site is built, the files get copied into an nginx
|
||||
container and pushed to my forgejo container registry. Then it’s deployed via
|
||||
Docker Compose and updated by Renovate.
|
||||
|
||||
I tried this—and while it’s straightforward to implement—it didn’t sit well
|
||||
with me. Renovate only updates the digest after a new image is published, so
|
||||
every deployment meant two commits: noisy. Also, building a whole nginx image
|
||||
just to serve a few static files felt redundant—especially when I already have
|
||||
an nginx image serving static pages for another service.
|
||||
|
||||
So I went with a more “traditional” route: after the site is built, it’s copied
|
||||
via SSH to a target machine where the folder is mounted to the existing nginx
|
||||
container. Easier, faster, less overhead.
|
||||
|
||||
In the end, the meat of the deployment is in the publish workflow, which can
|
||||
also be referenced in the repository itself [[5]]:
|
||||
|
||||
```yaml
|
||||
name: "Build and deploy website"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- .gitignore
|
||||
- README.md
|
||||
- LICENSE
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "blog"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-push:
|
||||
name: Build and Push Hugo Site
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Build and test site
|
||||
|
||||
- name: Cache Hugo resources
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-hugo-resources
|
||||
with:
|
||||
path: resources
|
||||
key: ${{ env.cache-name }}
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "^1.17.0"
|
||||
- run: go version
|
||||
|
||||
- name: Setup Hugo
|
||||
uses: https://github.com/peaceiris/actions-hugo@v2
|
||||
with:
|
||||
hugo-version: "latest"
|
||||
extended: true
|
||||
|
||||
- name: Build
|
||||
run: hugo --minify --gc
|
||||
|
||||
- name: Copy website to destination server
|
||||
uses: https://github.com/garygrossgarten/github-action-scp@release
|
||||
with:
|
||||
local: public
|
||||
remote: /srv/docker/nginx/html/blog
|
||||
host: ${{ secrets.SSH_HOST }}
|
||||
port: ${{ secrets.SSH_PORT }}
|
||||
username: ${{ secrets.SSH_USER }}
|
||||
privateKey: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
rmRemote: true
|
||||
```
|
||||
|
||||
## Rules... Nay, guidelines
|
||||
- I don’t do projects to write a blog post. I write blog posts to document
|
||||
projects.
|
||||
|
||||
- No promises about future posts. That **never** works out (I’ll explain why
|
||||
that is… in a future post).
|
||||
|
||||
## What to expect, and how often can be expected No expectations. No schedule.
|
||||
No guarantees of quality or consistency. You’ve been warned.
|
||||
|
||||
**Postscriptum**: I started writing this post on April 7th, but only managed to
|
||||
publish it now. Is that an indicator of how often I'm going to actually publish
|
||||
stuff? Yes, probably it is. Aaaaanyway, I'm out.
|
||||
|
||||
[1]: https://web.archive.org/web/20180810023635/http://martin.md/
|
||||
[2]: https://ghost.org/
|
||||
[3]: https://github.com/myles/awesome-static-generators
|
||||
[4]: https://chirpy.cotes.page/
|
||||
[5]: https://git.martin.md/radu/blog
|
Loading…
Add table
Add a link
Reference in a new issue