Self-hosted multi-platform broadcast newsroom for activist collectives: publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style column wall with hostile-content-safe rendering, live control room with Auto Director, bridged chat governance with polls and quorum, distributed sandboxed transcode workers, encrypted content-addressed archive, monthly analytics. MIT licensed. See README.md and docs/.
3.1 KiB
PeerTube Setup — Tactical Media Broadcast Hub's video/live backbone
PeerTube runs as a subproject (infra/peertube/) on a different server than the Tactical Media Broadcast Hub API/web. It stores all media in S3 and carries the Tactical Media Broadcast Hub brand, propagated from this repo.
Deploy (on the media server)
cp infra/peertube/.env.example infra/peertube/.env— fill in hostname, S3 keys (dedicated buckets:tactical-media-broadcast-hub-peertube-{videos,playlists,redundancy}), DB passworddocker compose -f infra/peertube/docker-compose.yml up -d- Put the instance behind HTTPS (nginx/caddy) — federation + OAuth require it
- First boot creates the admin account (PEERTUBE_ADMIN_EMAIL)
S3 storage
PeerTube's object-storage env handles ALL media (videos, playlists, redundancy). Point it at the same S3-compatible infra the Tactical Media Broadcast Hub media plane uses (MinIO or cloud), with dedicated buckets + credentials. The Tactical Media Broadcast Hub API never proxies PeerTube bytes — both speak S3 natively.
Branding — propagation rule
Source of truth: this repo (apps/web/public/brand/ + design tokens in apps/web/src/app/globals.css). After ANY brand change:
infra/peertube/brand-sync/sync-brand.sh
It pushes instance name, custom CSS (accent #FF1610 on black), and the solid disk mark to the instance via PeerTube's config API (needs PEERTUBE_URL + PEERTUBE_TOKEN with settings scope). Idempotent — run it whenever the brand moves. (Later: a "Sync branding" button in Tactical Media Broadcast Hub settings that calls the same API.)
Connecting Tactical Media Broadcast Hub → PeerTube
- OAuth bridge: stock PeerTube exposes a password grant only. Our connect flow (docs/oauth-connect.md) supports a same-instance OAuth bridge when configured; otherwise use an instance with a bridge plugin or a token-entry connection. The connector (
packages/connector-peertube) handles publish, livestream keys, per-instance federation. - Live ingest: the media worker's compositor pushes RTMP to
<host>:1935(opened in the compose file). Livestream keys flow through the connector. - Live chat: install the livechat plugin (peertube-plugin-livechat) on the instance — S5's chat hub consumes chat via the XMPP/plugin surface (phase 2 of S5, per the streaming architecture doc).
Different-server topology
[app server] [media server]
apps/api apps/web scheduler peertube (+redis +postfix)
media-worker compose (pg, S3 buckets (dedicated peertube-*)
redis, temporal...) │
└────── RTMP :1935 ───────┘
└────── OAuth/API over HTTPS ──┘
Firewall: app server → media server :443 (API) and :1935 (RTMP). Nothing else required between them; S3 is the shared storage plane.
Settings checklist (instance admin UI, after first boot)
- Enable live + allow replay + transcode lives
- Registration: closed (users join via Tactical Media Broadcast Hub)
- Federation: follow only trusted instances (moderated homepage)
- Plugins: peertube-plugin-livechat (chat), optionally peertube-plugin-rtc