blog/content/posts/how-to-blog.md

5.6 KiB

+++ date = '2024-11-27' title = 'How to Host a Simple Blog' tags = ['howto', 'tutorial', 'web'] categories = ['technical'] +++

No. I don't want to have a git repository with a million billion files that are auto generated by hugo, jekyll. No. I don't want to use some non-official, homebrew, backwater, docker image made by some random guy that stopped maintaining the image in 2011. I want my own dockerfile that is based on alpine or even use an image official to the framework. No. I definitely don't want to use a WYSIWYG (What You See Is What You Get) editor - I have my own local markdown editor that works just fine thank you. All I want i one (1) - i repeat - ONE fucking goddamn configuration file for the entire site (toml, conf, yaml I don't care) and blog posts should be written in markdown.

If you are like me, read on.

Additionally, there should be community made themes available - but I shouldn't have to fucking add them as a git submodule, god damn. The blog should be hostable through a docker image that just takes your markdown and config file, builds the static website, and serves it using some standard server (e.g. nginx or python's http.server I don't care which, as long as it is somewhat standard - If I am managing a docker container, I will manage the networking in docker)

Ideally, the directory structure should look like this:

blog
├── Dockerfile      // dockerfile to build and host the site
├── README.md       // info about the repository, not a blogpost
├── hugo.toml       // blog-framework configuration file
├── content
│   ├── about.md    // the "about" page
│   └── posts       // actual blog posts go here
│       └── example.md
└── static          // non-markdown files
    └── example.png

And then to build the site, simply build the container:

docker build .

Then you should just be able to insert the docker image into some docker-compose or kubernetes stack - or even just docker run -d if you'd like. The point of this is that you should really just focus on writing the blog entries - not the blog website.

If you want to use this workflow - this blog is written using this approach, so see my gitea instance or the github mirror for reference.

The Dockerfile I have settled on goes like this:

FROM alpine
RUN apk add hugo git
WORKDIR /hugo
RUN hugo new site /hugo
RUN git clone https://github.com/yihui/hugo-xmin.git themes/hugo-xmin
ADD hugo.toml /hugo/hugo.toml
ADD content /hugo/content
ADD static /hugo/static
CMD ["hugo", "serve", "--bind", "0.0.0.0"]

For now, I am just using the built-in server in hugo, but it should be possible to serve using nginx.

I mentioned hugo before, but I was mostly mad that I had to add the autogenerated stuff in git - with this approach... I don't have to 🎊!

Images

Just put images in the static directory, and reference to them in your blogposts like you would normally in a hugo project:

![example](/example.png)

example

This is not centered, and there's no built-in shortcode for centering images (why not, hugo? You have a shortcode for figures, but no css class for centering - you cant even add a style tag? Such an oversight)... So we have to add one dirty thing to this setup. We have to add a shortcodes directory, that is then also added to the docker container in /hugo/layouts/shortcodes:

blog
├── Dockerfile
├── README.md
├── hugo.toml
├── content
│   ├── about.md
│   └── posts
│       ├── example.md
│       └── how-to-blog.md
├── shortcodes
│   └── centered.html        // <-- Added
└── static
    └── example.png
<!-- centered.html -->
<p align="center">
    <img alt="example" src="{{.Get `image`}}" style="max-width: 100%;">
</p>

Then we can use this new shortcode like so:

{{</* centered image="/example.png" */>}}

{{< centered image="/example.png" >}}

Yes! Now we're cooking with gas! ... or atleast cooking with something.

If you want to just manually build and run docker image on your website server, feel free to stop reading here. The next section really elevates the publishing flow to a whole another level though.

Hosting and Deployment

Being able to build and launch the docker image is nice and can suffice for smaller projects. Yes, this blog is a small project and the manual method should be more than enough, but I also play factorio (highly recommend it!), so I hvae to automate everything that is tedious.

Continuous Integration

This section I am using my personal gitea instance to host the source code for this blog - which means that I will be using the integrated CI system there, but you can use whichever CI service you'd like. The general concepts of the workflow should be fairly easy to translate to any kind of CI

This setup also gives us the possibility of performing traditional code-review before releasing by using pull requests. This should empower us to identify and correct issues (e.g. spelling mistakes or whatever) before they are pushed to the official website.

Continuous Delivery

With a docker image readily available

Orchestration

I personally am a big fan of the simplicity of portainer, as it scales really well when doing perosnal server stuff