# Deployment & Self-Hosting

The product goal: someone looks at this and thinks *"oh, I (or my agent) can stand this up
in a few minutes."* Everything below is in service of that. Three install paths, all
**zero-config and encrypted by default**.

## 1. The three paths

### A. Docker (recommended)

```bash
docker run -d --name voicecat \
  -p 8384:8384/tcp \      # control (TLS 1.3)
  -p 8384:8384/udp \      # media (encrypted)
  -v voicecat-data:/data \
  ghcr.io/<org>/voicecat:latest
```

That's the whole thing. On first start it generates its Ed25519 identity + self-signed
cert, creates the SQLite database under `/data`, prints the **server fingerprint** (for
clients to verify), and listens. Control and media share one port number on TCP+UDP to keep
firewall rules trivial.

A `docker-compose.yml` is provided for people who prefer it, but it isn't required.

### B. Single static binary

```bash
# download for your OS, then:
./voicecat-server          # uses ./voicecat-data/ , prints fingerprint, runs
```

The server is a **single statically linked executable** (mbedTLS, libsodium, opus, sqlite,
etc. linked in — all permissive licenses). No runtime, no shared libraries to install, no
package manager. Linux (primary), macOS, and Windows builds.

### C. From source

```bash
git clone … && cd voice-cat
cmake --preset server-release      # vcpkg fetches & pins all deps; auto-triplet (Linux/macOS/Windows)
cmake --build --preset server-release
./build/server-release/bin/voicecat-server
```

One `cmake` invocation; vcpkg (manifest mode) resolves the dependency graph reproducibly.
The `server-release` preset produces an optimized, **stripped** binary (`-s` linker flag) —
smaller executables suitable for distribution. Works on Linux (primary), macOS, and Windows;
the vcpkg triplet is auto-resolved by [`cmake/voicecat-toolchain.cmake`](../cmake/voicecat-toolchain.cmake).
No system packages to chase.

## 2. Zero-config defaults

The server runs with **no config file at all**. Sensible defaults:

| Setting | Default |
|---------|---------|
| Encryption | On, always (not configurable off) |
| TLS cert / identity | Auto-generated on first run, persisted to the data dir |
| Database | Embedded SQLite in the data dir (no external DB) |
| Guests | Enabled (so the very first connect "just works"); easily disabled |
| Ports | `8384` TCP + UDP |
| A default channel | One "Lobby" voice/text channel created on first run |
| Opus policy | 48 kHz, 20 ms frames, mono/VOIP defaults; per-channel overrides allowed |
| Argon2id cost | Auto-tuned to the host on first run |

Override only what you care about, via env vars or an optional `server.toml`:

```toml
# server.toml — every key is optional
server_name   = "Cats United"
allow_guests  = false
bind_port     = 8384
data_dir      = "/data"

[tls]                       # only if you want a real CA cert; otherwise self-signed
cert_file = "/data/fullchain.pem"
key_file  = "/data/privkey.pem"

[opus.defaults]             # default Opus policy for new channels
mode = "mono"
bitrate_bps = 24000
frame_ms = 20
fec = true
dtx = true

[opus.limits]               # server-enforced ceilings (bound bandwidth)
max_bitrate_bps = 128000    # channels can't be configured above this
```

Every key also has an `VOICECAT_*` env var form, which is what the Docker path uses.

## 3. Connecting (client side)

- **Pure direct-connect.** Enter `host:port` (and a nickname or account). There is no central
  directory or server browser — you connect to a server you know.
- **Saved server list.** The client keeps a local list of saved servers (host:port, pinned
  fingerprint, nickname/credentials per server) so you can store several and pick one to
  join. This lives entirely in the client.
- On first connect the client shows the server's **fingerprint** and pins it (TOFU). No
  accounts or certs needed to try it; if the operator disabled guests, the client prompts for
  the username/password an admin gave you.

That's the entire flow: run the server, share `host:port` + fingerprint, friends save it and
connect.

## 3a. Provisioning accounts (admin)

Accounts are **admin-provisioned** — there is no self-serve registration. Two equivalent ways,
both writing the same SQLite store:

```bash
# CLI against the server's data dir or a running server
voicecat-admin account add   <username>          # prompts for / generates a password
voicecat-admin account reset <username>
voicecat-admin account del   <username>
voicecat-admin account list
```

…or from the **in-app admin interface** (a user with the admin permission), which sends the
privileged `CreateAccount`/`ResetPassword`/`DeleteAccount` control messages over TLS
(protocol.md §3). Guests need no provisioning; they just pick a nickname (if guests are
enabled).

## 4. Why it stays this easy (design constraints that protect the goal)

- **No external services.** No separate database, no Redis, no TURN/STUN server, no reverse
  proxy required. SQLite is embedded; media is plain UDP.
- **No certificate chore.** Self-signed + Ed25519 TOFU means encryption needs zero operator
  action. A domain owner *can* drop in a Let's Encrypt cert, but never *has* to.
- **One port pair.** TCP+UDP on the same number; one firewall/port-forward rule.
- **Static linking + permissive licenses.** The binary has no install-time dependencies and
  can be redistributed (including closed-source) without copyleft obligations.
- **Agent-friendly.** The run command is a single line with no interactive prompts, the
  server logs its fingerprint and listen address in machine-readable form, and `--help` /
  `--print-config` expose everything an automation needs. Health endpoint for liveness checks.

## 5. Operational niceties (planned, not blocking v1)

- `voicecat-server --print-fingerprint` and a `/healthz` TCP check.
- Graceful reload of `server.toml` on `SIGHUP`.
- `voicecat-admin` (see §3a) also handles bans and channel admin, talking to the same SQLite
  file or a running server.
- Prebuilt images for `linux/amd64` + `linux/arm64` (Raspberry Pi / cheap VPS friendly).
