Files

120 lines
5.0 KiB
Markdown

# Zopu VDS agents deployment
This directory holds the systemd unit, environment template, and Caddy reverse-proxy config that run the Zopu intelligence runtime on the VDS. It supersedes the former container deployment for the agents process.
## Runtime topology
One Node process hosts the entire runtime:
```
zopu-agents.service
└─ node /srv/zopu/current/packages/agents/dist/server.mjs
├─ Hono server 127.0.0.1:3000
├─ Flue 2.0 agents SQLite at /srv/zopu/data/flue/flue.db
└─ AgentOS registry envoy, native runtime (in-process)
```
The process connects outbound to the **Rivet Engine**, a separate private service on `127.0.0.1:6420`, managed by its own unit/compose. This unit does not start or own it.
The Hono/Flue server handles Convex callbacks and dispatches to Flue agents. The **AgentOS actor is hosted in-process**: the same process is the envoy that owns the native Actor Runtime Socket (Rivet Mode A). There is no separate runner process and no Rivet HTTP handler route.
### Rivet endpoint
| Variable | Role | Value on this host |
| --- | --- | --- |
| `RIVET_ENDPOINT` | Engine **control plane** this process connects _to_ for actor metadata | `http://127.0.0.1:6420` |
## Files
- `zopu-agents.service` — systemd unit. Runs `/srv/zopu/current/packages/agents/dist/server.mjs` as user `zopu`, waits for engine health before binding, hardens the service, and restarts on failure.
- `agents.env.example` — template for `/etc/zopu/agents.env`. Contains the full validated env schema (Hono/Flue + in-process envoy) with no secrets.
- `../../scripts/release-agents.sh` — local build, upload, and atomic release promotion command. Each release includes this directory so the unit's `Documentation=` target remains valid.
- `Caddyfile` — source-controlled public ingress for `agents.zopu.puter.wtf`. Terminates TLS and forwards only `/health`, `/internal/project-setup`, and `/internal/agents/*` to `127.0.0.1:3000`.
## Prerequisites on the VDS
1. **Node 24** installed at `/opt/zopu/node/bin/node` (the verified VDS Node; the unit's `ExecStart` and `PATH` are anchored on this path). The release bundle ships its own `node_modules`; only the Node binary is expected from the host.
2. **`curl`** and **`bash`** on `PATH` (used by the `ExecStartPre` engine health probe).
3. A dedicated service user and group:
```sh
sudo useradd --system --no-create-home --shell /usr/sbin/nologin zopu
```
4. The two writable state trees, owned by `zopu`:
```sh
sudo mkdir -p /srv/zopu/data/flue /srv/zopu/workspaces
sudo chown -R zopu:zopu /srv/zopu/data /srv/zopu/workspaces
```
5. The **Rivet Engine** running and answering `http://127.0.0.1:6420/health`.
6. A release promoted by `scripts/release-agents.sh` to `/srv/zopu/releases/<release-id>`, with `/srv/zopu/current` symlinked to it. The release must contain `packages/agents/dist/server.mjs` and `deploy/vds/`.
## Install
```sh
# 1. Secrets
sudo install -d -m 0750 -o root -g zopu /etc/zopu
sudo cp agents.env.example /etc/zopu/agents.env
sudo chown root:zopu /etc/zopu/agents.env
sudo chmod 0600 /etc/zopu/agents.env
sudo "$EDITOR" /etc/zopu/agents.env # fill in every REPLACE-WITH-...
# 2. Unit
sudo install -m 0644 zopu-agents.service /etc/systemd/system/zopu-agents.service
sudo systemctl daemon-reload
sudo systemctl enable --now zopu-agents.service
```
## Verify
```sh
systemctl status zopu-agents.service
curl -fsS http://127.0.0.1:3000/health # {"service":"zopu-agents","status":"ok"}
```
### Public ingress (Caddy)
Caddy terminates TLS for `agents.zopu.puter.wtf` and forwards only the three paths the Convex backend calls to the internal agents worker (`127.0.0.1:3000`). The AgentOS actor registry runs in-process, so no `/internal/rivet/*` path is exposed on the agents listener. All other paths return `404`.
Install or update from this checked-in artifact:
```sh
# 1. Materialize the config
sudo install -m 0644 Caddyfile /etc/caddy/Caddyfile
# 2. Validate before applying
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
# 3. Reload the running Caddy (no restart needed)
sudo systemctl reload caddy
```
Verify the narrow public surface:
```sh
curl -fsS https://agents.zopu.puter.wtf/health # {"service":"zopu-agents","status":"ok"}
```
## Release switch
From the repository root on the build host, create and promote a release:
```sh
scripts/release-agents.sh <vds-host> <release-id>
```
The script atomically swaps `/srv/zopu/current`; it deliberately does **not** restart the service. After the upload succeeds, restart the unit:
```sh
sudo systemctl restart zopu-agents.service
```
Roll back by atomically replacing `current` with a symlink to a prior release, then restarting the service.
## Optional: explicit engine ordering
The unit already gates startup on the engine health endpoint via `ExecStartPre`. If the engine is itself a named systemd unit on this host, you may add a hard ordering by uncommenting/adding in the `[Unit]` section:
```ini
After=rivet-engine.service
Wants=rivet-engine.service
```