Self-hosting
Requirements
What a host needs before you run a Village on it for other Players. A local run needs much less — see Quick start for that.
The short list
- A Linux host with Docker Engine and the Compose plugin.
- Two hostnames under a domain you control, both resolving to that host.
- TLS on both hostnames. This is not optional; see below.
- MySQL 8.4 and Valkey 9. Both ship as Compose services, so you do not install them yourself.
- At least one Provider key — Anthropic, OpenAI, or both.
Docker and Compose
Everything runs as Compose services. docker-compose.yml uses a top-level
project name, service profiles, and depends_on with
condition: service_healthy, so you need Docker Compose v2 — the docker compose subcommand, not the older standalone docker-compose binary.
Nothing else is installed on the host for a Compose deployment. The API server, the web app, MySQL, Valkey, and the bundled edge are all images built or pulled by Compose.
Datastores
Two services hold state:
mysql, running themysql:8.4image, with theagentsville_mysql_datavolume. Every persisted row lives here — NPCs, Conversations, Messages, Skills, Memory, sessions.valkey, runningvalkey/valkey:9-alpine, with theagentsville_valkey_datavolume and append-only persistence. Rate limit counters, pending Connector authorizations and cached session lookups live here.
Valkey is required, not an optimisation. The server validates VALKEY_URL at
boot and refuses to start without it, because the rate limiter in front of the
Invite Code cannot quietly degrade to per-process counting and still be a gate.
Both publish on 127.0.0.1 only — MySQL on port 3306, Valkey on port 6379 — so
host-side tooling can reach them and the internet cannot.
If you want to use datastores you already run rather than these two services,
note that docker-compose.yml sets DATABASE_URL and VALKEY_URL in the
server service's environment: block, which wins over anything in .env.
Pointing AgentsVille at an external MySQL or Valkey means editing that file, not just
the .env.
Hostnames and DNS
AgentsVille is deployed as two origins: the web app on app.<your-domain> and the API
on api.<your-domain>. Both must have DNS records pointing at the host before
the first docker compose up if you use the bundled Caddy edge, because Caddy
cannot issue certificates for a name that does not resolve.
TLS is required on both origins
The session cookie is set SameSite=None; Secure. A browser will not store a
Secure cookie from a plain-HTTP origin, so a Village served over HTTP cannot
sign anyone in at all. There is no working plain-HTTP deployment — a LAN-only
one included.
The bundled Caddy profile issues and renews certificates for both hostnames with nothing to configure. If you run your own nginx or Apache, the certificates are yours to obtain and renew. See Reverse proxy.
Ports
- 80 and 443 inbound, published by the bundled
caddyservice. If you front AgentsVille with your own proxy instead, your proxy owns these. 127.0.0.1:3000— the web app. Loopback in every profile.127.0.0.1:8080— the API server. Loopback in every profile.127.0.0.1:3306— MySQL, for host-side tooling.127.0.0.1:6379— Valkey, for host-side tooling.- The sandbox broker publishes no port at all. It is reachable only over the Compose network.
The application ports bind to loopback on purpose. An application port on a public interface is an origin with no TLS and no forwarded headers, which is exactly the failure the edge contract exists to prevent. To reach MySQL from another machine, forward the port over SSH rather than republishing it.
Provider keys
AgentsVille runs on your keys, or on none. Set ANTHROPIC_API_KEY, OPENAI_API_KEY,
both, or neither: a Village whose models all run locally — chat and Memory
embeddings alike — needs no cloud key. See
Using local models.
If you do use a hosted Provider, set a spend cap in its own console before you invite anyone. AgentsVille records the Usage a Provider reports and never enforces a quota, so the console cap is the only hard ceiling on a bill.
If you plan to enable Sandboxes
Sandboxes add requirements beyond the base stack:
- One more service,
sandbox-broker, which holds the host's Docker socket. - An image built on the host with
pnpm sandbox:build. It carries a shell, Python, Node, and Chromium, so it is not small and the build is not quick. - Headroom for one running Docker container per NPC that has one. Each is capped at 2 GB of memory, 1.5 CPUs and 512 processes, so size the host against the number of NPCs you expect to be working at once rather than the number that exist.
Read Enabling sandboxes and ADR 0006 before turning this on.
Node and pnpm on the host
A Compose deployment does not need them to run. You do need them for a few operational tasks:
pnpm sse:checkproves your edge does not buffer. It is a plain Node script, so Node alone is enough.pnpm sandbox:buildandpnpm sandbox:checkneed pnpm and Docker.
The repository pins pnpm 11 in package.json, and the images are built on Node
24, which is the version to match.
Disk
Plan for the two named volumes, the images Compose builds, and whatever backup
retention you choose — scripts/backup.sh keeps seven days of compressed dumps
locally by default. Container logs are capped by Compose at 10 MB across 3 files
per service, so they cannot fill the disk on their own.
Next
- Configuration — every variable, in order.
- Install with Docker Compose — the deploy itself.
- Backup and restore — before you have anything worth losing.