Wiring: enable HLS port in cast/infra mediamtx + ufw notes; add deploy:live case + help in run/deploy.sh; update live deploy script. Ties the quinn.cast relay (on-demand DO) to the VIP shows live feature (fanout to live.transquinnftw.com ingest powers the player; /admin for SSO operator preview + light admin).
137 lines
5.8 KiB
Bash
Executable file
137 lines
5.8 KiB
Bash
Executable file
#!/bin/bash
|
|
# bootstrap.sh — robust post-boot / first-run setup for the quinn.cast relay droplet.
|
|
# Idempotent. Run as root.
|
|
#
|
|
# This is the "make it work" piece for the DO side:
|
|
# - kernel modules (v4l2loopback + snd-aloop for video+audio bridges)
|
|
# - docker + compose v2
|
|
# - ufw with sensible rules for SRT (public) + UI (consider further restrict) + SSH
|
|
# - layout of /opt/stream with the deployed infra/ files symlinked/copied
|
|
# - .env from example if missing
|
|
# - start the stack
|
|
#
|
|
# Called automatically by provision-stream-droplet.sh create (after scp of infra+controller).
|
|
# Also usable standalone after you scp the infra/ tree yourself:
|
|
# scp -r .../infra root@IP:/opt/stream/infra
|
|
# ssh root@IP 'bash /opt/stream/infra/scripts/bootstrap.sh'
|
|
#
|
|
# After: edit /opt/stream/.env , then the stack is up.
|
|
# The controller UI will be at http://IP:8080/?p=THE_PASSPHRASE
|
|
#
|
|
# Cost control: when done, doctl compute droplet delete NAME -f (or power off to stop billing transfer).
|
|
|
|
set -euo pipefail
|
|
|
|
echo "==> [bootstrap] quinn.cast relay stack setup (robust production mode)"
|
|
|
|
echo "==> System update + essentials (docker, ufw, audio/video loopback support)"
|
|
apt-get update -y
|
|
apt-get install -y \
|
|
docker.io \
|
|
docker-compose-v2 \
|
|
ufw \
|
|
v4l-utils \
|
|
alsa-utils \
|
|
curl \
|
|
jq \
|
|
htop \
|
|
ca-certificates
|
|
|
|
# Use docker compose v2 plugin (space, not hyphen)
|
|
if ! command -v "docker compose" >/dev/null 2>&1; then
|
|
echo "docker compose v2 not found after install; trying alternatives"
|
|
ln -sf /usr/libexec/docker/cli-plugins/docker-compose /usr/local/bin/docker-compose || true
|
|
fi
|
|
|
|
echo "==> Ensure docker daemon"
|
|
systemctl enable --now docker || true
|
|
docker --version
|
|
docker compose version || true
|
|
|
|
echo "==> v4l2loopback (video device for OBS)"
|
|
modprobe v4l2loopback devices=1 video_nr=10 card_label="RemoteFeed" exclusive_caps=1 || true
|
|
echo 'options v4l2loopback devices=1 video_nr=10 card_label="RemoteFeed" exclusive_caps=1' > /etc/modprobe.d/v4l2loopback.conf || true
|
|
|
|
echo "==> snd-aloop (audio loopback for virtual mic into OBS)"
|
|
echo 'options snd-aloop index=2,3' > /etc/modprobe.d/snd-aloop.conf || true
|
|
modprobe snd-aloop || true
|
|
|
|
echo "==> Show audio cards (for debugging the 'Hotel Mic' ALSA device if silent)"
|
|
cat /proc/asound/cards || aplay -l || true
|
|
echo " (If 'Hotel Mic' is silent in the seeded scene, use a webtop one-time or arecord -l to pick correct hw:xx and update the source settings in OBS.)"
|
|
|
|
echo "==> ufw firewall (SRT UDP must be open; UI 8080 should be restricted in prod)"
|
|
ufw default deny incoming || true
|
|
ufw default allow outgoing || true
|
|
ufw allow 22/tcp || true
|
|
ufw allow 8080/tcp || true # LLM controller UI (gate with passphrase; put real TLS/domain in front soon)
|
|
ufw allow 8890/udp || true # SRT ingest (public by design; hotel push targets this)
|
|
ufw allow 8888/tcp || true # HLS preview (for live.transquinnftw.com/admin + shows; operator or proxied)
|
|
ufw allow 1935/tcp || true # RTMP (local produced from OBS; also optional public ingest)
|
|
ufw allow 4455/tcp || true # obs-websocket (internal to compose; do not expose publicly)
|
|
ufw allow 8554/tcp || true # rtsp (optional)
|
|
ufw allow 8889/tcp || true # webrtc (optional)
|
|
ufw --force enable || true
|
|
ufw status verbose || true
|
|
|
|
echo "==> Prepare /opt/stream layout (infra/ was scp'ed here by provision or manually)"
|
|
mkdir -p /opt/stream
|
|
cd /opt/stream
|
|
|
|
# Make the deployed files the active ones (idempotent links/copies)
|
|
if [ -d infra ]; then
|
|
ln -sfn infra/docker-compose.yml docker-compose.yml 2>/dev/null || cp -f infra/docker-compose.yml .
|
|
ln -sfn infra/.env.example .env.example 2>/dev/null || cp -f infra/.env.example .
|
|
mkdir -p mediamtx obs
|
|
cp -rf infra/mediamtx/* mediamtx/ 2>/dev/null || true
|
|
cp -rf infra/obs/* obs/ 2>/dev/null || true
|
|
echo " infra/ files activated"
|
|
else
|
|
echo " WARNING: no infra/ subdir found — you must scp it before bootstrap or use the create flow"
|
|
fi
|
|
|
|
echo "==> .env setup (edit this!)"
|
|
if [ ! -f .env ]; then
|
|
if [ -f .env.example ]; then
|
|
cp .env.example .env
|
|
else
|
|
cat > .env <<'E'
|
|
XAI_API_KEY=sk-replace-me
|
|
OBS_WS_PASSWORD=replace-me
|
|
UI_PASSPHRASE=replace-me
|
|
E
|
|
fi
|
|
echo " Created .env from example — EDIT IT NOW with real XAI key + strong passwords"
|
|
else
|
|
echo " .env already present (leaving it)"
|
|
fi
|
|
|
|
echo "==> Pull / build and start the stack (controller will build from ./controller which must also be present)"
|
|
docker compose pull mediamtx video-bridge audio-bridge || true
|
|
docker compose build --pull controller obs || true
|
|
docker compose up -d
|
|
|
|
echo "==> Stack status"
|
|
docker compose ps
|
|
|
|
echo "==> Quick health"
|
|
curl -fsS http://localhost:8080/health || echo "(controller health not yet ready — normal on first boot; give it 20s and retry)"
|
|
curl -fsS http://localhost:9997/v3/paths/list | head -c 200 || echo "(mediamtx api not responding yet)"
|
|
|
|
echo ""
|
|
echo "==> DONE. Next:"
|
|
echo " 1. Edit /opt/stream/.env with your real XAI_API_KEY (from console.x.ai), strong OBS_WS_PASSWORD, UI_PASSPHRASE"
|
|
echo " 2. docker compose restart controller (or up -d again)"
|
|
echo " 3. From hotel: ./scripts/hotel-srt-push.sh --target YOUR_DROPLET_IP:8890 --bitrate 3500"
|
|
echo " 4. Open http://YOUR_DROPLET_IP:8080/?p=YOUR_UI_PASSPHRASE and chat e.g. 'what is the status?'"
|
|
echo " 5. 'start broadcast' once you have the hotel feed and at least one destination added."
|
|
echo ""
|
|
echo " Optional but recommended soon:"
|
|
echo " - Add a domain + Caddy/TLS in front of 8080 (or use WG mesh for UI only)"
|
|
echo " - Set a strong srtPublishPassphrase in mediamtx/mediamtx.yml and update your hotel push URL"
|
|
echo " - Monitor DO bandwidth / cost; destroy droplet when done: doctl compute droplet delete NAME -f"
|
|
echo ""
|
|
echo " ufw is enabled; 8080 is open to world (protected by passphrase). Restrict via DO firewall or"
|
|
echo " 'ufw allow from YOUR_LAPTOP_IP to any port 8080' if you want belt-and-suspenders."
|
|
echo ""
|
|
echo "We run real systems."
|