Run a 24/7 TV channel on the TLTV network. Start a channel, broadcast content, relay or bridge channels, explore the network, or program a cathode broadcast server. Triggers include tltv, television, channel, broadcast, stream, relay, bridge.
You help users create and run television channels on the TLTV network — a federation protocol for 24/7 TV channels. No signup, no platform, no permission needed. A channel is an Ed25519 key, a stream, and a link.
Your primary tool is the tltv CLI — a single static binary that handles
identity, signing, serving, bridging, relaying, and network operations. For
advanced broadcast programming (plugins, scheduling, content generation), you
use the cathode broadcast server's REST API.
| Variable | Default | Purpose |
|---|---|---|
TLTV_HOST | localhost:8000 | Where the tltv CLI server listens |
CATHODE_URL | http://localhost:8888 | Cathode REST API via traefik (advanced mode) |
API_KEY |
| (none) |
| Cathode API key (if server requires auth) |
Check if tltv is installed:
tltv version
If missing, install it:
curl -sSL https://raw.githubusercontent.com/tltv-org/cli/main/install.sh | sh
Four commands. No dependencies beyond the tltv binary.
tltv keygen
This creates an Ed25519 keypair. The channel ID (starts with TV, 46 characters)
is your permanent identity. The .key file is your private key — back it up,
never share it, never print it.
tltv server test --name "My Channel" -k TV*.key
Or with Docker (recommended — handles restarts, survives reboots):
docker run -d --restart unless-stopped \
--name my-channel \
-p 8000:8000 \
-v $(pwd):/data \
-e NAME="My Channel" \
-e KEY=/data/TV*.key \
ghcr.io/tltv-org/cli server test
This starts a full TLTV origin server with SMPTE color bars, a wall clock, and a 1 kHz tone. Pure Go — no ffmpeg, no external tools. It serves:
/.well-known/tltv — node info/tltv/v1/channels/{id} — signed metadata/tltv/v1/channels/{id}/stream.m3u8 — HLS stream/tltv/v1/channels/{id}/guide.json — signed guide/tltv/v1/peers — peer exchangeThe channel is live at http://localhost:8000.
tltv format <channel-id> --hint <your-host>:8000
This produces a tltv:// URI — the address anyone uses to find your channel.
Get the stream URL and open it in any player:
# Get the HLS URL
tltv stream --url tltv://<channel-id>@localhost:8000
# VLC (most people already have this)
vlc "$(tltv stream --url tltv://<channel-id>@localhost:8000)"
# mpv
mpv "$(tltv stream --url tltv://<channel-id>@localhost:8000)"
# ffplay (comes with ffmpeg)
ffplay "$(tltv stream --url tltv://<channel-id>@localhost:8000)"
# Or paste the HLS URL directly into any browser
# (most browsers play .m3u8 natively or via an HLS extension)
VLC is the easiest path — everyone already has it, and it plays HLS natively.
Just paste the stream URL from tltv stream --url.
For a web-based viewer, use phosphor —
it resolves tltv:// URIs in the browser with full protocol support. Cathode's
docker-compose bundles phosphor automatically. There's a live demo at
demo.timelooptv.org.
For IPTV apps (TiviMate, Kodi, IPTV Smarters), cathode and phosphor serve M3U playlists and XMLTV guides that these apps can subscribe to directly.
Your channel starts on localhost:8000. To let other people watch, you need
to make it reachable from the internet and tell the server its public address.
# Install cloudflared
# macOS: brew install cloudflared
# Linux: see https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
# Start a quick tunnel (gives you a random *.trycloudflare.com URL)
cloudflared tunnel --url http://localhost:8000
# Note the URL it prints, e.g. https://random-words.trycloudflare.com
# Restart the server with that hostname:
tltv server test --name "My Channel" -k TV*.key \
--hostname random-words.trycloudflare.com:443
The --hostname flag is important — it goes into the signed origins field
in your channel's metadata. Viewers use it to find your server.
tailscale funnel 8000
# Your channel is at https://<machine-name>.<tailnet>.ts.net
tltv server test --name "My Channel" -k TV*.key \
--hostname <machine-name>.<tailnet>.ts.net:443
Put Caddy, nginx, or traefik in front of port 8000 with TLS:
# Caddy (auto-TLS with Let's Encrypt)
# Caddyfile:
# mychannel.example.com {
# reverse_proxy localhost:8000
# }
tltv server test --name "My Channel" -k TV*.key \
--hostname mychannel.example.com:443
If your router lets you forward port 8000, you can expose it directly. This works but means no TLS — fine for testing, not for production.
tltv server test --name "My Channel" -k TV*.key \
--hostname <your-public-ip>:8000
Build and share your tltv:// URI:
tltv format <channel-id> --hint mychannel.example.com:443
# → tltv://[email protected]:443
# Your friend watches it:
vlc "$(tltv stream --url tltv://[email protected]:443)"
Capture a single frame from any TLTV stream:
ffmpeg -i "$(tltv stream --url <target>)" -vframes 1 -q:v 2 /tmp/snapshot.jpg
Or use the bundled script:
bash scripts/snapshot.sh <target> /tmp/snapshot.jpg
Where <target> is a tltv:// URI or id@host:port. View the image with your
vision capability to see exactly what viewers see.
Do this:
tltv stream <target>
Shows segment count, target duration, and whether the stream is live.
tltv fetch <target>
Fetches and cryptographically verifies the channel's signed metadata.
tltv guide <target>
Shows what's currently airing and upcoming. Marks the current entry.
tltv node example.com
Fetches /.well-known/tltv — shows protocol version, hosted channels, and
relayed channels.
tltv crawl example.com
BFS-crawls the gossip network starting from a node. Discovers channels across
the network via peer exchange. Use --depth to control how far to go.
tltv resolve "tltv://[email protected]:443"
Full resolution: tries hints, verifies metadata signatures, follows migration chains (up to 5 hops), checks stream availability.
Run a relay node that re-serves channels from upstream with full signature