Skip to content

Xtream Services

Xtream Services expose a full Xtream Codes-compatible API backed by groups, channels, and users you define yourself. They are the right blueprint when you want to operate your own panel rather than reverse-proxy an existing provider.

Use one when you need to:

  • Curate a custom lineup from public sources, paid feeds, or your own streams.
  • Hand out per-user logins with expiry dates and concurrent-connection limits.
  • Mix manually-managed channels with auto-imported iptv-org groups in one service.

Anatomy

flowchart TB
    classDef svc  fill:#6366f1,stroke:#4338ca,color:#fff
    classDef grp  fill:#0ea5e9,stroke:#0369a1,color:#fff
    classDef ch   fill:#22d3ee,stroke:#0e7490,color:#0f172a
    classDef usr  fill:#f59e0b,stroke:#b45309,color:#0f172a
    classDef src  fill:#a855f7,stroke:#7e22ce,color:#fff

    S["Xtream service<br/>(/xtreme/...)"]:::svc

    subgraph GROUPS["Groups (Live / VOD / Series)"]
      G1["Group: News"]:::grp
      G2["Group: Sports"]:::grp
      G3["Group: Movies"]:::grp
    end

    subgraph CHANNELS["Channels"]
      C1["Manual channels<br/>+ streamUrl + epgChannelId"]:::ch
      C2["iptv-org imports<br/>(by country, category)"]:::ch
    end

    subgraph USERS["Users"]
      U1["alice — expires 2026-12-31<br/>maxConnections: 2"]:::usr
      U2["bob — active"]:::usr
    end

    S --> GROUPS
    G1 --> C1
    G2 --> C1
    G3 --> C2

    C2 --> IPTV["iptv-org catalog"]:::src
    USERS --> S

Start with the wizard

The fastest way to stand one up is the CLI wizard:

./tunlx --xtremeWizard

It prompts you through:

  1. A service name, host, and port.
  2. Country and category filters for iptv-org imports.
  3. A few demo users.
  4. A safe write-back to config.json (existing services can be replaced after confirmation).

You can also build everything from the dashboard's Add Proxy → Xtream Service flow if you prefer a UI.

Xtream wizard step

Configuration shape

{
  "xtremeServices": [
    {
      "name": "panel",
      "description": "House lineup",
      "welcomeMessage": "Welcome to the panel",
      "thisServerHost": "0.0.0.0",
      "thisServerPort": "20000",
      "route": "system",
      "mediaFlowEnabled": false,
      "remuxHlsStreams": true,
      "groups": [
        {
          "id": "1",
          "name": "US News",
          "type": "live",
          "order": 0,
          "channels": [
            {
              "id": "101",
              "name": "ABC News",
              "streamUrl": "https://example.com/live/abc.m3u8",
              "logo": "https://example.com/logos/abc.png",
              "epgChannelId": "ABC.us",
              "country": "US",
              "enabled": true
            }
          ]
        }
      ],
      "iptvOrgImports": [
        {
          "name": "World Sports",
          "countries": ["GB", "DE", "FR"],
          "categories": ["sports"],
          "limit": 80,
          "includeNsfw": false
        }
      ],
      "users": [
        {
          "username": "alice",
          "password": "$2y$05$...",
          "expiryDate": "2026-12-31T00:00:00Z",
          "maxConnections": 2,
          "active": true,
          "notes": "Premium subscriber"
        }
      ]
    }
  ]
}

See Configuration Reference → Xtream Services for the full field list.

Manage from the dashboard

The service itself is configured here — identity, bind port, and the delivery options including HLS remuxing:

The Xtream service dialog

Categories are split by content type, each with its own count and import menu:

The category manager

Manage channels

  • Manage Channels — add, reorder, enable/disable, and edit channel metadata (logo, EPG channel ID, country, loop flag, EPG override).
  • Manage Categories — group ordering, prefixes, name overrides.
  • Manage Users — create, expire, disable, and adjust connection limits.

Manage users

Per-user controls

Field Purpose
username Xtream login presented by the client.
password bcrypt hash (htpasswd -nbB user pass). Never plaintext.
expiryDate ISO 8601 cutoff after which logins are denied.
maxConnections Concurrent stream cap. 0 / omitted means unlimited.
active Quick on/off without deleting the user.
notes Free-form internal label.

Channel features

  • loop: true — perfect for short placeholder VODs (slate or ad clip) that should look like a 24/7 channel.
  • epgOverride.title / epgOverride.description — show your own programme metadata even when the upstream offers none.
  • enabled: false — hide a channel without losing its config; useful for temporary blackouts.
  • iptvOrgChannelId / backupStreamUrls — provenance written by the Regional IPTV wizard and iptv-org imports: which catalog channel a stream came from, plus ranked alternate URLs that self-healing can swap in.

Real EPG from an XMLTV source

By default a service's xmltv.php lists every channel (id, name, logo) but carries programme data only for channels with an epgOverride. Point the service at a real guide instead:

"epgSourceUrl": "https://example.com/uk-guide.xml.gz"

tunlx fetches the document (gzip supported), caches it for a few hours, and matches programmes to channels by epgChannelId against the document's channel ids. The same data feeds get_short_epg and get_simple_data_table, so player now/next rows fill in too. Wizard-created channels use canonical iptv-org ids (e.g. BBCOne.uk) as their epgChannelId, so any XMLTV source following that convention — such as a self-hosted iptv-org/epg grab — lines up without extra mapping. Guides with display-name-style ids (e.g. BBC.One.HD.uk from epgshare01) are matched too: when an exact id lookup misses, tunlx falls back to a normalized comparison that ignores punctuation, case, and HD/regional markers. The regional wizard picks a recommended public guide for the chosen country automatically unless you supply your own. epgOverride still wins per channel.

Self-healing streams

Public catalog streams die. A service with self-healing enabled probes every enabled live channel on a schedule and, when the primary URL stops answering, swaps in the best working alternate — first from the channel's backupStreamUrls, then from fresh iptv-org catalog streams for the same iptvOrgChannelId. The dead URL is demoted to the back of the backup list so it can win again once the origin recovers.

"selfHeal": {
  "enabled": true,
  "intervalMinutes": 360,
  "disableAfter": 0
}
Field Purpose
enabled Turns the scheduled passes on.
intervalMinutes Time between passes (minimum 15, default 360).
disableAfter Disable a channel after N passes with no working alternate. 0 (default) never disables — the channel keeps its URL and recovers on its own.

Probes follow the service's route/sourceIP, so a VPN-bound service is checked through the VPN it actually plays through. Swaps are hot: the next playback request uses the new URL, no restart. Run a pass on demand with POST /xtreme-service/self-heal?proxy=NAME, and read the last pass report with GET on the same URL.

HLS remux to MPEG-TS

Some IPTV clients only handle MPEG-TS reliably. Enable:

"remuxHlsStreams": true

and tunlx will spawn a per-request ffmpeg that converts .m3u8 and .mp4 sources into MPEG-TS. HEVC streams get -bsf:v hevc_mp4toannexb, others get h264_mp4toannexb. Streams that already end in .ts bypass ffmpeg entirely.

ffmpeg in the official image

The official Docker image ships with ffmpeg preinstalled. On bare metal, install ffmpeg and keep it on PATH.

Egress

Like standard proxies, Xtream services have their own route. See Inbound & Outbound for global topology, and WireGuard / VPN for per-service VPN binding.