Agent factory
A self-hosted VPS for building, testing and deploying apps with coding agents.
Overview
A Netcup VPS running Coolify for deployments, Forgejo for Git and CI, and Hermes as the coding agent. PostgreSQL, an isolated Actions runner and Tailscale support the setup, which is kept separate from my personal machines and data.
Server and setup details
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:
A 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
Initial resource use
With Coolify, Forgejo, PostgreSQL, Hermes, and the runner running:
RAM: 2.1 GB of 15 GB
Disk: 19 GB of 314 GBThis initial setup left room for small apps. Firecrawl was not included; its browser workers can use more memory.
Motivation
I wanted a disposable place for agents to build and break things without touching the rest of my infrastructure. An old i7 desktop died mid-setup, so I rented a VPS instead; it was easier to manage and gave me a cleaner boundary.
Inspired by Jake Saunders' self-hosted agentic software factory.
Check it out
Open Forgejo to browse the repositories. For a similar setup, start with a Debian VPS, deploy Coolify and Forgejo, add an isolated Actions runner, then configure Hermes with scoped credentials. The intended workflow takes a small app idea through a repository, application code, tests and CI, and deployment through Coolify. Administration stays private over Tailscale.