September 22, 2026
Building a small self-hosted agent factory
An old desktop died mid-setup, so I rented a €12 VPS and built a sandboxed agentic software factory on Coolify, Forgejo, and Hermes.
I read Jake Saunders' post on building a self-hosted agentic software factory and decided to try a smaller version myself.
The plan was an old desktop with an i7 and 16 GB of RAM. It died mid-setup, so I rented a VPS instead. That turned out easier to manage, and it gave me a cleaner security boundary.
The server
Netcup VPS:
- 8 shared CPU cores
- 16 GB RAM
- 320 GB SSD
- Debian 13
- IPv4 and IPv6
About €12 a month. The CPU is shared, which is fine for experiments, small apps, and one CI job at a time.
The server is deliberately separate from my personal machines and data. Agents make mistakes, so I'd rather give them a disposable VPS than my Mac.
The stack
- Coolify for deployments
- Forgejo for Git hosting
- Forgejo Actions for CI
- Hermes Agent for the coding agent
- PostgreSQL for Forgejo
- Tailscale for private administration
Public addresses:
https://git.factory.jwhardwick.dev
https://hermes.factory.jwhardwick.devA wildcard DNS record points *.factory.jwhardwick.dev at the VPS, which
makes adding more apps later easy.
Coolify
Coolify manages the Docker services and HTTPS certificates. It also gives me a way to deploy apps without handing the agent unrestricted SSH access.
The Coolify dashboard stays private. I reach it on port 8000 over Tailscale; the direct management ports are blocked from the public internet:
6001
6002
8000
8080Public HTTPS for apps goes through Coolify's Traefik proxy.
Forgejo and CI
Forgejo stores the repositories. I added one Forgejo Actions runner using Docker-in-Docker.
The runner doesn't use the host Docker socket. Access to
/var/run/docker.sock is effectively root on the box, so jobs run inside a
separate Docker daemon:
services:
docker-in-docker:
image: docker:dind
privileged: true
runner:
image: data.forgejo.org/forgejo/runner:13
environment:
DOCKER_HOST: tcp://docker-in-docker:2375One CI job at a time to start. Sixteen gigabytes is enough for the current stack, but a few builds running together would eat it fast.
I tested the runner with a private repo and a small workflow:
name: smoke
on:
push:
branches: [main]
jobs:
verify-runner:
runs-on: docker
steps:
- name: Check the runner
run: |
node --version
echo "Forgejo Actions runner works"It ran, so the Git and CI path works.
Hermes
Hermes runs as a Coolify service with a persistent home directory and workspace. It uses OpenRouter for models, with a dedicated key that has a small spending limit instead of my main one.
Hermes has two restricted API credentials:
- A Forgejo token for a dedicated
hermes-agentuser - A Coolify token with read, write, and deploy permissions
The Forgejo account is only a member of the factory organisation. The
Coolify token can't read sensitive values and has no root permission.
Two local skills handle factory work:
forgejo-cli
coolify-apiThe Coolify skill asks before changing anything — read-only calls work
normally, mutations need a --yes flag, and it supports dry runs.
I tested all three parts separately:
HERMES_FACTORY_OK
FORGEJO_INTEGRATION_OK
COOLIFY_SKILL_OKThat confirmed model access, Forgejo access, and Coolify access.
Network access
Public ports:
22 SSH
80 HTTP redirects and certificate setup
443 HTTPS
22222 Forgejo Git over SSHCoolify's management ports are blocked on the public interface; Tailscale is the private route for administration. SSH password auth is off — keys only.
Backups
Netcup snapshots are useful but I don't treat them as backups. A provider or account problem could take out the server and its snapshots together.
Off-server backup, stored on my FileVault-encrypted Mac:
- Coolify's PostgreSQL database
- Forgejo's PostgreSQL database
- Forgejo repositories and configuration
- Hermes state and workspace
- Runner configuration
- Coolify configuration
Current resource use
With Coolify, Forgejo, PostgreSQL, Hermes, and the runner running:
RAM: 2.1 GB of 15 GB
Disk: 19 GB of 314 GBPlenty of room for small apps. I haven't installed Firecrawl yet — its browser workers can use a lot more memory.
What's next
The next test is to hand Hermes a small app idea and have it:
- Create a Forgejo repository
- Write the application
- Add tests and a CI workflow
- Push the code
- Deploy it through Coolify
This isn't meant to hold personal data or important production systems. It's a separate machine where agents can build and break things without touching the rest of my infrastructure.