How I'm Built
A single virtual server hosts this site and every project alongside it, behind one web server, maintained conversationally by an AI agent running on the same box.
The idea
Most personal projects die in the gap between "it works on my laptop" and "it is on the internet." The goal here was to close that gap permanently: one server, one address, and a repeatable path from idea to live URL that does not involve remembering how any of it works.
The result is an additive host. New projects are added; nothing is torn down to make room. Each one is reachable under the same address at its own path.
This page is a live example of that gap being closed in real time. I'm not SSH'd in editing config by hand — I'm texting an AI agent (OpenClaw, running Claude) from my phone, in plain English, and it's reading the codebase, editing the files, rebuilding, and redeploying this exact site while you're reading this sentence. That's the actual hook of this whole project: the server doesn't just host the work, it maintains itself conversationally. No terminal, no dashboard — just a chat thread that turns into a shipped change on a live URL, every time.
From a text message to a live URL
The workflow that built this exact paragraph, end to end: I text a plain-English request from my phone. The agent reads the relevant repo, makes the edit, rebuilds it, deploys it, backs it up, and replies with the live link — no step in between touches a terminal on my end.
"Add on" is the operative word — every new project follows this exact same pipeline
into /srv/projects/, out to /srv/www/ or a systemd service, and
onto a Caddy route, alongside everything already live rather than replacing it.
Reading about the pipeline is one thing — watching it happen is another. This is that same workflow turned into a short animated walkthrough: a request lands in Telegram, an OpenClaw agent builds and deploys it live on this VPS, then the shipped result plays out.
RLabs Demo
live From a text message to a live URL, animated — a Telegram request, an OpenClaw agent building and deploying on this VPS, then the shipped result.Set this up yourself (quick version)
Never touched a server before? Here's the whole thing compressed to the main steps. You'll still need to look up specifics for your own provider/OS as you go — this is the map, not the turn-by-turn directions.
- Rent a VPS. Any provider works (Hetzner, DigitalOcean, Linode). Pick the cheapest Ubuntu LTS box — 2 vCPU / 4GB is plenty to start. You get root SSH access and an IP address.
- Buy a domain name. Any registrar (Namecheap, Hetzner, Google Domains). Point its DNS "A record" at your VPS's IP address — this is what makes
yourdomain.comload your server instead of a random number. - Install Caddy on the VPS. It's a web server that gets you free, auto-renewing HTTPS with almost no config — one line in a
Caddyfilepointing your domain at a folder is enough to go live. - Install OpenClaw. This is the agent framework that lets an AI (here, Claude, via Claude Code) run persistently on the box, connected to a chat app (Telegram, etc.) so you can give it instructions from your phone.
- Connect a Claude account/API key to OpenClaw so the agent actually has a model to think with.
- Talk to it. From here, the agent can write code, edit server config, and deploy — all from plain-language requests in chat, which is how everything on this site was built.
That's the skeleton. Each step above has its own setup docs from the provider/tool in question — worth reading those directly rather than guessing, since exact commands vary by OS and provider version.
TL;DR
- Host: one Hetzner VPS, 2 vCPU / 4 GB RAM. That's the whole server — no cloud services, no CDN, no managed database.
- Web server: Caddy is the only process on ports 80/443. It terminates HTTPS (Let's Encrypt, auto-renewing) and routes each URL path to the right project folder.
- Sites: everything here is a static build — plain HTML/CSS/JS sitting in
/srv/www/<project>. No server-side code runs per request, so there's no backend to exploit. - Source & deploys: code lives in git at
/srv/projects/, pushed to GitHub. A deploy script builds it and copies the output into the web root — the two never share a filesystem path. - Security: firewall (ufw) allows exactly three ports: 22 (SSH), 80, 443. Everything else is closed at the OS level, not just unlisted.
- Maintenance: an OpenClaw agent runs on the same box and makes changes over a private chat channel — no public admin panel exists.
No database, no backend process, no login — plain files served straight off disk.
Architecture
Everything public flows through one firewall and one web server. The agent that maintains the box lives on a completely separate, private path — it never touches 80/443 and is not reachable from the internet.
The stack
How a request is served
Caddy matches the most specific path first and falls through to the root site last. Static projects are served straight off disk; dynamic ones are proxied to a local port that is never exposed publicly.
redir /projectname /projectname/ 308
handle_path /projectname/* {
root * /srv/www/projectname
file_server
}
# dynamic equivalent
handle_path /appname/* {
reverse_proxy 127.0.0.1:7001
}
The distinction that matters is handle_path rather than
handle: it strips the path prefix before the request continues.
Without that, an application mounted at /projectname receives
/projectname/asset.css when it expects /asset.css,
and every asset reference breaks.
Adding a project
The procedure is deliberately identical every time:
- Source goes in
/srv/projects/<name>as its own git repository, pushed to a remote for backup. - Static builds output to
/srv/www/<name>. Dynamic apps get a systemd unit running as an unprivileged service account, bound to loopback on the next free port from 7001. - A routing block is appended to the Caddyfile, which is validated before reload.
- The project is listed on the landing page.
Nothing about this requires taking an existing project offline.
The agent layer
An OpenClaw gateway runs as a service on the same host, backed by a Claude model. It is reached through a messaging channel, which makes the deployment procedure above something that can be requested in a sentence rather than performed by hand.
This is the part with real teeth, so it is worth being precise about the trade-off. An agent that can deploy software is an agent with a shell. The controls that make that acceptable:
- The messaging channel is restricted to a single allowlisted account. Unknown senders are rejected before a message is ever processed, not merely ignored in the reply.
- The gateway binds to loopback only. It is not reachable from the internet; administrative access goes through an SSH tunnel.
- Credentials live in files readable only by their owner, and are excluded from every repository before its first commit.
- Group messaging is disabled outright rather than filtered.