Familiar road, different scenery

A flurry of recent shares prompted me to consider blogging again. After all, I like writing, I have side projects, I’m investigating cool stuff, so why not share? It’s unlikely this post will get more than 10 unique viewers in its lifetime, so there’s little pressure for me to perform to some arbitrary standard.

Fighting that way of thinking is exactly what this blog will be about: building a habit of sharing cool stuff uninhibited by worry of comparison, getting it perfect, contributing something valuable for the better of humanity, procrastination. No, this is my little corner of the internet, my playground, my sandbox, my garden, where I document what’s going on, semi-anonymously, and without (too much) judgement.

The first thing to document is how this site came to be.

The simplest, but complete

Many of the articles I’ve read recently align with a feeling I’ve held for a long time: that of a playful contentment when tinkering at a fundamental level. Striving for simplicity is half of it, but it’s more than that. It’s an appreciation to take the direct and almost primal approach.

I use the latest and greatest tech in day job. “AI” is force-fed on an hourly basis. I’m 10 kilometres high flying over abstractions built on abstractions built on security loop holes built on abstractions that I don’t understand or appreciate. So the opportunity to take a proverbial crayon, draw a stick figure, and feel like that’s progress, that’s what I intended to do, and I succeeded in it, and be satisfied with that… that’s operating on a different level.

Every time I’ve launched a website or a blog before, I’ve turned to static site generators, SPAs, hybrids of the two. Now I’m been reminded that content should come first, not the tooling or the framework or the infrastructure or the architecture. But with technology ecosystems often moving so fast, how can you do that? By turning to established technology. As is so often the case, the old and boring dinosaurs still roam our lands. They sit quietly in the background. They’re not glamorous or hip or trendy. But look closely and you’ll see they’re doing most of the work.

HTML is one of those. The conventional approach today is to generate your HTML. Write your logic TypeScript, your content in Markdown. Add build steps, transpilation steps. Add tests. Encapsulate everything as a component. Reuse, reuse, reuse!

I think it’s very easy to over-engineer simple projects these days. Instead, this post is going to be online and accessible using only a few things:

  1. A virtual private server (VPS)
  2. A standard Linux distro
  3. A registered domain name
  4. A pre-configured file server
  5. An HTML page

I’ll walk through the setup.

Finding a host

Cheap VPSs start around a few pounds/euros/dollars per month. At the time of writing this, this thread on Lobsters is only five days old and can give some good recommendations for starting points. NearlyFreeSpeech is especially cheap if you just want static hosting. Fly.io and Vultr over general shared servers if you want to multi-purpose your machines. Hetzner do as well and seem especially good if your needs are for RAM rather than CPU. Glitch Servers and Aluy seem particularly focused on game servers. And then there’s always the old holdouts in Big Tech if you want an enterprise solution. This post on free clouds and list on free-for.dev might help you make compare quotas on offer.

I chose Vultr. Their 1 vCPU/1GB RAM/25 GB SSD compute plan is $5 USD per month and there’s a data centre in my city. The spec is more than enough for my purposes and the latency will be low. Vultr’s dashboard is straightforward. Within a few minutes of initialising my machine, I could hop into a fresh Debian 13 deployment.

Setting up the domain

I used to use Namecheap as my domain registrar but recently switched over to Porkbun. Once you’ve registered your domain, create an A record to point to your VPS’s IP address. This is configured in the registrar’s dashboard DNS settings (here’s the docs for Porkbun). Once the DNS records have propagated (which takes a few minutes to a few hours), anything you host on your VPS can be accessed via your domain name.

So let’s host something!

Caddy is capable of acting as file server and can automatically renew TLS certificates. This means users of your site can visit an HTTPS version of it without any additional effort from you. Modern browsers tend to show a warning when visiting a website over plain HTTP, so this can help with viewership.

apt install -y caddy

A Caddyfile should already exist at /etc/caddy/Caddyfile. You can edit it so just includes this.

mydomain.me {
    root * /var/www/html
    file_server
}

Reload Caddy’s configuration and open up the firewall on the two ports needed for HTTP traffic. 80 is for unencrypted traffic and 443 is for TLS traffic, which Caddy is facilitating for us.

systemctl reload caddy
ufw allow 80
ufw allow 443

Serving content

The file tree under /var/www/html will now map to the routes of your website. Let’s create two HTML pages so you can see what I mean. Place this in /var/www/html/index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="alternate" type="application/rss+xml" title="mydomain.me" href="/feed.xml">
    <title>mydomain.me</title>
  </head>
  <body>
    <p>Greetings</p>
    <ul>
      <li>
        <a href="https://mydomain.me/blog/familiar-road-different-scenery.html">
          Familiar road, different scenery
        </a>
      </li>
    </ul>
  </body>
</html>

Now create a folder at /var/www/html/blog and place this in /var/www/html/blog/familiar-road-different-scenery.html.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>mydomain.me</title>
  </head>
  <body>
    <h1>Familiar road, different scenery</h1>
    <p>A flurry of recent shares...</p>
  </body>
</html>

If your DNS records have propagated, navigate to your site via your domain name (or directly to the VPS IP address if they haven’t) and you should see these pages in all their unstyled raw HTML glory, complete with link navigation.

You now have a public blog.

Bonus: getting more from your VPS

Even if this blog had a hundred posts, it still wouldn’t be making much of a dent on the available compute resources. But since it’s your VPS, you can host whatever you want on it. Console recently named Glance the most interesting dev tool of 2025. Glance is a personal dashboard that can show you RSS feeds, stocks, subreddit posts, and the like. And it’s self-hostable.

Download, unzip, and place the Glance binary where it belongs (based on the Glance README, note to replace the version number here).

wget https://github.com/glanceapp/glance/releases/download/<glance_version>/glance-linux-amd64.tar.gz
tar -xzf glance-linux-amd64.tar.gz
mkdir /opt/glance
mv glance /opt/glance

Then create a systemd service (at /etc/systemd/system/glance.service) to manage Glance and ensure it starts on reboot.

[Unit]
Description=Starting Glance
After=multi-user.target

[Service]
ExecStart=/opt/glance/glance --config /opt/glance/glance.yml
Type=simple

[Install]
WantedBy=multi-user.target

Fetch the default Glance config from GitHub, then enable the Glance service.

cd /opt/glance
wget https://raw.githubusercontent.com/glanceapp/glance/refs/heads/main/docs/glance.yml
systemctl daemon-reload
systemctl enable glance.service
systemctl start glance.service

Then expose Glance to the outside world with Caddy. Add this as a separate block in your Caddyfile.

glance.mydomain.me {
    reverse_proxy 127.0.0.1:8080
}

Reload the Caddyfile with systemctl reload caddy.

Since this is exposed publicly, adding authentication to Glance would be prudent. A basic config might look like this, but you can read how to configure this further in the Glance docs.

auth:
  secret-key: <your_secret_key>
  users:
    admin:
      password: <your_password>

If you encounter an issues, you can check Glance’s logs with journalctl -u glance.service.

Another bonus: consuming our own feed

Glance has an RSS widget. We have just created a blog. Can blog posts feed into that RSS widget?

Of course. Create a /var/www/html/feed.xml file to define our feed.

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mydomain.me</title>
        <link>https://mydomain.me/</link>
        <atom:link href="https://mydomain.me/feed.xml" rel="self" type="application/rss+xml" />
        <item>
            <title>Familiar road, different scenery</title>
            <pubDate>Fri, 16 Jan 2026 19:00:00 GMT</pubDate>
            <guid>6f6058b4-4d67-4892-93da-a63609dcfe31</guid>
            <link>https://mydomain.me/blog/familiar-road-different-scenery.html</link>
            <description><![CDATA[
                <h1>Familiar road, different scenery</h1>
                <p>A flurry of recent shares...</p>
            ]]></description>
        </item>
    </channel>
</rss>

Then update our RSS configuration in /opt/glance/glance.yml to point to our feed:

- type: rss
  title: Blog Posts
  style: horizontal-cards
  feeds:
    - url: https://mydomain.me/feed.xml
      title: mydomain.me

And with that, our blog posts show up in our Glance feed.

Blog post shown in Glance

I’ve been down this road a few times before. The urge to compare kicks in, the feeling of building a reputation builds pressure. But I hope to return to this first post and remind myself why I started whenever those feelings crop up. There’s nothing to overthink here. It’s just a blog.

~K