No description
  • TypeScript 77.1%
  • Svelte 9.2%
  • Rust 6.5%
  • Shell 4.4%
  • JavaScript 1.2%
  • Other 1.6%
Find a file
2026-04-11 01:36:43 -07:00
backend checkpoint with android audio kind of working 2026-04-05 22:22:07 -07:00
docs revert to turn 2026-03-23 14:47:17 -07:00
frontend strictness checkpoint, linux works, android broken 2026-04-11 01:36:43 -07:00
infra revert to turn 2026-03-23 14:47:17 -07:00
mk checkpoint, still broken 2026-03-31 11:40:59 -07:00
.dockerignore checkpoint, still broken 2026-03-31 11:40:59 -07:00
.gitignore checkpoint with android audio kind of working 2026-04-05 22:22:07 -07:00
AGENTS.md iOS to linux chromium working 2026-03-18 23:56:29 -07:00
current-hypotheses.md strictness checkpoint, linux works, android broken 2026-04-11 01:36:43 -07:00
Dockerfile checkpoint, still broken 2026-03-31 11:40:59 -07:00
failed-approaches.md strictness checkpoint, linux works, android broken 2026-04-11 01:36:43 -07:00
README.md iOS to linux chromium working 2026-03-18 23:56:29 -07:00

Web 1:1 video chat

Single-VPS deployment

This repo builds a mobile-friendly, link-based WebRTC chat where one Rust container serves the SPA, signaling API, room/token endpoints, and an embedded turn-rs relay on the same VPS. Nginx only terminates HTTPS for the web app and websocket traffic.

1. Prerequisites

  1. One Ubuntu 24.04+ VPS (minimum 2 vCPU, 4 GiB RAM) with ports 22, 80, 443, 3478/udp, and 3478/tcp open in your firewall.
  2. One DNS A record pointing your chat domain (for example meet.example.com) to the VPS IP.
  3. Docker, Node 20+, Rust 1.83+ toolchain, and Certbot with the nginx plugin installed.

2. Obtain TLS certificates via Certbot

sudo certbot --nginx -d meet.example.com

Certbot writes /etc/letsencrypt/live/meet.example.com/{fullchain.pem,privkey.pem} and nginx reuses those files directly.

3. Build the frontend + backend

cd frontend
npm ci
npm run build

frontend/scripts/postbuild.mjs copies the Svelte build output into frontend/public and backend/public so Axum can serve the SPA from the Rust binary.

cd ../backend
cargo build --release

4. Configure and launch the container

The repo already includes ./mk/run and ./mk/deploy-single-vps. For a single-VPS deployment, the container publishes:

  • your HTTP app port, for example 8011 -> 8000
  • embedded TURN on 3478/udp
  • optional TURN-over-TCP on 3478/tcp (enabled by default)

If you prefer a systemd wrapper around ./mk/run, use something like:

[Unit]
Description=catchup single-vps app
After=network.target

[Service]
WorkingDirectory=/home/ubuntu/src/repos/video-chat
ExecStart=/home/ubuntu/src/repos/video-chat/mk/run 8011 single 0
Environment=TURN_SECRET=<hex from openssl rand -hex 32>
Environment=CATCHUP_RELAY_PORT=3478
Environment=CATCHUP_TURN_ENABLE_TCP=1
Restart=on-failure

[Install]
WantedBy=multi-user.target

Reload systemd and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now catchup

4.1 Runtime environment variables

  • TURN_SECRET: HMAC key used by the embedded relay for TURN-style credentials. Generate it once with openssl rand -hex 32. Do not commit it.
  • CATCHUP_RELAY_PORT: TURN bind port inside the container. Default 3478.
  • CATCHUP_TURN_ENABLE_TCP: advertise and serve TURN over TCP on the same port. Default 1.
  • TURN_HOSTS: optional comma-separated TURN hostnames advertised to the browser. For single-VPS deploys, leaving this unset is fine because the backend derives the host from CATCHUP_DOMAIN.
  • STUN_SERVERS: optional comma-separated STUN URLs. Defaults to empty so the app stays self-sovereign and uses only the embedded relay unless you explicitly opt into extra STUN infrastructure.

5. Deploy nginx for meet.example.com

You only need one nginx config from this repo:

5.1 HTTP reverse proxy

Copy infra/turn.nginx into /etc/nginx/sites-available/meet.example.com and symlink it into /etc/nginx/sites-enabled. Update the upstream 127.0.0.1:8011 if you deploy to a different host port.

That file does the following:

  • Redirects all HTTP → HTTPS.
  • Proxies all HTTP requests, including static assets, websocket upgrades, and API endpoints, to the catchup container.
  • Adds HSTS headers and sane timeouts for long-lived signaling.

After installing the HTTP proxy file:

sudo nginx -t
sudo systemctl reload nginx

Verify from the VPS:

curl -I https://meet.example.com/healthz
nc -vu meet.example.com 3478
nc -vz meet.example.com 3478

6. Firewall and operations

sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 3478/udp
sudo ufw allow 3478/tcp

Renew certs with sudo certbot renew and reload nginx after renewal. If you change stream includes, always run sudo nginx -t before reloading.

7. Deploy with the existing helper

Your current deploy command stays the same:

./mk/deploy-single-vps myvpshostname 8011 0 0

That copies the repo to the VPS and runs ./mk/run 8011 single 1 remotely. After deploy, nginx should proxy HTTPS to 127.0.0.1:8011, and TURN should be reachable directly on 3478/udp (and 3478/tcp when enabled).

8. Test before and after deploy

cd frontend
npm run test:unit
cd ../backend
cargo test

Both commands certify the Svelte UX and Axum server behave after configuration changes.