+++ 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](https://gohugo.io/), [jekyll](https://jekyllrb.com/). 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: ```sh 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](https://git.gtz.dk/agj/blog) instance or the [github](https://github.com/sillydan1/blog) mirror for reference. The `Dockerfile` I have settled on goes like this: ```dockerfile 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: ```markdown ![example](/example.png) ``` ![example](/example.png#center) This is not centered, and there's no built-in [shortcode](https://gohugo.io/content-management/shortcodes/) 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 ``` ```html

example

``` Then we can use this new shortcode like so: ```markdown {{}} ``` {{< centered image="/example.png" >}} Yes! Now we're cooking with gas! ... or atleast cooking with something. Note that this image centering trick does not work in [reader mode](https://support.mozilla.org/en-US/kb/firefox-reader-view-clutter-free-web-pages). ## Conclusion We have made a docker file for automatically downloading, generating and serving a simple `hugo` blog site. Personally, I would've liked the `static` and `shortcodes` directories to not exist, but blogposts need images and it needs to center them, so they are a necessary evil. Could we make the directory structure better and cleaner? Probably yes. Will I make it better for this blog in the future? Probably yes. Will I make another post when I do that? Probably yes! If you want to just manually build and run docker image on your website server, feel free to stop reading here. The next section concerns about hosting, orchestrating and deploying the site automatically, but it's totally not required. # 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](https://store.steampowered.com/app/427520/Factorio/) (highly recommend it!), so I _hvae_ to automate everything that is tedious. I also have other projects that I host on my VPS (Virtual Private Server) such my portfolio site [gtz.dk](https://gtz.dk) and a [gitea instance](https://git.gtz.dk/) amongst other things. ## Continuous Integration I am using my personal [gitea instance](https://git.gtz.dk/agj/blog) 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, but this is how my setup looks like: ```yaml ``` Make sure to replace the `git.gtz.dk` website mentions with your own github hosting service (whether self-hosted, or `github.com`) and replace the `gitea/GITEA` mentions with `github/GITHUB` instead. Note that the syntax is extemely similar to GitHub Actions - in fact Gitea Actions are trying to be 1 to 1 compatible with GitHub Actions, so it should be relatively straight forward. This setup also gives us the possibility of performing traditional code-review before releasing by using [pull requests](https://docs.gitea.com/next/usage/pull-request?_highlight). 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](https://www.portainer.io/), as it scales really well when doing perosnal server stuff. I might write another post on how to set portainer up in the future.