2026-09-29 12:21:04 +00:00
# Wolloseum
Wolloseum is a deterministic, procedurally generated game server. Players
2026-09-30 08:47:33 +00:00
upload untrusted WASM agents that control spawned agents in a tick-based
simulation. Agent code runs in a sandboxed Extism/Wasmtime runtime with fuel
and memory limits.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
Identity is based on Ed25519 keypairs. The server stores public keys; private
keys stay with their owners. HTTPS and WSS termination are intended to be
provided by a reverse proxy such as nginx or Caddy. The Wolloseum process
serves HTTP and does not create TLS certificates.
## Build and Run
2026-09-29 12:21:04 +00:00
```sh
cargo build --release
2026-09-30 08:47:33 +00:00
cargo run --release -- serve --data-dir data --bind 127.0.0.1:8080
2026-09-29 12:21:04 +00:00
```
2026-09-30 08:47:33 +00:00
### Docker
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
Build and start the server with Docker Compose:
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
```sh
docker compose up --build -d
docker compose logs -f wolloseum
```
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
The HTTP service is published on `127.0.0.1:8080` ; configure nginx or Caddy to
proxy HTTP and WebSocket traffic to that address and terminate TLS. Compose
stores the SQLite database and generated administrator keypair in `./data` .
The entrypoint sets the data tree's ownership before starting the server as an
unprivileged user.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
Set `WOLLOSEUM_UID` and `WOLLOSEUM_GID` in the environment or a Compose `.env`
file to choose the container process identity. Both default to `1000` . The
ownership of the host `./data` tree is changed to these IDs at startup.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
The first startup logs the administrator identity ID and the key path inside
the container. Copy the key to a secure host location for admin sign-in:
2026-09-29 12:21:04 +00:00
```sh
2026-09-30 08:47:33 +00:00
docker compose cp wolloseum:/var/lib/wolloseum/keys/admin-private.pem /secure/path/admin-private.pem
chmod 600 /secure/path/admin-private.pem
2026-09-29 12:21:04 +00:00
```
2026-09-30 08:47:33 +00:00
Back up the key and database volume. To stop the server while preserving data,
run `docker compose down` . To remove all persistent identity and game data as
well, run `docker compose down --volumes` .
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
The server bootstraps an administrator keypair on first start:
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
- `data/keys/admin-private.pem` is the owner-only Ed25519 PKCS#8 private key.
- The server prints the corresponding identity ID at startup.
- Keep a secure backup of the private key. The server cannot recover it.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
Existing installations continue to use `data/certificates/admin-client-key.pem`
and the old certificate fingerprint as the admin identity ID when those legacy
files are present. Existing player identities and uploaded data remain in the
SQLite database. HTTPS certificates, if needed, belong to the reverse proxy.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
Configuration flags and environment variables:
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
| Flag | Environment variable | Default | Purpose |
| ------------ | -------------------- | ---------------- | ------------------------------------------- |
| `--data-dir` | `WOLLOSEUM_DATA_DIR` | `data` | Keypairs and SQLite database directory |
| `--bind` | `WOLLOSEUM_BIND` | `127.0.0.1:8080` | HTTP listener, usually private to the proxy |
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
## Web Interfaces
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
- `/` is the player console. Users sign in with their identity key and upload or replace their agent WASM.
- `/admin` is the administrator console. It creates and removes users, pauses or resumes the simulation, and replaces the core WASM module.
- `/viewer` is a public live event viewer. It connects to `/api/events` , tracks event sequence numbers, and restores state from snapshots after reconnecting.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
The admin console generates a fresh Ed25519 keypair when creating a player.
The server receives only the public key. The browser downloads a JSON identity
bundle containing the new identity ID and private key; deliver that bundle to
the player through a secure channel. The private key is not stored by the
server.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
On the admin page, enter the startup identity ID and select
`data/keys/admin-private.pem` . For an existing installation, select the legacy
admin key and use the identity ID printed by the server.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
## Browser Authentication
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
1. The browser requests `POST /api/auth/challenge` with `{ "client_id": "..." }` .
2. The server returns a random, short-lived challenge.
3. The browser signs the decoded challenge bytes using Ed25519 and posts the identity ID, challenge, and base64 signature to `POST /api/auth/login` .
4. The server verifies the signature against the stored public key and returns an opaque session token.
5. The browser stores the token and sends it as `Authorization: Bearer <token>` on protected API requests.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
Challenges expire after five minutes and are single-use. Session tokens expire
seven days after the last authenticated API interaction. Each authenticated
request extends the expiry. Only a SHA-256 hash of each token is persisted.
Revoking an identity by deleting it also removes its sessions.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
## API
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
| Method | Path | Access | Purpose |
| ------ | --------------------- | ---------------- | ------------------------------------------------- |
| `POST` | `/api/auth/challenge` | Public | Request an identity challenge |
| `POST` | `/api/auth/login` | Public | Verify a signed challenge and issue a token |
| `GET` | `/api/me` | Session | Read the signed-in identity and agent status |
| `GET` | `/api/users` | Admin session | List identities and agent digests |
| `GET` | `/api/status` | Public | Read the simulation running state |
| `GET` | `/api/events` | Public WebSocket | Receive snapshots and ordered state events |
| `POST` | `/api/create_user` | Admin session | Register a username and base64 Ed25519 public key |
| `POST` | `/api/delete_user` | Admin session | Delete a player and its uploaded agent |
| `POST` | `/api/start_game` | Admin session | Resume the simulation |
| `POST` | `/api/stop_game` | Admin session | Pause the simulation |
| `POST` | `/api/update_agent` | User session | Upload or replace the caller's agent WASM |
| `POST` | `/api/upload_core` | Admin session | Upload or replace the core simulation WASM |
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
Agent and core WASM uploads are limited to 1 MiB and validated in the
sandboxed runtime before they are persisted. Existing signed request headers
remain accepted for compatibility with older clients.
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
## CLI
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
The binary also provides an authenticated client. New installations use the
admin keypair directly:
2026-09-29 12:21:04 +00:00
```sh
cargo run --release -- cli \
2026-09-30 08:47:33 +00:00
--client-key data/keys/admin-private.pem \
2026-09-29 12:21:04 +00:00
create-user alice
2026-09-30 08:47:33 +00:00
```
2026-09-29 12:21:04 +00:00
2026-09-30 08:47:33 +00:00
`create-user` prints the identity ID and private key as JSON. For commands run
as a player, use that player's private key and identity ID:
```sh
2026-09-29 12:21:04 +00:00
cargo run --release -- cli \
2026-09-30 08:47:33 +00:00
--client-id < identity-id > \
--client-key alice-private.pem \
2026-09-29 12:21:04 +00:00
update-agent example-wasm-agent/target/wasm32-unknown-unknown/release/example_wasm_agent.wasm
```
2026-09-30 08:47:33 +00:00
Legacy installations can pass `--client-cert` and `--client-key` to derive the
historical certificate-based admin ID. The CLI exchanges a challenge for a
session token before making protected requests.
## Example Agent
`example-wasm-agent/` is a standalone crate implementing the Extism plugin ABI
used by `src/wasm_agent.rs` . Build it with:
```sh
cd example-wasm-agent
rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown
```
The compiled module is at
`example-wasm-agent/target/wasm32-unknown-unknown/release/example_wasm_agent.wasm` .