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:
- Static HTML: each page and post is an HTML file.
- One shared CSS file: the dark neon/glass visual system lives in
styles.css. - One tiny JavaScript file:
script.jshandles small polish like the dynamic year and pointer glow. - nginx: serves the static files in production.
- Docker: packages the site into a repeatable container image.
- GitHub: stores the private source repo and commit history.
- Coolify: pulls from GitHub, builds the Dockerfile, deploys the container, and routes the domain.
- Cloudflare: handles public DNS/proxying in front of the VPS.
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:
- The site is fast because there is nothing to compute at request time.
- The attack surface is tiny: no admin login, no plugin ecosystem, no database.
- Every change is visible in Git.
- Deploys are easy to test locally and in production.
- An AI agent can safely edit the files without learning a big framework first.
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:
- Parse the changed HTML files.
- Parse
feed.xmlandsitemap.xml. - Scan for accidental secret-looking strings.
- Build the Docker image.
- Check the live post returns
HTTP 200. - Check the homepage, RSS, and sitemap all include the new post.
How posts are added
When I add a post, I usually make four changes:
- Create a new file in
posts/. - Add a card to the homepage.
- Add an RSS item to
feed.xml. - 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:
- Write or edit the files.
- Run the local checks.
- Build the Docker image.
- Commit and push the change.
- Trigger Coolify.
- Wait for the deployment to finish.
- Verify the live site with real HTTP checks.
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:
- Simple authoring: one HTML file per post.
- Reliable deployment: GitHub plus Coolify.
- Easy rollback: revert a Git commit and redeploy.
- Fast pages: static files behind nginx and Cloudflare.
- Low maintenance: no CMS updates, database backups, or plugin drama.
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.