Punch
Fast Link Access Gate — SRT session brokerage for broadcast.

Punch is a free, open-source signalling service that lets SRT endpoints find each other and connect — without manual port forwarding or static IP coordination, on networks that allow UDP rendezvous. It runs on Cloudflare Workers and costs nothing to operate.
The problem
Every SRT connection today requires manual coordination:
- Someone opens a UDP port on a public IP
- Both sides agree on IP, port, passphrase, and latency — via phone, Signal, email, or spreadsheet
- Someone configures caller vs listener mode (and gets it wrong half the time)
- Repeat for every camera, every show, every venue
For a 4-camera ISO shoot, that’s 4 separate coordination conversations. On a hotel WiFi with double NAT, it’s impossible without a relay server.
Commercial solutions exist (Haivision Hub, LiveU, Teradek Sharelink) — starting at hundreds of dollars per month, locked to proprietary hardware, closed ecosystems.
Between free CLI tools and enterprise SaaS, there is nothing.
Punch fills that gap.
How it works
- Producer creates a session → gets a URL and QR code
- Encoder scans the QR → registers with Punch, reports its public IP:port
- Decoder does the same → Punch sends each peer the other’s coordinates
- Both start SRT in rendezvous mode → direct peer-to-peer, NAT hole-punched
- Punch stays connected → monitors health, carries tally, shows dashboard
The signalling server never touches the media. It brokers the introduction, then gets out of the way.
Quick start
From the web UI (recommended)
- Open
punch.thåst.se, enter a session name, and create the session. You will be taken to the operator dashboard atpunch.thåst.se/s/<name>?t=<token>. - Show the QR code on screen, or send the operator URL to the camera operator. They register their SRT endpoint with one tap.
- When both peers register, Punch reveals the auto-generated connection strings —
ffmpeg, OBS, vMix, GStreamer andsrt-live-transmit, ready to paste.

A 60-second walkthrough lives in docs/quick-start.md.
Programmatic / self-hosted
The HTTP API works the same way against any Punch deployment. The hosted service punch.thåst.se enforces Cloudflare Turnstile on POST /api/session, so curl-only callers must use a self-hosted instance (no Turnstile secret set), or supply a turnstileToken from a Turnstile-enabled client.
# Self-hosted instance — no Turnstile secret configuredcurl -X POST http://localhost:8787/api/session \ -H 'Content-Type: application/json' \ -d '{"name": "nab-floor-cam1"}'Response:
{ "session": "nab-floor-cam1", "token": "p_abc123...", "url": "http://localhost:8787/s/nab-floor-cam1", "qr": "http://localhost:8787/s/nab-floor-cam1/qr", "streams": ["default"], "latency": 200, "ttl": 1800, "state": "WAITING", "created": "2026-05-03T11:49:15.620Z"}After both peers register, fetch the connection strings:
curl -H "Authorization: Bearer $TOKEN" \ http://localhost:8787/api/session/nab-floor-cam1/connectThe response contains parallel for_peer_a and for_peer_b format maps. See docs/protocol.md for the full shape.
Features
Session brokerage
- Peer discovery — no manual IP exchange
- NAT traversal — UDP hole punching via SRT rendezvous mode
- Passphrase distribution — auto-generated AES keys, never texted
- Auto-generated commands — exact FFmpeg, OBS, vMix, and GStreamer strings
Multi-camera sessions
- Session bundles — group multiple SRT streams under one production
- Per-stream metadata — camera role, audio config, labels
- One QR per camera — operators scan and stream, nothing else
Real-time monitoring
- Stream health dashboard — RTT, retransmit ratio, bitrate, buffer levels
- Colour-coded status — green/amber/red, visible at arm’s length
- Latency recommendation — measured RTT → suggested setting
Production control plane
- Tally signalling — on-air/preview/off state via WebSocket
- Camera labels — human-readable names on the dashboard
- Session state machine — WAITING → READY → CONNECTED → CLOSED
Architecture
Punch runs entirely on Cloudflare Workers with Durable Objects:
- Edge Worker — handles HTTP/WebSocket routing, JWT validation
- Session Durable Object — one instance per session, strong consistency
- Hibernatable WebSockets — idle connections cost nothing
- Alarm API — automatic session cleanup after 30 minutes of inactivity
No servers to maintain. No databases to manage. Free tier handles ~3,000 sessions/day.
Why Durable Objects, not KV
Workers KV has eventual consistency — up to 60 seconds propagation delay. For signalling, that means peer B might not see peer A’s registration for a full minute. Fatal.
Durable Objects provide single-threaded strong consistency per session. One object per session. No race conditions. No stale state.
The Punch protocol
PUNCH — Peer Unification via NAT Crossing Handshake
A minimal signalling protocol for SRT session brokerage. Designed to be what WHIP is for WebRTC — a simple, standardised way to negotiate SRT connections over HTTP and WebSocket.
Session lifecycle
WAITING Both peers not yet registeredREADY Coordinates exchanged, rendezvous can beginCONNECTED SRT connection established (reported by peers)RELAYING Hole punch failed, relay path active (future)CLOSED Session terminated or TTL expiredWebSocket messages
// Peer → Punch{ type: 'register', port: 9000, meta: { label: 'CAM-1', audio: 'stereo' } }{ type: 'health', rtt: 45, retransmit: 0.2, bitrate: 8500000 }{ type: 'status', srt: 'connected' }
// Punch → Peer{ type: 'peer', ip: '198.51.100.3', port: 9000, passphrase: '...' }{ type: 'tally', state: 'preview' }{ type: 'session', streams: [...], connected: 3, total: 4 }Full protocol specification: docs/protocol.md
Comparison
| Solution | Cost | Signalling | Multi-cam | Monitoring | Open source |
|---|---|---|---|---|---|
| FFmpeg CLI | Free | Manual | No | No | Yes |
| srt-live-transmit | Free | Manual | No | No | Yes |
| SRT Mini Server | $30/mo | Basic | No | Basic | No |
| Punch | Free | Automatic | Yes | Yes | Yes |
| LiveU Solo | $450/yr + hw | Proprietary | Limited | Yes | No |
| Haivision Hub | Enterprise | Proprietary | Yes | Yes | No |
Documentation
| Document | Description |
|---|---|
docs/why.md | Why Punch exists — design philosophy and origin essay |
docs/architecture.md | Technical architecture, Durable Objects, state machine |
docs/protocol.md | Protocol overview — narrative reference |
docs/spec/punch-protocol-rfc.md | Formal protocol specification (RFC-style, normative) |
docs/spec/openapi.yaml | OpenAPI 3.1 description of the HTTP API |
docs/spec/punch-messages.schema.json | JSON Schema 2020-12 for WebSocket messages |
docs/nat-traversal.md | NAT types, hole punching, relay fallback |
docs/srt-primer.md | SRT fundamentals for context |
docs/integration.md | FFmpeg, OBS, vMix, CasparCG, hardware encoders |
docs/security.md | Tokens, passphrases, access control |
docs/deployment.md | Cloudflare Workers setup and configuration |
docs/roadmap.md | Phased feature roadmap |
Known limitations
Punch is honest about what it does and does not do.
- Signalling only, no media. Punch never touches video or audio. The signalling server brokers the introduction; once peers exchange coordinates, SRT runs direct peer-to-peer between them.
- NAT traversal is signalling-assisted, not guaranteed. Punch coordinates the rendezvous, but it does not run STUN, TURN, or any UDP probing. The connection succeeds whenever the encoder’s NAT preserves a usable UDP mapping for the duration of the SRT handshake. In practice this covers the bulk of fixed-line and broadcast-venue deployments (port-preserving / cone NATs) and most prosumer home routers. It does not cover symmetric NAT, carrier-grade NAT, or networks that aggressively rewrite UDP source ports between packets — those need a TURN-style relay (Phase 3 roadmap). Field-validation matrix in progress; please file an issue with your environment if rendezvous fails.
- Cloudflare-locked. Punch is built on Cloudflare-specific primitives — Workers, Durable Objects, hibernatable WebSockets, the alarm API. Running it elsewhere would be a rewrite. This is a deliberate trade-off: it makes the service free and globally distributed, but not portable.
- IPv4 first. SRT rendezvous and the underlying UDP hole-punching mechanics are exercised on IPv4. IPv6 paths work but have less field validation in v1.0.
- Free-tier scaling. The free Cloudflare Workers tier covers roughly 3,000 sessions per day. Sustained higher volumes need a paid Workers plan or a self-hosted deployment.
- Operator URL = session-scoped admin token. The producer URL (
/s/<session>?t=<token>) embeds the admin token. Anyone holding it can observepeer_matchevents and close the session. The token is bound to the single session and expires with its TTL — treat it like the SRT passphrase itself: send it through a private channel, do not paste it into shared chats. Per-peer scoped tokens with a separate join UI are on the roadmap (Phase 2/3); v1.0 ships with admin-scoped operator URLs and per-stream peer tokens via the API.
If any of these matter for your use case, open an issue — several are roadmap items waiting on a real-world driver.
Roadmap
Phase 1 — MVP
- Session creation and peer discovery
- WebSocket signalling with Durable Objects
- Auto-generated FFmpeg/OBS/vMix commands
- Web UI with QR code
- Passphrase distribution
Phase 2 — Production grade
- Multi-stream session bundles
- Real-time health dashboard
- Tally signalling
- Latency recommendation engine
Phase 3 — Ecosystem
- Formal protocol specification — see
docs/spec/ - Relay (TURN) fallback for symmetric NAT
- CLI companion tool
- Pre-flight network analysis
See docs/roadmap.md for the detailed phased plan.
Testing
npm test # Vitest under @cloudflare/vitest-pool-workersnpm run check # TypeScript type-check (no emit)113 tests cover the HTTP and WebSocket surface end-to-end, session lifecycle, authentication, per-token stream-scope enforcement, rate limiting, CSP headers, and Turnstile verification.
Contributing
Punch is built by broadcast engineers, for broadcast engineers. Contributions welcome.
CONTRIBUTING.md— getting started, commit style, PR checklistCODE_OF_CONDUCT.md— Contributor Covenant 2.1SECURITY.md— disclosure policy and threat modelCHANGELOG.md— release history
Licence
MIT — © 2026 The Thåst Collective