I’ve been writing notes with Joplin in Markdown syntax for a long time. As IDE for PowerShell, I use VSCode - and I have to say, I absolutely love it. There’s something deeply satisfying about writing content in such a pure, basic form. It reminds me of the early days of web development, back when there were no Content Management Systems and we hand-crafted every single page. That’s probably why creating this website with Markdown and VSCode feels so natural to me - it combines modern tools with that wonderful simplicity of the early web.

Hugo fits perfectly into this approach. It’s a static website generator freely available under the Apache license. The web pages are written in Markdown, and Hugo takes care of generating the HTML pages. I transfer the pages in PowerShell to an Ubuntu VM, where a Lighttpd web server runs in a Docker container. Access to the Docker container is controlled by the reverse proxy Traefik, which also takes care of the website’s Lets Encrypt certificate.

Preparation

Creating a site

On windows 11, I use the Windows Terminal with Powershell 7. I assume a working HUGO installation.

We change the path to the Hugo root directory (which I place in ~/Documents) and create a new site:

cd .\Documents\_HUGO\

hugo new site blog.example.com

Hugo creates all necessary files of the new site in the path $env:USERPROFILE\Documents\_HUGO\blog.example.com:

Congratulations! Your new Hugo site is created in $env:USERPROFILE\Documents\_HUGO\blog.example.com

Just a few more steps and you're ready to go:

1. Download a theme into the same-named folder.
   Choose a theme from https://themes.gohugo.io/ or
   create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
   with "hugo new <SECTIONNAME>\<FILENAME>.<FORMAT>".
3. Start the built-in live server via "hugo server".

Visit https://gohugo.io/ for quickstart guide and full documentation.

Installing a Hugo Theme

I use the theme m10c: https://themes.gohugo.io/themes/hugo-theme-m10c/

cd .\Dammmert.net\

git clone https://github.com/vaga/hugo-theme-m10c.git themes/m10c

The theme is defined in the configuration file config.toml of the new Hugo site:

baseURL = "https://blog.example.com/"
title = "HomeLab & Selfhosting"
theme = "m10c"
paginate = 10

Test the website

In a new Windows Terminal tab, we start the Hugo-Live Server within the site folder:

cd .\Documents\_HUGO\blog.example.com
hugo server

The page can be accessed via the URL http://localhost:1313/. All changes to the files will be immediately visible on this website.

Create content

A new page is created with the following command:

hugo new posts/Hello-World.md

I then edit the page in VSCode:

Web server for external access

On an Ubuntu VM, I create a Docker container for the Lighhtpd web server:

ssh ubuntu-vm
mkdir web/blog.example.com
cd web/blog.example.com
touch docker-compose.yml

Further editing is done in VSCode. With the extension Remote - SSH I connect to the Ubuntu VM and open the file docker-compose.yml.

In the YAML file the service lighttpd is defined. I use the image rtsp/lighttpd.

version: "3.3"
services:
  lighttpd:
    container_name: web-example.com
    volumes:
      - ./htdocs:/var/www/html:ro
    image: rtsp/lighttpd
    restart: unless-stopped
    networks:
      - proxy
    labels:
      ## Enable Trafik
      - "traefik.enable=true"
      ## Traefik Entry-Point HTTP
      - "traefik.http.routers.web-example.com.entrypoints=http"
      ## Traefik Host-Rule
      - "traefik.http.routers.web-example.com.rule=Host(`blog.example.com`)"
      ## Traefik Middleware Redirect HTTPS
      - "traefik.http.middlewares.web-example.com-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.web-example.com.middlewares=web-example.com-https-redirect"
      ## Traefik Entry-Point HTTPS
      - "traefik.http.routers.web-example.com-secure.entrypoints=https"
      ## Traefik Host-Rule HTTPS
      - "traefik.http.routers.web-example.com-secure.rule=Host(`blog.example.com`)"
      ## Traefik Enable TLS
      - "traefik.http.routers.web-example.com-secure.tls=true"
      ## Traefik Service Definition
      - "traefik.http.routers.web-example.com-secure.service=web-example.com"
      ## Traefik Load-Balancer
      - "traefik.http.services.web-example.com.loadbalancer.server.port=80"
      ## Traefik Network
      - "traefik.docker.network=proxy"
networks:
  proxy:
    external: true

The directory local directory ~/web/blog.example.com/htdocs is mapped read-only into the Docker container with: ./htdocs:/var/www/html:ro. So the static content from the Hugo installation just needs to be copied to this path.

The container is started:

sudo docker-compose up -d

Creating static web pages

To generate the HTML files of the web page, just execute HUGO in the site directory:

hugo

The files are placed in the subfolder public.

Workflow: Updating the web page

After making changes to the website, the static content needs to be regenerated with Hugo and transferred to the Ubuntu server. For this I use a small Powershell function.

function Update-HugoWeb {

    Set-Location "$env:USERPROFILE\Documents\_HUGO\blog.example.com"
    & "C:\Program Files\hugo\hugo.exe"
    $expression = "scp -r .\public\* $env:USERNAME@ubuntu-vm:/home/$env:USERNAME/lighttpd/htdocs"
    Invoke-Expression $expression

}

The function is inserted into my Powershell Profile, so its available in all Powershell consoles: C:\Users\and\Documents\PowerShell\Microsoft.PowerShell_profile.ps1.

Finally, to make changes to the web page, it is enough to save the change in the Markdown file (for example, with VSCode) and call the function in Powershell:

Update-HugoWeb