How This Site Works


How this site works

I’d like to write out how I set this website up, since I think it’s kind of interesting. This website is hosted on a VPS that a friend generously provisioned for me. It’s nothing powerful or fancy, but it’s more than enough for this setup. This site uses Hugo, nginx, certbot, Gitea, and webhook.

Hugo

Hugo is a static site generator. It’s not a heavy program like WordPress that generates the HTML when the page is requested. It just chews up markdown files and spits out HTML. You set up themes using HTML and CSS, which I found to be very straightforward despite my minimal web development experience. There’s no javascript, no database queries, just static HTML. Everything is generated from a folder full of markdown, HTML, and CSS files.

The site’s theme is a collection of HTML and CSS files. I’ve created a theme called toasterdragon here:

themes
└── toasterdragon
    ├── layouts
    │   ├── _default
    │   │   ├── baseof.html
    │   │   ├── list.html
    │   │   └── single.html
    │   ├── index.html
    │   └── partials
    │       ├── footer.html
    │       └── sidebar.html
    └── static
        └── css
            └── style.css

This is pretty straightforward. I have defined building blocks like the sidebar in /layouts/partials and I’ve got the default page in /layouts/_default/baseof.html

Content for the site is written in markdown. It’s all contained in a folder called content:

content
├── about.md
├── buttons.md
├── links.md
├── posts
│   ├── how-this-site-works.md
│   ├── _index.md
│   ├── libresprite
│   │   ├── animation_menu.png
│   │   ├── canvas_setup.png
│   │   ├── evilbutton.gif
│   │   ├── index.md
│   │   ├── oldbutton.gif
│   │   ├── pixelgrid.png
│   │   └── pixel_grid_setting.png
│   ├── patissiere
│   │   ├── cargo_run.png
│   │   ├── index.md
│   │   ├── pastoid.png
│   │   ├── pastoid_raw.png
│   │   └── working_yay.png
│   └── rpm-packaging.md
└── projects.md

That’s what it looks like on mine right now. Simple posts that don’t have any images, like this one, are just single markdown files. Posts that include images or other embedded content go into their own subdirectory. These folders are called Page Bundles. It’s just a nice way to keep files near the blog post they go with.

While making changes to the site, it would be rather cumbersome to do it on the server. So I keep everything in a git repository hosted on my server. This has extra benefits that I’ll go over later. I can keep a working copy on my laptop, and make changes there. While I’m making changes, I can run hugo server --buildDrafts to have hugo continously scan for new files and changes to existing files. Hugo content files are marked Draft = True or Draft = false, and without that flag, Hugo will skip over posts with Draft = true. When I save a file inside the site folder, hugo will automatically rebuild and refresh the page. It’s very nice for a live preview.

Once all the files are the way they should be, I can run hugo and it will output all of the HTML and other files needed to serve my site into the /public folder, ready for serving. Speaking of serving HTML…

nginx

So, on the server, that git repo is located in /var/www and my nginx config looks like this:

server {
    server_name toasterdragon.com;
    root /var/www/toasterdragon/public;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

We very simply point nginx to the folder that hugo outputs the files to. Very straightforward. For HTTPS, I am very thankful for the existence of certbot. Getting HTTPS set up is as simple as sudo certbot --nginx -d toasterdragon.com

Gitea

So, the git repository… I originally had it on github, but I found it’s really easy to set up gitea. It took just a few moments to grab the gitea binary from their github and get things going. I have that running at git.toasterdragon.com. Simple stuff. I use gitea because it supports webhooks, which is what makes this setup fun!

The deploy pipeline

After getting the initial hugo site looking nice on my laptop, and pushing it to the repository, I got on the server and cloned the repo to /var/www. I wrote a short script that would flush the old files and pull the new site files from git before generating the site with hugo:

/usr/local/bin/deploy-hugo.sh:

#!/bin/bash
cd /var/www/toasterdragon
git reset --hard HEAD
git pull
hugo

Now that I have that script, I need a way to trigger it. webhook describes itself as “a lightweight configurable tool written in Go, that allows you to easily create HTTP endpoints (hooks) on your server, which you can use to execute configured commands.” That’s exactly what I need! After getting it installed, I created a simple configuration file:

/etc/webhook.conf:

[
  {
    "id": "deploy-toasterdragon",
    "execute-command": "/usr/local/bin/deploy-hugo.sh",
    "command-working-directory": "/var/www/toasterdragon",
    "trigger-rule": {
      "match": {
        "type": "payload-hmac-sha256",
        "secret": "a long random string.",
        "parameter": {
          "source": "header",
          "name": "X-Gitea-Signature"
        }
      }
    }
  }
]

The secret is basically like a password. It makes sure that only the right requests will trigger it. Webhook runs on port 9000. Gitea hits it at http://localhost:9000/hooks/deploy-toasterdragon since they’re on the same server. If you are following along here and are using github, or another host outside of your server, it needs to reach your server over the internet. In that case you’ll want to proxy webhook through nginx rather than exposing port 9000 directly.

After that, just configure the webhook in Gitea’s settings. Make sure you set the secret to the same string you set in webhook.conf!

Wrapping up

So now, when I want to write a new blog post, I just go to the folder containing my site files, run hugo new content/posts/name.md, then write the post in the file. Once I’m done, I git push, the files go to the Gitea repository, which sets off the webhook, which triggers that script that updates my site. It’s very easy.

rhizomatic queer ascendance toasterdragon.com