syaffers.xyz

My blog deployment flow

#blog #web

February 3, 2026

My Hugo blog is coming together swimmingly. I’m comfortable in Markdown and Hugo makes it quick to build; big fan.

What I’m sometimes not a big fan of: is my idiosyncratic desire to be technical when it doesn’t need to be.

Let me explain:

I like VPSes

It’s your little computer-away-from-computer. It’s accessible, cheap (if you know what you’re getting), and you have sudo superpowers. I can have other things running while my site’s being served

This blog is hosted on a VPS (currently Vultr). Their machines are affordable and suit my use cases. Really I picked them because their color theme is 🔵 blue 🔵. There are many others in the market, though; shop around. Neither this post nor I is sponsored by Vultr; I’m just a happy customer.

VPS means self-hosting fu, managing which versions of software are installed, regular restarts for the latest security patches — you know the drill. But my brain cannot fathom any other way. I’ve tried selling myself on static S3 hosting or some other managed service: didn’t bite. I love the control… and the command line.

I like web servers

Web apps are my thing. Monitoring, databases, whatever; if they’re web-accessible, I’m sold. A solid web server is the gateway to this wonderland.

On my last site, I used to endure the pains of Nginx and Certbot for a while, longer than one cares to admit. This choice meant revisiting docs, Googling for answers, and going “How do I do this again? Is the command still in the bash history?”

Well, no more. To serve this site, I employ Caddy: the self-proclaimed “Ultimate Server” (and I kinda agree). Caddy gives me TLS on my sites for free, no extra plumbing. It’s one of those “it just works” things. Very nice!

What’s better: is that I’m not obliged to apt install it — great for my obsessive need to have a pure, unadulterated host environment — I just need Docker. Well, docker compose but it’s only got the one service:

services:
  caddy:
    image: caddy:2.10.2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./conf:/etc/caddy
      - /path/to/hugo/blog/public:/srv
      - caddy_data:/data
      - caddy_config:/config

volumes:
  caddy_data:
  caddy_config:

And the Caddyfile:

syaffers.xyz {
        root * /srv
        file_server
        encode gzip
}

Want a subdomain? 5 more lines in the Caddyfile. Isn’t that great?

I like private git repos

I’m ashamed of my deluge of ramblings. No one should see my blog’s secret git diffs. So I chuck ’em into a dark corner of a VPS, along with 5 other projects I’ve been meaning to release (if I can muster the courage).

Private repos give me a safe space to experiment while not closing the door on future public contributions. Here’s how I set it up:

Make a bare repository somewhere in your VPS:

cd /path/to/repos
git init --bare blog.git

Then in your local:

git remote add origin ssh://user@domain.com/path/to/repos/blog.git

There you go, your private repo is set up. Everything is done via SSH. You might want to copy your SSH keys ahead of time (if you haven’t already).

But whoops, logistics. Having this setup means: after every blog post, I must

To streamline that, I have a post-receive hook in my private repository to do all that every time I push:

#!/usr/bin/env bash
set -e

echo "Updating content..."

git --work-tree="/path/to/hugo/blog" \
    --git-dir="/path/to/repos/blog.git" \
    checkout -f

cd "/path/to/hugo/blog"
make build

echo "Updated."

If you want to make the project public while still keeping this private repo, just add another remote:

git remote add github ssh://github.com/<user name>/<repo name>.git

EOF

That’s about it for my blog setup. Feel free to steal and make your own.