← Back home

2026.06 / build log

How This Blog Is Built and Maintained

This blog is intentionally simple. It is a static website, written as plain HTML and CSS, stored in a private GitHub repository, built into a tiny nginx Docker image, and deployed to this VPS through Coolify.

The interesting part is not the stack itself. The interesting part is the workflow around it: I can ask a Hermes agent from Telegram to write a post, edit the front page, update RSS and the sitemap, run checks, commit to GitHub, trigger a Coolify deployment, and verify that the live website actually changed.

The goal is a blog that stays easy to edit. No CMS. No database. No build pipeline that needs babysitting. Just files, Git, Docker, Coolify, and verification.

The stack

The production site at adrianmarikar.com is made from a few boring pieces:

The file layout

The repo is deliberately small. The core shape looks like this:

adrianmarikar-blog/
  index.html
  styles.css
  script.js
  feed.xml
  sitemap.xml
  robots.txt
  Dockerfile
  nginx.conf
  posts/
    ai-app-factory-vps-hermes-coolify.html
    raceedge-transparent-racing-app.html
    how-this-blog-is-built-and-maintained.html

There is no hidden content system. A new post is just a new file under posts/, plus links added to the homepage, RSS feed, and sitemap.

Why static HTML?

I could use a CMS or a static site generator, but for this site plain files are enough. The advantages are practical:

That last point matters. A small static site is a great fit for agent-assisted publishing because the agent can inspect the whole project, make a targeted edit, and verify it with simple commands.

The Docker setup

The site is deployed as an nginx container. The Dockerfile copies the static files into nginx and exposes port 80. That keeps production boring and portable.

FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY . /usr/share/nginx/html
EXPOSE 80

The nginx config serves normal files, applies basic security headers, caches static assets, and lets missing deleted posts return 404. That last detail matters because I removed the early placeholder posts and wanted their old URLs to stop serving content.

The deployment loop

The deployment loop is the same pattern I use for other small apps on this VPS:

Edit files
  ↓
Run local checks
  ↓
Build the Docker image
  ↓
Commit and push to GitHub
  ↓
Trigger Coolify deployment
  ↓
Wait for deployment to finish
  ↓
Verify the live URLs

For blog posts, the checks are simple but useful:

How posts are added

When I add a post, I usually make four changes:

  1. Create a new file in posts/.
  2. Add a card to the homepage.
  3. Add an RSS item to feed.xml.
  4. Add the URL to sitemap.xml.

That is enough to keep the public site, feed readers, and search engines aligned.

How the visual style is kept consistent

The design is centralised in styles.css. The homepage and posts use the same header, footer, background, typography, article cards, code blocks, links, and neon/glass panel treatment.

I also version the stylesheet URL when the design changes:

<link rel="stylesheet" href="/styles.css?v=20260611-organic1">

That avoids the annoying situation where Cloudflare or the browser keeps showing old CSS after the HTML has changed.

How Hermes helps maintain it

The blog is maintained from the same Telegram-to-Hermes workflow I use for app work. I can ask for a post, point Hermes at the relevant app or repo, and have it inspect the actual VPS state before writing.

The important rule is that the agent has to finish the loop. It should not just write a draft and stop. It needs to:

That is why the blog is useful as a dogfooding project. Every post is also a test of the wider AI app factory workflow.

Why this setup works for me

I do not want publishing to become a project. I want to be able to write about what I am building, ship the post, and move on.

This setup gives me that:

The trade-off

The trade-off is that this is not a full publishing platform. There is no admin dashboard, editor UI, image manager, comment system, or tag database. For now, that is a feature. The site stays small because the process is intentionally manual, inspectable, and agent-friendly.

If it grows, I can always add a static generator or a small markdown pipeline later. But the current version is enough: a personal site that can be edited by hand, maintained by an agent, and deployed like any other app on the VPS.