Parlay — Self-Hosted Voice & Chat Platform
A Discord-style community app I built alone in Rust: real-time group voice, screen sharing, live chat, moderation and an admin panel, all running on a $12/month server the community owns.
Parlay is my own version of Discord. Groups can voice chat, share their screens, and message each other, but instead of their conversations living on a big company's servers, they run Parlay on a small server they control and keep all of their data. I designed and built every part of it myself, from the audio engine to the hosting setup, and shipped the first release in five weeks.
- My role
- Solo creator: design, architecture, server, desktop app, admin panel, deployment
- Key results
- Group voice and 4K screen sharing that adapts to each viewer's connection
- Full server, Windows app and web admin panel, built and shipped solo
- One-command deploy; communities own and can export all of their data
- Tech used
Why I built it
Community chat apps are great until the company behind them changes the rules, raises prices, or loses your history. I wanted to see whether one engineer could build the whole thing — voice, video, chat, moderation, hosting — so a community could run its own copy and keep its data. Parlay is the answer: it went from an empty repository on 19 September 2026 to a tagged v0.1.0 release on 18 October, and I’ve kept shipping since.
What it does
- Voice channels — drop in and talk, with echo cancellation, noise suppression, push-to-talk, global hotkeys, and per-person volume (0–300%) that only you hear.
- Screen sharing — share a monitor or a single window, with its sound, from 144p up to 4K at 30 or 60 fps. Watching is opt-in, and each viewer gets the quality their connection can hold without slowing anyone else down.
- Text chat — rich formatting, @mentions, emoji, replies, edits, file and image attachments with previews, and infinite scroll-back.
- Communities — channels and sections, roles with per-channel permissions, invites with expiry and use limits, kicks and bans.
- Moderation — a report queue, an audit log of every admin action, and rate limits against spam and brute-force sign-ins.
- Admin panel — a web dashboard for members, roles, channels, invites, reports, appearance and extensions.
- Your data, your server — one command deploys it; one command exports a whole community as documented JSON; backup and restore need no database tools.
- Extensible — installable themes, bot accounts with scoped tokens and sidebar panels, and federation that bridges a channel between two independent Parlay servers.
What it shows about how I work
- Ownership end to end. I made every decision: product scope, architecture, protocol design, UI, testing strategy, deployment and documentation.
- Planning, then shipping in phases. The MVP was split into eight written phases, each landed as its own reviewed change with tests, and logged in a plan document as it went.
- Quality as a habit. 524 automated tests run against a real database and real network sockets, and CI checks that the admin panel’s API types never drift from the server.
- Cost-aware operations. A whole community runs on one $12/month AWS Lightsail box behind automatic HTTPS.
For engineers: how it’s built
Architecture. A Cargo workspace split along the platform line, not the feature line: portable crates (parlay-protocol, parlay-proto, parlay-core) hold the protocol, identity and networking; every Windows API call lives in parlay-win. A macOS or Linux port means writing one platform crate, not untangling cfg blocks.
Server (parlay-server). Tokio + Axum REST API under /v1 with an OpenAPI document generated by utoipa and RFC 9457 problem-details errors; a WebSocket gateway with per-channel subscriptions, presence and session resume; PostgreSQL via sqlx with compile-time-checked queries and migrations applied on start. Accounts use Argon2id and hashed, expiring session tokens.
Real-time media. Group voice runs through a selective forwarding unit (SFU) on QUIC (iroh), so each member uploads one stream instead of N-1 in a mesh. Joining is gated by signed, single-use, 60-second tickets the HTTP API mints after a permission check. Control and media ride separate QUIC streams so a roster update never queues behind audio, and video frames each get their own unidirectional stream so a late frame can be cancelled outright instead of head-of-line blocking the rest.
Audio pipeline. Opus encoding, a per-speaker jitter buffer with a 60 ms prebuffer, a pure-Rust AEC3 echo canceller fed with what the speaker actually plays, a voice gate, and device hot-swap that follows the OS default. Several commits are nothing but chasing down choppiness from timer jitter — the unglamorous part of real-time audio.
Screen share. Hardware H.264 (NVENC, AMF, Quick Sync, Media Foundation) with a software fallback, delay-loaded FFmpeg so the app still starts without it, per-watcher adaptive bitrate that steps down and back up a rung at a time, and process-scoped audio capture so the call is never echoed back.
Federation. Two instances pair with a one-time token, then bridge a channel once both admins agree. Requests are Ed25519-signed, delivered in order from a database outbox with retries, applied exactly once, and never re-relayed.
Clients. The Windows desktop app is written in Slint (a declarative Rust UI toolkit) on an async runtime that never sits in the media path. The admin panel is Vite + TypeScript with types generated from the server’s OpenAPI spec.
Testing & ops. Integration tests share one embedded PostgreSQL across test binaries and cover the gateway with resume, voice admission, permissions route by route, backup/restore into a second database, and two federated instances talking to each other. Deployment is one Docker Compose file (server, PostgreSQL, Caddy for HTTPS and HTTP/3) plus backup scripts and a Lightsail launch script the desktop app fills in for you.