Add blog post: Blogging with Hugo & Cloudflare Pages

This commit is contained in:
Akumatic 2024-09-22 01:47:13 +02:00
parent 334bad0fef
commit 3e38640221
5 changed files with 388 additions and 0 deletions

View File

@ -10,5 +10,7 @@ defaultContentLanguage = "en"
# This will make .Summary and .WordCount behave correctly for CJK languages.
hasCJKLanguage = false
enableEmoji = true
[pagination]
pagerSize = 5

View File

@ -0,0 +1,4 @@
---
title: "Dienste"
slug: "services"
---

View File

@ -0,0 +1,4 @@
---
title: "Services"
slug: "services"
---

View File

@ -0,0 +1,189 @@
---
title: Bloggen mit Hugo & Cloudflare Pages
date: 2024-09-21
description: |
Nachdem ich meinen Blog letztens zu Hugo umgzogen und per Cloudflare Pages veröffentlicht habe, zeige ich in diesem Beitrag, wie.
categories:
- services
tags:
- blog
- hugo
- cloudflare
- git
- github
- domain
---
## Intro
Wenn man an Blogs im Internet denkt, kommt vielen erst einmal Wordpress in den Sinn. Auch ich habe es eine Zeit lang selbst gehostet und genutzt, denn es war komfortabel, von überall erreichbar und dank Plugins leicht erweiterbar. Wordpress ist jedoch relativ schwer, viele Funktionen benötige ich nicht und da es mit das bekannteste CMS ist, sind auch die Angriffsmöglichkeiten entsprechend verbreitet. Deshalb habe ich mich dazu entschieden, auf [Hugo](https://gohugo.io/) umzusteigen.
Hugo ist ein Open-Source-Framework zur Generierung statischer Seiten. Die Inhalte werden in Markdown geschrieben und Hugo erstellt daraus eine statische HTML-Website, die mit jedem beliebigen Webserver gehostet werden kann. Da die Seiten vorgeneriert werden, ist der Zugriff schneller. Dank Git ist alles versioniert, zudem kann die Website einfach über [Github Pages](https://pages.github.com/) oder [Cloudflare Pages](https://pages.cloudflare.com/) bereitgestellt werden, wenn man Github nutzt und den Inhalt nicht selbst hosten möchte.
Ich habe mich für Cloudflare Pages im kostenlosen Tarif entschieden. Gründe meinerseits waren mitunter:
- Ich nutze Cloudflare schon für die DNS-Verwaltung meiner Domain
- Der Inhalt wird über das Cloudflare-CDN bereitgestellt
- Unlimitierte statische Requests und Bandbreite
- Github Pages haben im kostenlosen Tarif ein Limit von 100 GB / Monat. Auch wenn das erstmal erreicht werden muss, ist es eben eine Grenze, die man im Hinterkopf behalten müsste
- Integration mit Github und Gitlab. Bei jedem `git push` auf den konfigurierten Branch wird der Build-Prozess angestoßen und die fertige Seite veröffentlicht
Auch wenn man die Inhalte nicht wie bei Wordpress über die Weboberfläche erstellt und bearbeitet, ist Hugo nicht sonderlich komplex. Man sollte jedoch ein Grundverständnis von git und keine Angst vor der Konsole haben.
## Den Blog lokal erstellen
Auf dem System sollte Git und Hugo installiert sein. Unter Linux sollte Git in der Regel vorinstalliert sein und Hugo über den Paketmanager bezogen werden können, unter Windows empfiehlt es sich, das **Windows Subsystem for Linux (WSL)** einzusetzen. Unter Windows nutze ich z.B. Ubuntu 24.04 LTS per WSL, mit meinen Linux-Systemen nutze ich Hugo direkt.
> **Hinweis:**
>
> Mit WSL sind die Festplatten von Windows unter `/mnt` verfügbar. Öffnet man WSL aus dem Explorer oder über cmd, befindet man sich weiterhin im entsprechenden Ordner, z.B. `/mnt/c/Users/<Username>`. Erstellt man den Ordner für den Blog in einem von Windows gemounteten Ordner, funktioniert das Live-Preview von Hugo nicht, da Dateiänderungen nicht verfolgt werden. Stattdessen sollte ein Ordner direkt im Dateisystem von WSL angelegt werden, beispielsweise unter `~/blog`.
Nachdem man zum übergeordneten Ordner navigiert ist, führt man folgenden Befehl aus. Hierbei ist `blog` beispielsweise der Name des Ordners, der angelegt wird, und kann beliebig gewählt werden:
```
hugo new site blog
```
Damit erstellt hugo die entsprechende Ordnerstruktur und erstellt verschiedene Dateien. Nachdem man in den angelegten Ordner gewechselt hat, initialisiert man dort noch das leere Git-Repository:
```
git init
```
Jetzt fehlt nur noch ein Theme. Hugo bietet eine [Übersicht über verschiedene Themes mit Vorschaubildern](https://themes.gohugo.io/) an, über die Tags lässt sich die gewünschte Funktionalität filtern. Ich habe mich selbst erst einmal für [Stack](https://themes.gohugo.io/themes/hugo-theme-stack/) entschieden, bei Nichtgefallen lässt sich das Theme jedoch einfach austauschen, ohne den Inhalt der Website anpassen zu müssen.
Der Quellcode hinter den Themes, die auf der Übersichtsseite angeboten werden, ist in Repos auf Github zu finden. Diese lassen sich als [Git Submodul](https://git-scm.com/book/en/v2/Git-Tools-Submodules) hinzufügen. In meinem Fall mit Stack:
```
git submodule add https://github.com/CaiJimmy/hugo-theme-stack.git themes/stack
```
Abschließend muss in der Konfiguration nur noch festgelegt werden, welches Theme verwendet wird. Dafür muss in der Datei `hugo.toml` folgende Zeile ergänzt werden:
```
theme = 'stack'
```
> **Hinweis:**
>
> Diese Konfigurationsdatei ist relativ einfach gehalten. Damit kann man Hugo und das Theme weiter konfigurieren. Statt einer einzelnen Datei kann man auch eine Ordnerstruktur verwenden. Weitere Informationen findet man in der [Dokumentation von Hugo](https://gohugo.io/getting-started/configuration/).
>
> Für Stack findet man im Quick Start-Repo eine [Vorlage für die Konfigurationsdateien](https://github.com/CaiJimmy/hugo-theme-stack-starter/tree/master/config/_default).
Anschließend kann man den Entwicklungsserver von Hugo starten und sich die Website anzeigen lassen, auch wenn bisher kein Inhalt vorhanden ist:
```
hugo server
```
## Das Github-Repository
Als nächstes wird ein neues Repository bei Github erstellt. Der Name kann beliebig gewählt werden, das Repo muss jedoch nicht initialisiert werden.
Ein Vorteil von Cloudflare Pages ist, dass das Repo auch Privat sein kann - mit Github Pages im kostenlosen Tarif muss die Sichtbarkeit *Öffentlich* sein.
Lokal indexiert man alle angelegten Dateien für den ersten Commit, erzeugt diesen, fügt das zuvor angelegte Repository als Remote hinzu und lädt den Commit hoch. `<Ziel>` ist hierbei entweder `https://github.com/UserName/RepoName.git` (HTTPS) oder `git@github.com:UserName/RepoName.git` (SSH):
```
git add *
git commit -m "Initial Setup"
git branch -M main
git remote add origin <Ziel>
git push -u origin main
```
## Cloudflare Pages
Als nächtes soll der Blog statisch generiert und über Cloudflare Pages bereitgestellt werden. Hierfür klickt man im Cloudflare-Dashboard auf "Workers und Pages > Überblick" und anschließend auf den Button "Erstellen". Wechselt man zum Reiter "Pages", lässt sich ein vorhandenes Git-Repository von Github oder Gitlab importieren. Man kann die Dateien zwar auch direkt hochladen, müsste dies aber bei jeder Änderung manuell machen.
Nach dem Login wählt man den Account sowie das Repository aus, das getrackt werden soll. Danach wählt man einen Projektnamen (dieser Name wird zur Generierung eines dauerhaften Hostnamens auf pages.dev genutzt), den Branch und konfiguriert die Build-Einstellung. Als Preset kann man hierbei **Hugo** auswählen, was auch den Build-Befehl (`hugo`) und das Ausgabeverzeichnis (`public`) ausfüllt. Den Build-Befehl passe ich wie folgt an:
```
hugo --minify -b $BASE_URL
```
Unter "Umgebungsvariablen (erweitert) konfiguriere ich nun noch die Umgebungsvariable `BASE_URL` mit Wert `https://www.akumatic.eu`. Erstelle ich später noch eine Preview-Umgebung, kann ich für diese dann den Wert `$CF_PAGES_URL` einsetzen. Möchte man keine eigene Domain nutzen, kann man hier auch direkt `$CF_PAGES_URL` einsetzen.
Zudem nutzt Cloudflare Pages eine ältere Version von Hugo (in meinem Fall v.0118.2), die mit der aktuellen Version von *Stack* einen Fehler beim Rendern wirft (`<.Site.Lastmod.IsZero>: can't evaluate field Lastmod in type page.Site`). Für dieses Problem existiert ein [Issue auf Github](https://github.com/CaiJimmy/hugo-theme-stack/issues/974), als Lösung muss man die Version von Hugo explizit auf eine Version >= 0.123.0 setzen. Hierfür habe ich noch die Variable `HUGO_VERSION` mit Wert `0.123.8` angelegt.
Fährt man jetzt fort, baut Cloudflare die Seite und veröffentlicht diese. Den Blog kann direkt mit der angezeigten Subdomain von `.pages.dev` aufrufen.
### Eigene Domain nutzen
Eventuell hat man jedoch schon eine eigene Domain gemietet und möchte diese selbst oder eine Subdomain davon nutzen. In meinem Fall möchte ich die Subdomain `www` für die Website selbst nutzen und vom Domain-Apex zu `www` weiterleiten.
#### Subdomain `www`
Im Dashboard unter "Workers und Pages" wählt man die eben erstellte Page aus und wechselt zum Reiter "*"Benutzerdefinierte Domänen". Nach Klick auf "Benutzerdefinierte Domänene einrichten" kann man die gewünschte Domain oder Subdomain eingeben, die für die Website benutzt werden soll - in meinem Fall `www.akumatic.eu`. Anschließend wird noch gezeigt, welcher DNS-Eintrag erzeugt wird.
Nach der Bestätigung und einer kurzen Wartezeit ist der Eintrag gesetzt und das Zertifikat generiert - die Website kann nun über die Domain aufgerufen werden.
#### Umleitung vom Apex
Analog zu `www` könnte ich auch die Apex-Domain konfigurieren, dadurch wäre die Website direkt durch beide Domains erreichbar. Um den Auftritt konsistent zu halten, richte ich jedoch nur `www` ein und leite Anfragen von `akumatic.eu` zu `www.akumatic.eu` um.
Hierbei reicht ein einfacher CNAME-Record nicht aus, da das SSL-Zertifikat nur für `www.` ausgestellt wurde. Deshalb wird eine **Umleitungsregel** genutzt, wofür der DNS-Eintrag für die Apex-Domain eingerichtet werden muss. In meinem Fall sieht der Eintrag so aus:
| Eigenschaft | Inhalt |
| -- | -- |
| Typ | CNAME |
| Name | `akumatic.eu` |
| Ziel | `www.akumatic.eu` |
| Proxy-Status | Mit Proxy |
> **Hinweis:**
>
> Normalerweise kann man CNAME nicht für den Apex-Eintrag nutzen, Cloudflare ermöglicht dies durch [CNAME Flattening](https://developers.cloudflare.com/dns/cname-flattening/)
Anschließend kann die Umleitungsregel konfiguriert werden. Im Dashboard für die Domain geht man zu "Regeln > Umleitungsregeln" und erstellt eine neue Regel. Der Name kann dabei beliebig gewählt werden. Folgende Einstellungen werden getroffen, damit man bei einer Umleitung auch den vollständigen Pfad beibehält:
**Wenn...**
- [ ] Platzhaltermuster
- [ ] Alle eingehenden Anforderungen
- [x] Benutzerdefinierter Filterausdruck
| Eigenschaft | Inhalt |
| -- | -- |
| Feld | Hostname |
| Operator | gleich |
| Wert | `akumatic.eu` |
**Dann...**
URL-Umleitung
| Eigenschaft | Inhalt |
| -- | -- |
| Typ | Dynamisch |
| Ausdruck | `concat("https://www.akumatic.eu", http.request.uri.path` |
| Statuscode | 301 |
| Abfragezeichenfolge beibehalten | :ballot_box_with_check: |
## Kommentare mit Giscus
*Stack* bietet mehrere Optionen, um Kommentare zu integrieren, darunter auch Giscus. Giscus hat den Vorteil, dass Kommentare über die Diskussions-Funktion von Github realisiert werden und kein Secret in der Konfiguration hinterlegt werden muss.
Hierfür muss zum einen die [Diskussions-Funktion für das Repo aktiviert werden](https://docs.github.com/de/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/enabling-or-disabling-github-discussions-for-a-repository), zum anderen muss [Giscus installiert werden](https://github.com/apps/giscus). Dabei kann gewählt werden, ob es für alle oder nur ausgewählte Repos installiert werden soll.
Zudem habe ich in den Github-Diskussionen die vorhandenen Kategorien aufgeräumt und eine neue Kategorie explizit für die Kommentare vom Typ "Ankündigung" angelegt - dadurch können dort nur ich und die Giscus-App neue Diskussionen eröffnen.
Über die [Seite von Giscus](https://giscus.app/) kann unter "Konfiguration" geprüft werden, ob alle Voraussetzungen erfüllt sind. Anschließend können auf der Seite die Optionen so gewählt werden, wie man sie gerne hätte, und sieht unter "giscus aktivieren" einen fertigen Code-Block, um Giscus einzubinden. Für uns sind jedoch nur die Werte interessant, die wir in der Konfiguration einpflegen. Im Template findet man den entsprechenden Abschnitt unter [config/_default/params.toml](https://github.com/CaiJimmy/hugo-theme-stack-starter/blob/master/config/_default/params.toml):
```
## Comments
[comments]
enabled = true
provider = "giscus"
[comments.giscus]
repo = ""
repoID = ""
category = ""
categoryID = ""
mapping = ""
lightTheme = ""
darkTheme = ""
reactionsEnabled = 1
emitMetadata = 0
```
Nach dem Ausfüllen der Werte und dem Erstellen eines Posts kann die Funktionalität direkt getestet werden.

View File

@ -0,0 +1,189 @@
---
title: Blogging with Hugo & Cloudflare Pages
date: 2024-09-21
description: |
After I recently moved my blog to Hugo and published it via Cloudflare Pages, I'll show you how in this post.
categories:
- services
tags:
- blog
- hugo
- cloudflare
- git
- github
- domain
---
## Intro
When you think of blogs on the Internet, Wordpress is the first thing that comes to mind. I also hosted and used it myself for a while because it was convenient, accessible from anywhere and easy to expand thanks to plugins. However, Wordpress is relatively heavy, I don't need many of its functions and as it is one of the most-known CMSs, the potential for attacks is correspondingly widespread. That's why I decided to switch to [Hugo](https://gohugo.io/).
Hugo is an open source framework for generating static pages. The content is written in Markdown and Hugo uses it to create a static HTML website that can be hosted on any web server. As the pages are pre-generated, access is faster. Thanks to Git, everything is versioned, and the website can be easily deployed via [Github Pages](https://pages.github.com/) or [Cloudflare Pages](https://pages.cloudflare.com/) if you use Github and don't want to host the content yourself.
I opted for Cloudflare Pages on the free plan. Some of my reasons were:
- I already use Cloudflare for the DNS management of my domain
- The content is served via the Cloudflare CDN
- Unlimited static requests and bandwidth
- Github Pages have a limit of 100 GB / month in the free plan. Even if this has to be reached first, it is a limit that should be kept in mind
- Integration with Github and Gitlab. With every `git push` on the configured branch, the build process is triggered and the finished page is published
Even if you cant't create and edit content via the web interface like with Wordpress, Hugo is not particularly complex. However, you should have a basic understanding of git and not be afraid of the console.
## Create the blog locally
Git and Hugo should be installed on the system. On Linux, Git should usually be pre-installed and Hugo should be available via the package manager, on Windows it is recommended to use the **Windows Subsystem for Linux (WSL)**. On Windows I use e.g. Ubuntu 24.04 LTS via WSL, with my Linux systems I use Hugo directly.
> **Note:**
>
> With WSL, the Windows drives are available under `/mnt`. If you open WSL from Explorer or via cmd, you are still in the corresponding folder, e.g. `/mnt/c/Users/<username>`. If you create the folder for the blog in a folder mounted by Windows, Hugo's live preview will not work as file changes are not tracked. Instead, a folder should be created directly in the WSL file system, for example under `~/blog`.
After navigating to the parent folder, execute the following command. For example, `blog` is the name of the folder that should be created and can be chosen as desired:
```
hugo new site blog
```
With this command, hugo creates the corresponding folder structure and various files. After switching to the created folder, initialize the empty Git repository there:
```
git init
```
The only thing missing now is a theme. Hugo offers an [overview of different themes with preview images](https://themes.gohugo.io/), the tags can be used to filter the desired functionality. I opted for [Stack](https://themes.gohugo.io/themes/hugo-theme-stack/) for the time being, but if I don't like it, the theme can be easily replaced without having to change the content of the website.
The source code behind the themes offered on the overview page can be found in repositories on Github. These can be added as [Git Submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). In my case with Stack:
```
git submodule add https://github.com/CaiJimmy/hugo-theme-stack.git themes/stack
```
Finally, you only need to specify which theme is to be used in the configuration. To do this, the following line must be added to the `hugo.toml` file:
```
theme = 'stack'
```
> **Note:**
>
> This configuration file is kept relatively simple. It can be used to further configure Hugo and the theme. Instead of a single file, you can also use a folder structure. For more information, see [the Hugo documentation](https://gohugo.io/getting-started/configuration/).
>
> A [template for the configuration files](https://github.com/CaiJimmy/hugo-theme-stack-starter/tree/master/config/_default) can be found in the Quick Start Repo of Stack.
You can then start the Hugo development server and display the website, even if there is no content yet:
```
hugo server
```
## The Github repository
Next, a new repository is created on Github. The name can be chosen as desired, but the repo does not need to be initialized.
One advantage of Cloudflare Pages is that the repo can also be private - with Github Pages in the free plan, the visibility must be *public*.
Locally index all files created for the first commit, create it, add the previously created repository as a remote and upload the commit. The `<destination>` is either `https://github.com/UserName/RepoName.git` (HTTPS) or `git@github.com:UserName/RepoName.git` (SSH):
```
git add *
git commit -m "Initial Setup"
git branch -M main
git remote add origin <Ziel>
git push -u origin main
```
## Cloudflare Pages
The next step is to generate the blog statically and make it available via Cloudflare Pages. To do this, click on “Workers & Pages > Overview” in the Cloudflare dashboard and then on the “Create” button. If you switch to the “Pages” tab there, you can import an existing Git repository from Github or Gitlab. You can also upload the files directly, but you would have to do this manually every time you make a change.
After logging in, select the account and the repository to be tracked. Then select a project name (this name is used to generate a permanent host name on pages.dev), the branch and configure the build setting. You can select **Hugo** as the preset, which also fills out the build command (`hugo`) and the output directory (`public`). I modify the build command as follows:
```
hugo --minify -b $BASE_URL
```
Under “Environment variables (advanced)” I now configure the environment variable `BASE_URL` with the value `https://www.akumatic.eu`. If I create a preview environment later, I can then use the value `$CF_PAGES_URL` for this. If you don't want to use your own domain, you can also use `$CF_PAGES_URL` directly here.
In addition, Cloudflare Pages uses an older version of Hugo (in my case v.0118.2), which throws an error when rendering with the current version of *Stack* (`<.Site.Lastmod.IsZero>: can't evaluate field Lastmod in type page.Site`). There is an [Issue on Github](https://github.com/CaiJimmy/hugo-theme-stack/issues/974) for this problem, as a solution you have to explicitly set the version of Hugo to a version >= 0.123.0. For this I have created the variable `HUGO_VERSION` with the value `0.123.8`.
If you continue now, Cloudflare builds the page and publishes it. The blog can be accessed directly with the displayed subdomain of `.pages.dev`.
### Use your own domain
However, you may already have rented your own domain and want to use it directly or a subdomain of it. In my case, I would like to use the subdomain `www` for the website itself and redirect from the domain apex to `www`.
### Subdomain `www`
In the dashboard under “Workers & Pages”, select the page you have just created and switch to the *Custom domains* tab. After clicking on “Set up a custom domain”, you can enter the desired domain to be used for the website - in my case `www.akumatic.eu`. The DNS entry to be created is then displayed.
After confirmation and a short wait, the entry is set and the certificate is generated - the site can now be accessed via the domain.
### Redirect from the Apex
Similar to `www`, I could also configure the Apex domain so that the website would be directly accessible via both domains. However, to keep the website consistent, I only set up `www` and redirect requests from `akumatic.eu` to `www.akumatic.eu`.
A simple CNAME entry is not sufficient here, as the SSL certificate was only issued for `www.`. A **redirect rule** is therefore used, for which the DNS entry for the Apex domain must be set up. In my case, the entry looks like this:
| Property | Content |
| -- | -- |
| Type | CNAME |
| Name | `akumatic.eu` |
| Content | `www.akumatic.eu` |
| Proxy status | Proxied |
> **Note:**
>
> Normally you cannot use CNAME for the Apex entry, Cloudflare makes this possible by [CNAME Flattening](https://developers.cloudflare.com/dns/cname-flattening/)
The *Redirect Rule* can then be configured. In the Cloudflare dashboard for the domain, go to `Rules > Redirect Rules` and create a new one. The name can be chosen as desired. The following settings are made so that the full path is retained in the event of a redirect:
##### If...
- [ ] Wildcard pattern
- [ ] All incoming requests
- [x] Custom filter expression
| Property | Content |
| -- | -- |
| Field | Hostname |
| Operator | equals |
| Value | `akumatic.eu` |
##### Then...
URL redirect
| Property | Content |
| -- | -- |
| Type | Dynamic |
| Expression | `concat("https://www.akumatic.eu", http.request.uri.path` |
| Status Code | 301 |
| Preserve query string | :ballot_box_with_check: |
## Comments with Giscus
*Stack* offers several options for comments, including Giscus. Giscus has the advantage that comments are realized via the discussion function of Github and no secret has to be stored in the configuration.
To do this, the [discussion function must be activated for the repo](https://docs.github.com/de/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/enabling-or-disabling-github-discussions-for-a-repository) and [Giscus must be installed](https://github.com/apps/giscus). You can choose whether it should be installed for all or only selected repos.
I have also tidied up the existing categories in the Github discussions and created a new category explicitly for comments of the “Announcement” type - this means that only I and the Giscus app can open new discussions there.
On the [Giscus page](https://giscus.app/) under “Configuration”, you can check whether all requirements have been met. You can then select the options on the page as you wish and find a ready-made code block for integrating Giscus under “activate giscus”. However, we are only interested in the values that we enter in the configuration of Hugo. The corresponding section can be found in the template under [config/_default/params.toml](https://github.com/CaiJimmy/hugo-theme-stack-starter/blob/master/config/_default/params.toml):
```
## Comments
[comments]
enabled = true
provider = "giscus"
[comments.giscus]
repo = ""
repoID = ""
category = ""
categoryID = ""
mapping = ""
lightTheme = ""
darkTheme = ""
reactionsEnabled = 1
emitMetadata = 0
```
After filling in the values and creating a post, the functionality can be tested directly.