iptv-proxy is a reverse proxy for IPTV: give it an M3U/M3U8 playlist or an Xtream Codes account, and it serves the same channels, movies and series from your own address, with a user and a password you choose.
Your players (TiviMate, IPTV Smarters, VLC, Kodi...) talk to the proxy and never see the provider's address or credentials. Media servers (Plex, Jellyfin, Emby, Channels DVR) can see the live channels as an HDHomeRun TV tuner, with their guide. Use it to share IPTV at home without handing out the provider's login, to put a provider behind your own domain, HTTPS or VPN, or to give every device one address that does not change.
It is one binary or one container, set up with a few flags or environment variables. There is no database and nothing to configure in a web interface; a read-only status page shows what is being watched.
In the examples, 192.168.1.10 is the machine running the proxy, as your
players reach it, and family / choose-a-password are the credentials you
give to your players. Replace them with your own.
docker run -d --name iptv-proxy -p 8080:8080 \
-e M3U_URL="http://provider.example:8080/playlist.m3u" \
-e PROXY_HOSTNAME=192.168.1.10 \
-e PROXY_USER=family \
-e PROXY_PASSWORD=choose-a-password \
-e GIN_MODE=release \
pierro777/iptv-proxy:latestGive this address to your player:
http://192.168.1.10:8080/iptv.m3u?username=family&password=choose-a-password
To check it from a terminal:
curl "http://192.168.1.10:8080/iptv.m3u?username=family&password=choose-a-password"The playlist can also be a local file: mount it and give its path.
docker run -d --name iptv-proxy -p 8080:8080 \
-v "$PWD/iptv.m3u:/iptv.m3u:ro" \
-e M3U_URL=/iptv.m3u \
-e PROXY_HOSTNAME=192.168.1.10 \
-e PROXY_USER=family \
-e PROXY_PASSWORD=choose-a-password \
-e GIN_MODE=release \
pierro777/iptv-proxy:latestdocker run -d --name iptv-proxy -p 8080:8080 \
-e XTREAM_BASE_URL="http://provider.example:8080" \
-e XTREAM_USER=xtream_user \
-e XTREAM_PASSWORD=xtream_password \
-e PROXY_HOSTNAME=192.168.1.10 \
-e PROXY_USER=family \
-e PROXY_PASSWORD=choose-a-password \
-e GIN_MODE=release \
pierro777/iptv-proxy:latestIn your player, choose the Xtream Codes login and enter:
Server: http://192.168.1.10:8080
Username: family
Password: choose-a-password
A player that only takes a playlist can use the usual Xtream addresses:
Playlist: http://192.168.1.10:8080/get.php?username=family&password=choose-a-password&type=m3u_plus&output=ts
Guide: http://192.168.1.10:8080/xmltv.php?username=family&password=choose-a-password
| Registry | Image |
|---|---|
| Docker Hub | pierro777/iptv-proxy |
| GitHub | ghcr.io/pierre-emmanuelj/iptv-proxy |
Tags: latest, and for a given version v4.7.1, v4.7 or v4 (v3 for the
3.x versions). Since v3.12.0 they work on amd64 and on ARM (Raspberry Pi, Apple silicon): Docker
pulls the image of your machine. The -amd64 and -arm64 tags
(pierro777/iptv-proxy:latest-arm64) name one architecture, as before.
Each tag also has an image with ffmpeg, about 140 MB larger: latest-ffmpeg,
v4-ffmpeg, v4.7.0-ffmpeg... Take it if the HDHomeRun tuner serves
channels your provider has only as HLS (see
Plex and other media servers); nothing
else needs it.
services:
iptv-proxy:
image: pierro777/iptv-proxy:latest
restart: unless-stopped
ports:
# the same port as PORT below
- 8080:8080
environment:
# Either an M3U playlist (an address, or a file mounted in the container)...
M3U_URL: "http://provider.example:8080/playlist.m3u"
# ...or an Xtream Codes account (remove M3U_URL then)
# XTREAM_BASE_URL: "http://provider.example:8080"
# XTREAM_USER: xtream_user
# XTREAM_PASSWORD: xtream_password
PORT: 8080
# Name or IP your players reach this machine at
PROXY_HOSTNAME: 192.168.1.10
# What your players log in with
PROXY_USER: family
PROXY_PASSWORD: choose-a-password
GIN_MODE: releasedocker compose up -dThe docker-compose.yml of this repository does the
same with an Xtream Codes account, building the image from the sources.
Download the archive for your system (Linux, macOS, Windows; amd64 and arm64;
also .deb and .rpm) from the
releases,
or build it with Go 1.27 or later:
git clone https://github.com/pierre-emmanuelJ/iptv-proxy.git
cd iptv-proxy
go build -o iptv-proxy .GIN_MODE=release ./iptv-proxy \
--m3u-url "http://provider.example:8080/playlist.m3u" \
--hostname 192.168.1.10 \
--user family \
--password choose-a-passwordQuote the playlist address: it usually contains ? and &.
Every option is a flag, an environment variable (the flag's name in upper
case, with _ instead of -) or a line of the configuration file. A flag
wins over the variable, and the variable over the file.
| Flag | Environment variable | Default | What it does |
|---|---|---|---|
--m3u-url, -u |
M3U_URL |
Provider playlist: an http(s) address or a local file. |
|
--xtream-base-url |
XTREAM_BASE_URL |
Provider's Xtream Codes address, e.g. http://provider.example:8080. |
|
--xtream-user |
XTREAM_USER |
Provider's Xtream Codes user. | |
--xtream-password |
XTREAM_PASSWORD |
Provider's Xtream Codes password. | |
--xtream-passthrough |
XTREAM_PASSTHROUGH |
false |
Players log in with their own account of the provider. See Each player with its own provider account. |
--hostname |
PROXY_HOSTNAME (or HOSTNAME) |
Name or IP your players reach the proxy at. It is written in every address the proxy gives out. | |
--port |
PORT |
8080 |
Port the proxy listens on. |
--listen-address |
LISTEN_ADDRESS |
every interface | IP address the proxy listens on, e.g. 127.0.0.1 behind a reverse proxy on the same machine. |
--advertised-port |
ADVERTISED_PORT |
value of --port |
Port written in the addresses the proxy gives out, when it differs from the listening port (behind a reverse proxy, or a different published Docker port). |
--https |
HTTPS |
false |
Write https:// instead of http:// in the addresses the proxy gives out. The proxy itself always listens in plain HTTP: put a reverse proxy in front for TLS. |
--user |
PROXY_USER (or USER) |
usertest |
User your players log in with. |
--password |
PROXY_PASSWORD (or PASSWORD) |
passwordtest |
Password your players log in with. |
--max-connections |
MAX_CONNECTIONS |
0 (no limit) |
Streams that user may watch at once. See Several users. |
--m3u-file-name |
M3U_FILE_NAME |
iptv.m3u |
Name of the playlist the proxy serves: http://host:port/iptv.m3u. |
--custom-endpoint |
CUSTOM_ENDPOINT |
Prefix put before every path: http://host:port/<custom-endpoint>/iptv.m3u. |
|
--custom-id |
CUSTOM_ID |
derived from your settings | First path element of M3U track addresses. The same settings give the same addresses, restart after restart. |
--m3u-cache-expiration |
M3U_CACHE_EXPIRATION |
1 |
Hours a playlist is kept before reading it again from the provider (M3U playlists included since v3.13.0). |
--xmltv-url |
XMLTV_URL |
the guide the playlist names | Guide (XMLTV) of an M3U playlist: an http(s) address or a local file. It is served at /xmltv.php. |
--xtream-api-get |
XTREAM_API_GET |
false |
Build the get.php playlist (live channels) from the provider's API, for providers that disabled get.php. |
--xtream-api-get-movies |
XTREAM_API_GET_MOVIES |
false |
Add the provider's movies to that generated playlist. Off by default: a catalogue of tens of thousands of movies makes a playlist some players cannot load. Series are not added (see below). |
--user-agent |
USER_AGENT |
User-Agent sent to the provider instead of the player's. Some providers only answer known players. | |
--no-stream-sharing |
NO_STREAM_SHARING |
false |
Open one provider connection per player for a live stream, instead of sharing one between the players watching it. |
--status-password |
STATUS_PASSWORD |
Password of a read-only status page at /status. See Status page. |
|
--proxy-logos |
PROXY_LOGOS |
false |
Serve the logos and covers of playlists, of the Xtream API and of the guides through the proxy too, so that players reach no other host. |
--hdhomerun-port |
HDHOMERUN_PORT |
Port of an HDHomeRun tuner for Plex, Emby, Jellyfin or Channels DVR. Local network only. See Plex and other media servers. | |
--hdhomerun-group-regex, --hdhomerun-channel-regex, --hdhomerun-group-exclude-regex, --hdhomerun-channel-exclude-regex |
HDHOMERUN_GROUP_REGEX... |
Filters of the tuner alone, applied after the proxy's: the media server gets fewer channels than your players. | |
--hdhomerun-tuners |
HDHOMERUN_TUNERS |
the account's connections (the sources' together), else 2 |
Number of tuners announced: how many channels a media server plays at once. |
--ffmpeg |
FFMPEG |
ffmpeg |
ffmpeg the HDHomeRun tuner turns HLS channels into MPEG-TS with, when it is found (the -ffmpeg images have it). none goes without. |
--group-regex |
GROUP_REGEX |
Keep only the live channels whose group matches this regular expression. See Filtering channels. | |
--channel-regex |
CHANNEL_REGEX |
Keep only the live channels whose name matches this regular expression. | |
--group-exclude-regex |
GROUP_EXCLUDE_REGEX |
Leave out the live channels whose group matches this regular expression. | |
--channel-exclude-regex |
CHANNEL_EXCLUDE_REGEX |
Leave out the live channels whose name matches this regular expression. | |
--iptv-proxy-config |
IPTV_PROXY_CONFIG |
.iptv-proxy.yaml in the home or current directory |
YAML file holding the same options, named as the flags (m3u-url: ...), the users and the sources. |
--version |
Prints the version and exits. |
Good to know:
- Change
--userand--password: the defaults are public. USERandHOSTNAMEare also ordinary system variables: a shell setsUSERto your login name, and Docker setsHOSTNAMEto the container's ID. Since v3.11.0, preferPROXY_USER,PROXY_PASSWORDandPROXY_HOSTNAME: they win over the old names, which keep working. Since v3.12.0,user,passwordandhostnamein the configuration file also win over the old names.GIN_MODEis not an option of the proxy but of its web framework. Since v3.10.0 the proxy runs inreleasemode unless you set it. Before that, setGIN_MODE=releaseas the examples do: the debug mode lists the routes at startup, and they contain your user and password. The access log masks them in both modes.
The proxy reads the provider's playlist at startup and serves it at
/iptv.m3u with every track address replaced by its own. All other lines
(names, logos, groups, guide IDs, player options) are kept as the provider
wrote them. When a player asks for it and it is older than
--m3u-cache-expiration (one hour by default), the playlist is read again: no
restart is needed to pick up the provider's changes. If the provider fails,
the previous playlist is kept.
A track's address on the proxy is derived from its address at the provider: it stays the same when the playlist is read again, wherever the track moves in it, and from one start of the proxy to the next.
The provider's playlist:
#EXTM3U
#EXTINF:-1 tvg-id="news.example" tvg-name="News" tvg-logo="http://provider.example/logos/news.png" group-title="News",News HD
http://provider.example:8080/live/news/1.ts
#EXTINF:-1 tvg-id="sport.example" tvg-name="Sport" tvg-logo="http://provider.example/logos/sport.png" group-title="Sport",Sport HD
http://provider.example:8080/live/sport/2.m3u8?token=abcWhat your players get:
#EXTM3U
#EXTINF:-1 tvg-id="news.example" tvg-name="News" tvg-logo="http://provider.example/logos/news.png" group-title="News",News HD
http://192.168.1.10:8080/e3c0c308/family/choose-a-password/4f2a9c1d7b21e0aa/1.ts
#EXTINF:-1 tvg-id="sport.example" tvg-name="Sport" tvg-logo="http://provider.example/logos/sport.png" group-title="Sport",Sport HD
http://192.168.1.10:8080/e3c0c308/family/choose-a-password/9b03e5c2d8a17f46/2.m3u8e3c0c308 is the --custom-id, and 4f2a9c1d7b21e0aa names the track.
Tokens and other query parameters of the provider's addresses stay on the
proxy.
When the playlist names a guide (url-tvg or x-tvg-url in its first line),
or --xmltv-url gives one, the proxy serves it at
/xmltv.php?username=...&password=..., and the playlist names that address
instead. Players load the guide through the proxy, and the filters apply to
it.
Some playlists name the provider's credentials outside of the track
addresses too: a guide address in url-tvg, a catch-up address in
catchup-source, a player option. Such an attribute or line is removed, so
that the credentials never reach a player. (In an Xtream Codes playlist, they
point to the proxy instead: see below.)
The proxy answers the Xtream Codes client API like the provider does: live, movies, series, catch-up and the guide. Your players log in with the proxy's address and credentials, the proxy asks the provider with the real ones.
| Provider | Proxy | |
|---|---|---|
| Server | http://provider.example:8080 |
http://192.168.1.10:8080 |
| User | xtream_user |
family |
| Password | xtream_password |
choose-a-password |
The provider's answers are passed on as they are, so the fields and quirks of
any provider reach the player. Only what names the provider is rewritten: the
account and server of the login answer, and the addresses holding its
credentials. In the get.php playlist, the guide (url-tvg) and catch-up
(catchup-source) addresses of the provider become the proxy's, and work
through it.
Endpoints served:
| Endpoint | What it is |
|---|---|
/player_api.php |
The client API (login, categories, streams, movie and series details, short guide). |
/get.php |
The M3U playlist, with the same parameters as the provider's (type, output). |
/xmltv.php |
The full guide (XMLTV), streamed from the provider. |
/apiget |
A playlist of the live channels built from the API. |
/<user>/<password>/<id>, /live/..., /movie/..., /series/..., /timeshift/... |
The streams. |
/player_api.php, /get.php, /xmltv.php and /apiget take
username=...&password=....
If you give --m3u-url the provider's get.php address
(http://provider.example:8080/get.php?username=xtream_user&password=xtream_password&type=m3u_plus&output=ts),
the Xtream options are read from it: everything above is served, and that
playlist is also available at /iptv.m3u.
With the Xtream options alone, /iptv.m3u is the account's playlist too (the
same as /get.php).
The playlist built from the API (/apiget, or /get.php with
--xtream-api-get) holds the live channels, and the movies with
--xtream-api-get-movies. Series are not in it: the API gives the episodes of
one series at a time, so listing them all would take one request per series.
Players that speak the Xtream API get movies and series from it directly.
HLS streams (.m3u8) work in both modes, whatever the provider. Every address
an HLS playlist names (variants, segments, keys, audio tracks) is replaced by
an address of the proxy, /hls/<token>/<name>, so the whole stream goes
through the proxy, on any host and after any redirect. The token is the
provider's address, encrypted: a player never sees the provider's host,
credentials or session tokens. Nothing is stored, and tokens stay valid across
restarts.
One user and password is all most homes need, and the options above give
exactly that. To give each person or device their own login, list the users
in the configuration file (--iptv-proxy-config, or IPTV_PROXY_CONFIG in
Docker):
# /config/iptv-proxy.yaml
users:
- name: family
password: choose-a-password
max-connections: 2
- name: kids
password: another-password
max-connections: 1
group-regex: "(?i)kids|cartoon"
- name: grandma
password: a-third-one
group-regex: "^FR "
channel-exclude-regex: "(?i)adult"docker run -d --name iptv-proxy -p 8080:8080 \
-v "$PWD/iptv-proxy.yaml:/config/iptv-proxy.yaml:ro" \
-e IPTV_PROXY_CONFIG=/config/iptv-proxy.yaml \
-e XTREAM_BASE_URL="http://provider.example:8080" \
-e XTREAM_USER=xtream_user \
-e XTREAM_PASSWORD=xtream_password \
-e PROXY_HOSTNAME=192.168.1.10 \
pierro777/iptv-proxy:latest- When
usersis there, those users replace--userand--password. The other options (provider, address, filters) stay where they are: flags, variables or the same file. - Each user logs in with their own name and password, and their playlists and stream addresses hold their own credentials.
max-connectionsis how many streams the user watches at once (none means no limit). At the limit, a new stream from the same device (the same address) replaces that device's oldest one: zapping keeps working. A stream from another device is refused until one stops. The login answer gives players the user's limit and the streams they watch. HLS segments are not counted: a live HLS channel is many short requests.- Filters (
group-regex,channel-regex,group-exclude-regex,channel-exclude-regex) apply to that user on top of the proxy's own, with the same rules (see Filtering channels): a live channel left out does not play, even asked by its id. Movies and series are not filtered. - Names must not be
hls,logo,live,movie,series,timeshiftorplay: they are the first elements of the proxy's own addresses. --max-connections(MAX_CONNECTIONS) sets the limit of the one user of--userand--password, without a file.
When everyone in the house has their own account with the same provider,
the proxy does not need one: with --xtream-passthrough, players log in to
the proxy with their provider account, and the proxy only gives the
provider's address.
docker run -d --name iptv-proxy -p 8080:8080 \
-e XTREAM_BASE_URL="http://provider.example:8080" \
-e XTREAM_PASSTHROUGH=true \
-e PROXY_HOSTNAME=192.168.1.10 \
pierro777/iptv-proxy:latest- Players are set up with the proxy's address and their own provider user and password. Their playlists, guide and stream addresses name the proxy and hold their own account; the provider's address is left out.
- The proxy asks the provider whether it accepts an account at the first request, then again every 10 minutes. An account refused by the provider gets a 401. An account it accepted keeps playing while the provider cannot answer, with the last good answers.
- Each account is held to the streams the provider allows it
(
max_connectionsof its login answer), with the same rule as several users: zapping on the same device works, another device waits.--max-connectionssets another limit for every account. - The proxy's filters apply to every account. Live streams are shared between the players of the same account only.
- There are no proxy users:
--xtream-user,--xtream-password,usersin the configuration file,--m3u-urland the HDHomeRun tuner do not go with it, and the proxy says so at startup.--userand--passwordare not used.
A second account, at the same provider or another, can back up the first:
list it under sources in the configuration file. The proxy then serves
both accounts as one catalogue.
# /config/iptv-proxy.yaml
sources:
- name: backup
xtream-base-url: http://other-provider.example:8080
xtream-user: other_user
xtream-password: other_password
max-connections: 1 # optional: the account's own limit by defaultThe Xtream options (XTREAM_BASE_URL, XTREAM_USER, XTREAM_PASSWORD)
stay the first source; without them, the first of sources is.
- Ids. The first source keeps its ids: the players set up before see the same channels under the same numbers. The second source's ids are shown as 100000000 + id, the third's as 200000000 + id, and so on.
- Categories of the same name are one, with the first source's id.
- A live channel several sources have is shown once, from the first of
them. Channels are recognised by their guide id (
epg_channel_id): a channel without one is shown from each source. - Failover. When a live channel fails at its source (an error, an HTTP error), the proxy opens it at the next source that has it. A source already holding as many streams as its account allows is passed over: its channels play from another source while its connections are busy.
- Movies and series of every source are listed, each from its own source.
- The guide is the first source's, plus the channels only the other sources
have. The playlist (
get.php,iptv.m3u) is built from the merged catalogue, as with--xtream-api-get. - A source that does not answer is left out of the lists for that request; the last complete answer is served instead when there is one.
- Sources are Xtream accounts: they do not go with
--m3u-urlor with--xtream-passthrough.
With --hdhomerun-port, the proxy also answers as an HDHomeRun network tuner
on that port. Plex, Emby, Jellyfin and Channels DVR then see your live
channels as a TV tuner, with a guide matched to them, and can record.
docker run -d --name iptv-proxy -p 8080:8080 -p 192.168.1.10:5004:5004 \
-e XTREAM_BASE_URL="http://provider.example:8080" \
-e XTREAM_USER=xtream_user \
-e XTREAM_PASSWORD=xtream_password \
-e PROXY_HOSTNAME=192.168.1.10 \
-e PROXY_USER=family \
-e PROXY_PASSWORD=choose-a-password \
-e HDHOMERUN_PORT=5004 \
-e HDHOMERUN_GROUP_REGEX='^(FR|UK) ' \
pierro777/iptv-proxy:latestIn Plex: Settings > Live TV & DVR > Set up Plex DVR, then "Don't see your
HDHomeRun device? Enter its network address manually": 192.168.1.10:5004.
When Plex asks for the guide, choose the XMLTV option and give
http://192.168.1.10:5004/guide.xml.
When Plex runs in Docker on the same machine, put both containers on one
network and give Plex iptv-proxy:5004 and http://iptv-proxy:5004/guide.xml
instead: the tuner's port then needs no publishing at all.
- A tuner has no login: anyone who reaches its port can watch. Keep it on your local network: do not publish it on the Internet or behind your reverse proxy. In exchange, nothing the tuner answers holds your proxy's or your provider's credentials.
- The tuner serves the live channels the filters keep, and only those. Use
them: a media server is not made for 10,000 channels. Besides the proxy's
filters, the tuner has its own (
--hdhomerun-group-regex,--hdhomerun-channel-regex,--hdhomerun-group-exclude-regex,--hdhomerun-channel-exclude-regex), applied after them: your players keep every channel while the media server gets a few groups. - Plex takes no more than about 400 channels with a guide for a tuner: past that, adding the DVR fails at its last step ("try again later"). The tuner helps: a channel the provider lists several times with the same guide id (another quality, a backup) is one tuner channel, the first of the list; the others are its fallbacks, played when it fails. If Plex still refuses, narrow the tuner's filters.
- With an Xtream account, a channel's number is its id at the provider: it
does not change when the provider reorders its list, so recordings stay on
their channel. With an M3U playlist, it is the track's
tvg-chno, else its place in the playlist. - The guide at
/guide.xmlnames each channel by its tuner number, which is how media servers match a guide to channels. - Channel logos in Plex. Plex's apps are served over HTTPS and refuse a
logo at a plain
http://address; many providers have only those. When the proxy's own address is HTTPS (--https, see Behind a reverse proxy), the tuner's guide gives such logos through that address, where the Plex apps load them and the proxy fetches them. With--proxy-logos, all of them come through it. - The tuner announces as many tuners as your Xtream account allows
connections, or, with several sources, as their accounts allow together
(
--hdhomerun-tunersto change it): a media server never opens more streams than that. - Media servers expect MPEG-TS. With an Xtream account, the tuner asks the
provider for MPEG-TS. A channel the provider has only as HLS (an M3U
playlist of
.m3u8addresses, or an account whoseallowed_output_formatshas nots) plays when ffmpeg is at hand: take an-ffmpegimage (see Docker images), or haveffmpegin thePATHof the binary. ffmpeg then reads the HLS stream and writes it as MPEG-TS, without encoding it again; viewers of a channel share one ffmpeg. Without ffmpeg, such a channel is passed on as a playlist, which media servers do not play. - Plex finds a tuner by its address, entered by hand: automatic discovery on the network is not supported.
With --status-password (STATUS_PASSWORD), the proxy serves a read-only
page at http://host:port/status. It asks for that password; any user name
does.
It shows:
- the streams being watched: by whom, from which address, for how long;
- the users and their limits;
- how many live streams are open at the provider, shared between their viewers;
- the sources and the streams each holds, when there are several;
- the HDHomeRun tuner's channels;
- the answers kept for when the provider fails.
The page refreshes itself every 10 seconds; /status.json gives the same
in JSON. It changes nothing, and shows no password: stream addresses are
masked, sources are named by their host. iptv-proxy --version prints the
version.
Providers fail now and then: an error for a minute, a maintenance page, a guide that will not generate. The proxy keeps the last answer the provider gave in full for the lists players load (the login, categories, channels, movies, series, details, playlists and the guide), compressed in memory. When the provider fails, players get that answer instead of an error, and the log says so. Streams themselves are not kept: when the provider is down, nothing plays.
A refusal (wrong account, expired subscription) is passed on: it says something you need to know.
Four options keep the live channels you want and leave out the others. Each
takes a regular expression matched
against a channel's group (group-title in a playlist, the category in the
Xtream API) or its name:
--group-regex,--channel-regex: keep only what matches.--group-exclude-regex,--channel-exclude-regex: leave out what matches, even if it was kept by the first two.
A channel is kept when it passes all of them. The expressions are case
sensitive; start one with (?i) to ignore case.
-e GROUP_REGEX='^(FR|UK) ' \
-e GROUP_EXCLUDE_REGEX='(?i)adult|xxx' \
-e CHANNEL_EXCLUDE_REGEX='(?i)backup|test' \The filters apply to:
- the M3U playlist (
/iptv.m3u) and the Xtream playlists (/get.php,/apiget): a channel left out is not in it, and in M3U mode it has no address on the proxy; - the live categories and channels of the Xtream API;
- the guide (
/xmltv.php): only the channels kept, and their programmes, are in it. A guide of thousands of channels shrinks to the ones you watch.
Movies and series are not filtered. In a get.php playlist that holds movies,
the same rules apply to them, by their group and name.
The filters also hold for streams: a live channel left out does not play, even asked by its id, and the provider is not asked for it. A channel the provider just added plays as soon as it passes the filters: when a stream asks for an id the list does not have, the list is read again (at most once a minute).
An IPTV account allows a few connections at a time, often a single one. When several players watch the same live channel, the proxy opens one connection to the provider and shares it: the first player opens the stream, the next ones join it where it is, and the connection is closed when the last one leaves.
If the provider drops the stream, or leaves it silent for 20 seconds, the proxy opens it again while someone is watching, so the player does not have to reconnect. After a few attempts that fail, the stream ends.
Movies, series and catch-up are files: each player reads its own, from where
it wants. --no-stream-sharing gives every player its own connection for live
streams too.
The proxy listens in plain HTTP. To serve it on your own domain with HTTPS, put a reverse proxy (Traefik, Caddy, nginx...) in front, and tell iptv-proxy which addresses to give out:
environment:
PORT: 8080 # where iptv-proxy listens
PROXY_HOSTNAME: iptv.example.com
ADVERTISED_PORT: 443 # the port your players use
HTTPS: 1 # addresses given out start with https://Your players then use https://iptv.example.com:443/iptv.m3u?username=...&password=....
The proxy's user and password travel in every address, so use HTTPS as soon as the proxy is reachable from the Internet.
A complete example with Traefik and Let's Encrypt is in the
traefik folder. From the root of the repository:
cp -r ./traefik/* .
mkdir -p Traefik/etc/traefik Traefik/logThen replace iptv.proxyexample.xyz with your domain in docker-compose.yml,
set your e-mail address in Traefik/traefik.yaml, and start it:
docker compose up -d- It does not provide channels or streams: you need a playlist or an account from a provider.
- It does not edit the catalogue: no channel editor, no renaming, no guide mapping. Players get what the provider sends.
- It does not transcode, record or cache streams: they are passed on as they come. The one exception is the tuner's HLS channels, which ffmpeg turns into MPEG-TS, without encoding them again.
- It has no web interface to change anything: the status page only shows.
Nothing is planned beyond fixes: what comes next depends on what users ask for. Open an issue for a bug or an idea, or a discussion for a question.
See the changelog for what each release brought.
Bug reports, ideas and pull requests are welcome: see CONTRIBUTING.md. Questions go to the discussions, vulnerabilities to SECURITY.md.
If the project is useful to you, you can buy me a beer:
