Automatic M3U playlist and XML guide updater for IPTV clients with interactive web interface.
10K+
Self-hosted IPTV server for live TV and sports
Aggregates live TV channels and sports events into a single M3U playlist with full XMLTV guide data. Streams are fully proxied, so upstream sources are never exposed to your clients.
Built for Jellyfin, Emby and Plex, and any other app that takes an M3U playlist and an XMLTV guide. It can also answer as an HDHomeRun tuner, the path Plex and Emby build their Live TV around. The web dashboard is available in 19 languages.
🌐 New here? The setup guide at rebeliptv.com builds a Docker configuration for your system and walks you through connecting your player.
📖 Full documentation and screenshots: github.com/rebeliptv/iptv
Create a docker-compose.yml:
services:
iptv:
image: rebeliptv/iptv:latest
container_name: iptv
hostname: iptv # lets clients on this compose network reach us by name
ports:
- "8080:8080"
# All environment variables are OPTIONAL — the defaults work out of
# the box. Uncomment any you need (see Configuration below):
# environment:
# TZ: "America/New_York" # set to YOUR timezone, e.g. Europe/London, America/Chicago, Etc/UTC
# HEADLESS: "true" # no browser on this box — see Updating below
volumes:
- iptv-data:/app/data
- /var/run/docker.sock:/var/run/docker.sock # enables in-app updates
stop_grace_period: 30s
restart: unless-stopped
volumes:
iptv-data:
docker compose up -d
docker run -d \
--name iptv \
-p 8080:8080 \
-v iptv-data:/app/data \
-v /var/run/docker.sock:/var/run/docker.sock \
--restart unless-stopped \
rebeliptv/iptv:latest
# Environment variables are optional (defaults work). Add -e flags as needed, e.g.:
# -e TZ=America/New_York (set to YOUR timezone — e.g. Europe/London, Etc/UTC)
Then open the dashboard at http://<server-ip>:8080. A short setup wizard walks you through choosing a channel source, your local market, which channel countries to carry, live sports on or off, an optional playlist key and dashboard login, and copying your playlist and guide URLs into your player. You can skip it and change anything later in Settings.
About the Docker socket: the
/var/run/docker.sockmount lets the container update itself from the dashboard. It also gives the container control of the Docker daemon on the host. If you'd rather not allow that, remove the line and update withdocker pullinstead (see Updating below).
| Tag | Use it for |
|---|---|
latest | The newest release. Required for the dashboard's Update now button and for headless mode. |
<version>, e.g. 1.4.5 | Pinning a release. Update now is hidden on a pinned tag; change the tag and pull to upgrade. |
Images are published for linux/amd64 and linux/arm64. What changed in each version: release notes.
TV, team and custom channels keep fixed numbers, so the mappings in your player survive restarts and upgrades:
| Numbers | Channels |
|---|---|
| 1–3999 | TV channels |
| 4000–4199 | Your favourite team channels |
| 5000+ | Live sports events, numbered by start time on each refresh |
| 10000+ | Your custom M3U sources, one range per source |
| URL | |
|---|---|
| M3U playlist | http://<server-ip>:8080/playlist?key=YOUR_KEY |
| XMLTV guide | http://<server-ip>:8080/epg?key=YOUR_KEY |
| XMLTV guide (gzip) | http://<server-ip>:8080/epg.gz?key=YOUR_KEY |
?key= is only needed once you've generated an API key (Settings → Access → Generate Key). Without one, the playlist and guide are open to anyone on your network.
Player running in a container on the same Docker network? A toggle in Settings switches the URLs you copy from the dashboard to the container's hostname (e.g. http://iptv:8080/playlist), so they work without hand-editing.
Recommended tuner settings:
Jellyfin can also add the server as an HDHomeRun tuner (enter <server-ip>:8080), and the stream is identical. The M3U route is suggested because your playlist URL is protected by your API key and the tuner's endpoints can't be.
Both build their Live TV around HDHomeRun tuners, so the server answers as one. No Plex Pass is needed. Check that Settings → Connect → Act as an HDHomeRun tuner is on (it is by default).
<server-ip>:8080. Skip the antenna lineup step, choose Have an XMLTV guide? and give it the guide URL, then check the channel mapping and save.<server-ip>:8080, then add the guide URL as an XMLTV guide source.Important: the tuner's endpoints are not protected by your API key, because the HDHomeRun protocol has no way to carry one. Use it on a trusted or local network, not one exposed to the internet.
Settings → Connect → Simultaneous streams (default 4, range 1–32) sets how many different channels play at once, across the tuner, the playlist and the dashboard. Several devices watching the same channel count as one. A channel past the limit shows a stream limit reached card and starts on its own as soon as another channel stops. Set it to what the line behind your channels can actually carry.
All environment variables are optional.
| Variable | Default | Description |
|---|---|---|
TZ | Etc/UTC | Your timezone. Also picks the default local market for ABC / CBS / NBC / FOX (override it in Settings → Content → Local Market) |
HEADLESS | false | For boxes nobody opens a browser on. See Headless mode below |
PORT | 8080 | Server port |
HOST | 0.0.0.0 | Bind address |
CRON_SCHEDULE | 30 * * * * | Data refresh schedule (cron). Each server starts its refresh at its own fixed point up to 20 minutes after this |
TRUSTED_PROXIES | (none) | Only behind a reverse proxy: its addresses or CIDR ranges, comma-separated. See Reverse proxy below |
RESET_AUTH | false | Locked out of the dashboard? Set to true and restart to remove every dashboard login, then remove it again. While it is set, logins are cleared on every start |
Sports, leagues, channel countries, local market, feed source, stream buffering and the tuner are dashboard settings, not environment variables.
Your data lives in the /app/data volume and survives restarts and upgrades. The database snapshot in it is encrypted at rest with AES-256-GCM.
From the dashboard: when a newer version exists, an Update now button appears on the Dashboard and in Settings → Server. Click it and the server downloads the new version and restarts, keeping your data. It needs the :latest tag and the Docker socket mount shown above. A server that falls too far behind to run shows a page saying so at its usual address, with the same button.
From the command line:
docker pull rebeliptv/iptv:latest
docker compose up -d
Your data lives in the iptv-data volume, so this only swaps in the new image.
docker restartis not an update. It starts the same container again on the same old image.docker compose up -dis what recreates it on the image you just pulled.
Headless mode: if nothing on the box has a browser (a NAS, a Kodi/LibreELEC box, a server you only reach over SSH), set HEADLESS=true. The server then checks for and installs new versions on its own, waiting until nothing is streaming so it never interrupts a viewer, and skips the first-run wizard so a fresh install needs no visit to the dashboard. It needs the Docker socket mount and the :latest tag.
Restarting: Settings → Server → Restart Server restarts on the same version with nothing lost, on any setup.
The playlist and guide URLs are built from the Host header your proxy passes through, and switch to https when the proxy sends X-Forwarded-Proto: https, so forward the original Host. Set TRUSTED_PROXIES to your proxy's address so logs and the login rate limit see the real visitor instead of the proxy. Left unset, no proxy is trusted, which is the safe default.
Nginx
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.iptv.rule=Host(`iptv.example.com`)"
- "traefik.http.services.iptv.loadbalancer.server.port=8080"
Proprietary: free for personal, non-commercial use, and only in its published container form. See the LICENSE for details.
Content type
Image
Digest
sha256:03deacb40…
Size
17.8 MB
Last updated
1 day ago
docker pull rebeliptv/iptv