Files
podsteadr/README.md
ssmithxandClaude Opus 5.5 bc393a3543 feat(blossom): upgrade to blossom-server 6.4.1, drop the nginx gateway
6.x serves Range requests natively, so the interim nginx gateway in
front of 4.4.1 is no longer needed and blossom publishes port 8098
again. 4.x is unmaintained; 6.4.1 also brings stricter auth and path
validation.

- New v6 config: one "*" rule with a 100-year expiration (v6 prunes
  for real and has no "never"), mirror/media/list/landing/dashboard/
  report disabled since podsteadr doesn't use them.
- BLOSSOM_REQUIRE_CONFIG=1 so a missing/invalid config fails startup
  instead of booting on defaults that prune video after a week.
- 6.x migrates a 4.x sqlite.db in place on first start and keeps the
  existing <sha256>.<ext> files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:26:53 +00:00

2.5 KiB

podsteadr

Self-hosted, nostr-native podcast publishing and livestreaming.

  • Log in with nostr — NIP-07 browser extension (Alby, nos2x, …); the server verifies NIP-98 signed requests. No passwords, no email.
  • Upload an mp4 → it is stored on a Blossom server (bundled, or point at any external one) and published in an RSS 2.0 podcast feed with Podcasting 2.0 <podcast:value> lightning-address payment info.
  • Go live — stream from OBS (RTMP) or straight from the browser (WebRTC/WHIP) through MediaMTX; viewers watch via HLS and the stream is announced on nostr as a NIP-53 (kind 30311) live event.
  • Publish recordings — live streams are recorded; one click remuxes and publishes a recording as a podcast episode.

Quick start

cp .env.example .env   # edit PUBLIC_HOST if not localhost
docker compose up --build -d

Then open http://localhost:8095, log in with a NIP-07 extension, and follow the wizard.

Services / ports

Service Host port Purpose
podsteadr 8095 Web UI + API + RSS feeds
MediaMTX 1935 RTMP ingest (OBS)
MediaMTX 8889 (+8189/udp) WebRTC/WHIP ingest (browser)
MediaMTX 8890 HLS playback
blossom-server 8098 Media blob storage (sha256-addressed)

Streaming with OBS

Create a stream in the UI; it gives you:

  • Server: rtmp://<host>:1935/live
  • Stream key: <streamId>?key=<secret>

The HLS playback URL (http://<host>:8890/live/<streamId>/index.m3u8) is public and never contains the secret.

Development

docker compose up mediamtx blossom -d   # backends
cd server   && npm install && npm run dev   # API on :8095
cd frontend && npm install && npm run dev   # Vite on :5173, proxies /api + /feeds

Tests: cd server && npm test.

Data

Everything lives in named docker volumes: podsteadr-data (SQLite, server nostr key, covers), mediamtx-recordings (stream recordings, 7-day retention), blossom-data (media blobs). docker compose down keeps them; down -v wipes them.

Verification

  • Unit tests: cd server && npm test (35 tests).
  • Against a running stack: node scripts/e2e.mjs (14 checks: login, blossom upload, feed, stream keys, MediaMTX auth webhook).

Status & internals

See docs/STATUS.md for the architecture, the full verification record, known gotchas (blossom v4 config nesting, no range requests, split-horizon blossom URL, MediaMTX polling rationale), and the remaining-work list (Archipelago packaging, git remote).