# 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//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 # prompts for / generates a password voicecat-admin account reset voicecat-admin account del 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).