Self-hosted Xtream Codes IPTV proxy & panel for TiViMate, Smarters and Kodi
3.8K
A self-hosted Xtream Codes proxy and control panel — in a single container.
Point Cedarwing at your existing Xtream or M3U lines and it becomes one tidy dashboard: hand out a separate login to every device, watch what's playing live, route any provider through WireGuard, and browse a full TV guide in the browser. No panel sprawl, no per-app credentials to juggle.
/api/docs.Full Rust, one small image, Postgres for storage.
Save this as docker-compose.yml, set a master key, and bring it up:
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_USER: cedarwing
POSTGRES_PASSWORD: cedarwing
POSTGRES_DB: cedarwing
volumes:
- cedarwing-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U cedarwing"]
interval: 5s
timeout: 5s
retries: 10
app:
image: sandeepsb/cedarwing:latest
depends_on:
db:
condition: service_healthy
environment:
CW_DATABASE_URL: postgres://cedarwing:cedarwing@db:5432/cedarwing
CW_BIND_ADDR: 0.0.0.0:8080
# Public URL for M3U / stream links. Leave unset behind a reverse proxy —
# it's derived from the incoming request automatically.
CW_PUBLIC_URL: ${CW_PUBLIC_URL:-http://localhost:8080}
# Encrypts stored provider credentials. Generate once, then keep it safe:
# openssl rand -base64 32
CW_MASTER_KEY: ${CW_MASTER_KEY:?set CW_MASTER_KEY in your environment or .env}
ports:
- "8080:8080"
volumes:
cedarwing-db:
export CW_MASTER_KEY=$(openssl rand -base64 32)
docker compose up -d
Open http://localhost:8080, create your admin account, and add your first source. Database migrations run automatically on start — there's no separate migrate step.
| Variable | Required | Notes |
|---|---|---|
CW_DATABASE_URL | yes | Postgres connection string. Any reachable Postgres works. |
CW_MASTER_KEY | yes | 32-byte base64 (openssl rand -base64 32). Encrypts stored secrets — losing or rotating it makes existing encrypted data unreadable, so treat it as a key, not a password. |
CW_PUBLIC_URL | no | Canonical URL for stream / M3U links. Unset ⇒ derived per-request from Host / X-Forwarded-*, which is what makes a bare reverse-proxy setup work with zero config. |
CW_BIND_ADDR | no | Default 0.0.0.0:8080. |
CW_LOG | no | Tracing filter, e.g. info,cw_api=debug. |
CW_OMDB_KEY | no | OMDb API key (omdbapi.com, free tier) to show IMDb / Rotten Tomatoes ratings for what's playing. Ratings are hidden when unset. |
Behind nginx, Caddy or Cloudflare Tunnel, just proxy to port 8080 and leave
CW_PUBLIC_URL unset.
latest — the newest released build.vX.Y.Z — immutable, per-release tags (e.g. v1.0.1). Pin one of these in
production so a redeploy can't surprise you.Both linux/amd64 and linux/arm64 are published under every tag.
Content type
Image
Digest
sha256:1baaf3eb3…
Size
200.3 MB
Last updated
2 months ago
docker pull sandeepsb/cedarwing