Hello, and how this site is built
What this blog is for, and how a static homepage and a Ghost blog share one locked-down VPS.
This is the first real post here: a short introduction, then a walk through how the site you're reading is put together.
What this blog is for
I'm a network security engineer. Most of my working day goes to firewall policy, segmentation and remote access, and to the change process around them. Outside of work I run a homelab that is part test bench and part household infrastructure, built on Proxmox, TrueNAS, Docker, pfSense and Tailscale, with Home Assistant and a growing set of self-hosted services on top.
Most of what I learn comes from one of those two places, and most of it never gets written down. This blog is where I'll write it down. Expect posts on:
- Network security practice: policy design, segmentation, and change management that holds up in production
- Homelab builds, including the ones that didn't work the first time
- Self-hosting: what's worth running yourself, and what it costs to do it properly
I won't be writing about my employer's environment. Anything here is general practice or my own lab.
How this site is built
The whole thing runs on a small VPS with a couple of gigabytes of RAM. The stack is ordinary; a few of the decisions behind it are worth writing up.
Two apps, one domain
The front page at gilmore.tech is a single static HTML page served by a read-only nginx container. There's no JavaScript, no trackers, and no third-party requests. A strict Content Security Policy enforces that, so nothing can quietly add them later. This blog is Ghost, running in its own container at /blog.
Both sit behind one reverse proxy (Nginx Proxy Manager), which routes by path: /blog goes to Ghost and everything else goes to the static page. Ghost is configured with /blog as its own base URL, so it builds every link, asset and feed path correctly without rewriting at the proxy.
Accessibility is part of the build
The design uses frosted glass over soft colour, a style that can easily become hard to read. I held the site to WCAG 2.2 AA. Automated checkers can't measure contrast through a blur, so I measured the pixels behind every piece of text at several screen sizes instead. On phones, text over the brightest part of the background fell well below the 4.5:1 minimum. A dark tint under the glass fixed it while keeping the look. The page has no motion, and the layout reflows down to a 320-pixel-wide screen.
Everything is in git
The static page, its container config and this blog's theme all live in a git repository, and I check the server's copy against it after each change, so drift between the two gets noticed.
What's next
The next post will probably go deeper on one of these pieces. The real-IP problem behind a CDN is a common trap and deserves its own write-up. If there's something you'd like to see covered, you can reach me on LinkedIn.