Skip to content

Configuration Reference

Every field tunlx accepts in config.json, the canonical defaults, and a note on how each one is used at runtime.

Looking for a tour, not a reference?

Configuration File (config.json)

The primary method of configuring tunlx is through the config.json file. If this file is not present when you start tunlx, a default configuration will be created for you. You can then modify it according to your needs.

In Advanced mode you can edit the same file from the dashboard, with JSON validation before saving.

The in-dashboard configuration editor

There is also a read-only view of the effective running configuration.

Read-only configuration JSON

Example config.json File

{
  "webCredentials": {
    "username": "admin",
    "password": "REPLACE_WITH_BCRYPT_HASH"
  },
  "sessionSecret": "REPLACE_WITH_YOUR_OWN_RANDOM_SECRET",
  "dashboardPort": "6060",
  "verboseNonProxyLogging": true,
  "enforceHttps": true,
  "vpn": {
    "mode": "provider",
    "autoStartOnBoot": true,
    "provider": {
      "name": "mullvad",
      "mullvad": {
        "accountNumber": "1234567890123456"
      }
    }
  },
  "proxies": [
    {
      "name": "exampleProxy1",
      "targetServer": "http://example.com",
      "thisServerHost": "0.0.0.0",
      "thisServerPort": "8080",
      "publicBaseURL": "https://streams.example.com",
      "route": "system",
      "sourceIP": "",
      "mediaFlowEnabled": true,
      "mediaFlowURL": "http://mediaflow:8800",
      "xtreamUsername": "demo-user",
      "xtreamPassword": "demo-pass",
      "epgAutoRefresh": true,
      "epgRefreshIntervalHours": 12,
      "categoryPreferences": {
        "live": {
          "selected": [
            { "id": "1", "name": "Sports", "prefix": "[Live] " }
          ]
        }
      },
      "verboseLogging": false
    }
  ],
  "compositeProxies": [
    {
      "name": "favorites",
      "description": "Aggregate multiple sources",
      "welcomeMessage": "Welcome to favorites",
      "thisServerHost": "0.0.0.0",
      "thisServerPort": "18000",
      "publicBaseURL": "https://favorites.example.com",
      "verboseLogging": true,
      "xtreamUsername": "combo-user",
      "xtreamPassword": "combo-pass",
      "categoryPrefix": "[Fav] ",
      "categories": {
        "live": [
          { "id": "1", "sourceProxy": "exampleProxy1" }
        ]
      }
    }
  ]
}

Global Settings

  • webCredentials: Defines the username and password for accessing the tunlx web interface.
  • username: Username for login.
  • password: Bcrypt-hashed password for login. Generate a hash using htpasswd -nbB <user> <pass>.
  • sessionSecret (recommended): A persistent 32-byte key used to encrypt and authenticate dashboard sessions. Provide the value as base64, hex, or a 32-character ASCII string (e.g., openssl rand -base64 32). When omitted, tunlx generates a random key at startup and existing sessions are invalidated on restart.

    Security Warning: Do not copy the widely published sample key 5CmeXB96... into your config. The application rejects it as insecure and falls back to an ephemeral key.

  • dashboardPort: The port used to access the tunlx dashboard for monitoring and configuration.
  • verboseNonProxyLogging (optional): Enables verbose logging for background services (MediaFlow bridge, Xtream helpers, EPG refreshers) even when TUNLX_DEBUG is not set. Use the Non-proxy logs toggle inside the dashboard's Activity & telemetry modal to flip this at runtime.
  • enforceHttps (optional): When true, automatically redirects HTTP requests to HTTPS using a 301 Moved Permanently response. This respects X-Forwarded-Proto headers when running behind a reverse proxy.
  • verboseUserActivityLogging (optional): Enables detailed logging of user activity events, including API calls and stream requests. Use the User activity logs toggle inside the dashboard's Activity & telemetry modal to flip this at runtime.
  • userActivityPolicies (optional): An array of rules that define which user API requests should be captured and logged. See User Activity Policies below.
  • vpn (optional): Global WireGuard configuration for provider integration and auto-start. See VPN Configuration below.
  • networking (optional): Global inbound/outbound mode selectors. See Networking below.
  • tailscale (optional): Embedded Tailscale node configuration. See Tailscale below.
  • setup (optional): First-run onboarding state. The dashboard reads setup.dashboardWizardCompleted to decide whether to launch the wizard.

Networking

The networking object selects global inbound and outbound modes:

{
  "networking": {
    "inbound": "public",
    "outbound": "vpn",
    "failClosed": false
  }
}
  • inbound — one of public, tailscale, both. Controls which interfaces listeners bind to.
  • outbound — one of public, vpn, tsexit. Controls how egress leaves the host (per-proxy route overrides this for individual proxies).
  • failClosed (optional): When true, makes proxies that request VPN or tsexit egress return a 503 error if the egress is unavailable, instead of silently failing open to the public route. See Networking.

Changing inbound triggers an in-place process restart so listeners can re-bind. See the Inbound & Outbound Modes guide.

Tailscale

The tailscale object configures the embedded tsnet Tailscale node:

{
  "tailscale": {
    "enabled": false,
    "hostname": "tunlx",
    "stateDir": "/app/data/tailscale-state",
    "ephemeral": false,
    "exitNodeID": "",
    "exitNodeHostname": "",
    "exitNodeAllowLAN": false
  }
}

Precedence is config.jsonTUNLX_TS_* env vars → defaults (see tailnet_config.go). See the Tailscale Access guide.

VPN Configuration

The vpn object configures WireGuard integration. It allows tunlx to manage the VPN connection automatically.

  • mode: manual or provider.
  • manual: Use an existing WireGuard config file.
  • provider: Use a VPN provider API (e.g. Mullvad) to fetch configurations.
  • autoStartOnBoot: When true, enables the systemd service for the WireGuard interface (Linux only).
  • manual:
  • configPath: Path to the WireGuard configuration file (e.g. /etc/wireguard/wg0.conf).
  • provider:
  • name: Provider name (currently only mullvad is supported).
  • refreshIntervalMinutes (optional): Interval in minutes to refresh provider data (default: 15).
  • mullvad:
    • accountNumber: Mullvad account number.
    • country, city, hostname: Optional filters for server selection.
    • ownedOnly: If true, restricts selection to Mullvad-owned servers.
    • cliBinary (optional): Path to the Mullvad CLI binary if not in system PATH.

Proxy Settings (ProxyConfig)

Each entry under proxies defines a standalone upstream.

  • name: A unique identifier for the proxy.
  • targetServer: The upstream Xtream/HTTP endpoint to which tunlx forwards requests.
  • thisServerHost / thisServerPort: Where the proxy listens locally.
  • publicBaseURL (optional): Externally reachable base URL. When populated, generated playlists, redirect URLs, and the web player prefer this address so remote clients connect back through the correct hostname/port. Invalid values fall back to the local host/port.
  • route: Routing policy for upstream connections. Matching is case-insensitive and surrounding whitespace is trimmed; the stored value is normalized to lowercase on save. One of:
  • system (default, alias public): use the system/default routing table.
  • vpn: on Linux, bind sockets to the WireGuard interface (SO_BINDTODEVICE), default wg0. See WireGuard / VPN.
  • tsexit: route this proxy's egress through the configured Tailscale exit node. See Tailscale Access.
  • direct: bind outbound sockets to sourceIP so host policy routing can bypass VPN.
  • sourceIP (required for direct): IP address bound when the direct route is selected.
  • strictEgress (optional): Boolean that overrides the global networking.failClosed setting for this specific proxy. When true, prevents silent IP leaks when the underlying interface drops by forcing a 503 error.
  • mediaFlowEnabled / mediaFlowURL: Enable MediaFlow Proxy integration and define its base URL. See MediaFlow Proxy Integration below.
  • xtreamUsername / xtreamPassword (optional): Stored Xtream credentials used automatically by the dashboard player, playlist builders, and EPG fetchers. These values are also used as fallbacks when API calls arrive without credentials.
  • epgAutoRefresh (optional): When true, tunlx spawns a background worker that refreshes the proxy’s EPG cache on a schedule. Requires Xtream credentials.
  • epgRefreshIntervalHours: Interval (1–72 hours) between automatic EPG refreshes. Mandatory when epgAutoRefresh is enabled. No default value is applied.
  • categoryPreferences (optional): Stores the enabled categories and their order for live, vod, and series content. Each entry contains a selected array of objects with id, optional name override, and optional prefix. Preferences can be edited from the dashboard Category Manager.
  • verboseLogging (optional): Emits per-proxy debug logs without enabling global debug mode.
  • upstreamUserAgent (optional): Override the User-Agent tunlx sends to the upstream. Useful when an origin gates on browser-like UAs.
  • normalizeUpstreamXtreamHeaders (optional): When true, send VLC-style request headers on Xtream paths. Often sidesteps WAF rules on Cloudflare-fronted upstreams.
  • forceStreamReferer (optional): Preserve the original Referer header through to the upstream. Helpful for hotlink-protected sources.
  • utlsFingerprint (optional): TLS ClientHello fingerprint. One of chrome, firefox, safari, ios, edge, android, randomized. Replaces Go's stdlib TLS handshake to defeat JA3 / JA4 detection.
  • redirectStreams (optional): When true, tunlx returns HTTP 302 to the upstream URL for /live/, /movie/, /series/, /hls/, and recognized stream extensions. The client connects directly — bypasses MediaFlow and per-proxy egress. Use when the upstream must see the client's IP.
  • streamBufferKB (optional): Read-ahead buffer size in kilobytes (0 disabled, otherwise 64–65536) inserted between the upstream and each streaming client. tunlx keeps draining the upstream while a viewer briefly stalls and smooths bursty upstream delivery, improving playback stability at the cost of that much memory per active stream. Configurable from the proxy form's Playback Buffering section in the dashboard. Not applied to playlist/API responses or when redirectStreams is enabled.

MediaFlow Proxy Integration

tunlx can integrate with MediaFlow Proxy, a specialized caching and optimisation proxy for IPTV and streaming media. When enabled, MediaFlow provides:

  • Intelligent caching to reduce load on origin servers
  • Optimised streaming with adaptive buffering
  • Better seeking and range request handling
  • Header preservation for authentication and session management

MediaFlow Configuration Example

{
  "proxies": [
    {
      "name": "iptv-proxy",
      "targetServer": "http://xtream-origin:8080",
      "thisServerHost": "0.0.0.0",
      "thisServerPort": "8080",
      "route": "system",
      "mediaFlowEnabled": true,
      "mediaFlowURL": "http://mediaflow:8800"
    }
  ]
}

How MediaFlow Routing Works

When mediaFlowEnabled is true, tunlx automatically routes these paths through MediaFlow:

  • /live/* - Live TV streams (Xtream Codes format)
  • /movie/* - VOD movies
  • /series/* - TV series episodes
  • /hls/* - HLS playlists

MediaFlow will handle the request using the appropriate endpoint: - .m3u8 playlists → MediaFlow /proxy/hls - .ts, .mp4, .mkv files → MediaFlow /proxy/stream

Example transformation:

Client request: http://your-tunlx:8080/live/user/pass/1234.ts
tunlx forwards to: http://mediaflow:8800/proxy/stream?url=http://xtream-origin:8080/live/user/pass/1234.ts

All other paths (API endpoints, authentication, etc.) continue to route directly to the target server.

Setting Up MediaFlow with Docker

To use MediaFlow with tunlx, run MediaFlow in a Docker container:

docker run -d \
  --name mediaflow \
  --restart unless-stopped \
  -p 8800:8800 \
  mhdzumair/mediaflow-proxy:latest

If using Docker Compose with tunlx, add MediaFlow to your compose file:

services:
  tunlx:
    # ... your tunlx config

  mediaflow:
    image: mhdzumair/mediaflow-proxy:latest
    container_name: mediaflow
    restart: unless-stopped
    ports:
      - "8800:8800"

Then update your tunlx config.json to reference http://mediaflow:8800.

Xtream Credentials and Player Features

When xtreamUsername and xtreamPassword are stored in the proxy or composite configuration:

  • The dashboard player auto-fills the credentials for playlist/API calls.
  • /xtreme/player_api.php responses mask credentials in logs but reuse stored values if the client omits them.
  • The built-in player exposes Proxy and Direct playback URLs simultaneously. It prefers publicBaseURL when building redirect links so devices outside your LAN can connect.
  • performEPGRefresh can fetch EPG data without prompting for credentials.

Category Preferences

Category preferences keep the dashboard and API responses tidy:

  • categoryPreferences.live.selected holds the enabled Live TV categories in display order.
  • categoryPreferences.vod.selected and categoryPreferences.series.selected mirror the structure for Movies and Series.
  • Each object supports:
  • id: Upstream category identifier (required).
  • name: Optional friendly label that overrides the provider name.
  • prefix: Optional prefix applied before the upstream name.

The dashboard’s Category Manager saves changes back to config.json. You can seed defaults in the file so fresh installations expose your preferred structure immediately.

EPG Automation

Enable epgAutoRefresh and set epgRefreshIntervalHours (1–72) to let tunlx schedule background EPG refreshes. The worker:

  1. Validates that Xtream credentials are present.
  2. Performs an initial refresh at startup (if none recorded).
  3. Fetches and caches XMLTV data on the configured interval.
  4. Updates epgLastRefresh in config.json for visibility.

Note on EPG caching: To reduce memory usage and ensure only relevant data is retained, tunlx strictly filters out programs that are older than 24 hours in the past or further than 72 hours in the future.

If auto-refresh is disabled, the dashboard still allows on-demand refreshes via the EPG controls in the Xtream player.

User Activity Policies

User Activity Policies allow you to audit specific user behaviour by defining rules that capture API requests. When verboseUserActivityLogging is enabled, any request matching a policy is recorded in the activity log.

Each policy object contains:

  • proxy: The name of the proxy to monitor.
  • proxyType (optional): The type of proxy (standard, composite, or xtreme-service). Effectively ignored if a proxy with the specified name exists, as the system prioritizes name-based resolution. Defaults to standard if no matching proxy is found and the field is omitted.
  • username: The Xtream username to track (case-insensitive). Use * (wildcard) to match all users.
  • actions: An array of API actions to capture (case-insensitive). Supported values include:
  • *: Matches any API call.
  • player_api: Matches any player_api.php action (acts as a wildcard for all player_api:* actions).
  • player_api:account: Matches account/login checks.
  • player_api:default: Matches Player API requests that have no explicit action parameter (typically fetching account/server status).
  • player_api:get_live_streams: Matches live stream list requests.
  • player_api:get_vod_streams: Matches VOD stream list requests.
  • player_api:get_series: Matches series list requests.
  • player_api:get_live_categories: Matches live category requests.
  • player_api:get_vod_categories: Matches VOD category requests.
  • player_api:get_series_categories: Matches series category requests.
  • player_api:get_short_epg: Matches EPG requests.
  • player_api:get_simple_data_table: Matches EPG table requests.
  • player_api:other: Matches other/unknown player API actions.
  • playlist:get: Matches get.php playlist requests. (Note: You must configure this as playlist:get or playlist. Configuring get.php directly is invalid due to internal action normalization).
  • stream:live: Matches live stream playback requests.
  • stream:vod: Matches VOD playback requests.
  • stream:series: Matches series playback requests.

Note on wildcards: The player_api action acts as a wildcard for all player_api:* actions. However, there is no stream wildcard. If you want to capture all streaming activity, you must specify stream:live, stream:vod, and stream:series individually.

User Activity Policy Example

{
  "verboseUserActivityLogging": true,
  "userActivityPolicies": [
    {
      "proxy": "exampleProxy1",
      "username": "*",
      "actions": ["player_api:account", "stream:live"]
    },
    {
      "proxy": "favorites",
      "proxyType": "composite",
      "username": "suspicious_user",
      "actions": ["*"]
    }
  ]
}

Composite Proxies (CompositeProxyConfig)

Composite proxies expose a unified Xtream endpoint that aggregates categories from one or more standard proxies.

Key fields:

  • name: Unique composite identifier. Clients connect to /composite/{name} endpoints.
  • description / welcomeMessage (optional): Shown on the dashboard and returned as the Xtream message field for player logins.
  • thisServerHost / thisServerPort: Listen host/port for the composite service. Leave blank to inherit the main server defaults.
  • publicBaseURL (optional): External base URL used in playlists and redirect URLs, mirroring the behaviour of the standard proxy field.
  • verboseLogging (optional): Enables debug logging scoped to this composite only.
  • xtreamUsername / xtreamPassword (optional): Credentials tunlx advertises to composite clients and uses when collecting streams from underlying proxies.
  • categoryPrefix (optional): Global prefix prepended to every category name the composite publishes. Individual selections can override it with their own prefix or name.
  • categories: Map keyed by content type (live, vod, series). Each value is an array of selections with:
  • id: Upstream category ID to request.
  • sourceProxy: Name of the source proxy hosting that category.
  • name (optional): Override label.
  • prefix (optional): Extra prefix applied before the name.

Setting Up Composite Proxies

  1. Define at least one standard proxy with a working Xtream upstream.
  2. Create a composite entry listing the categories you want to expose and which proxy they come from. You can mix categories from multiple proxies in a single composite.
  3. Supply xtreamUsername/xtreamPassword if you want to present a custom login to clients. Otherwise, tunlx relays the username presented by the client to the source proxy.
  4. Optionally set publicBaseURL to issue playlists and redirect URLs that match your public hostname.
  5. Restart tunlx or click Reload Config in the dashboard. The composite appears in the proxy table with a Composite badge and can be opened in the Xtream player just like a normal proxy.

Managing Category Preferences

Category selections live directly in config.json, but day-to-day management is handled through the dashboard:

  • Open a proxy’s Actions → Manage Categories to launch the Category Manager modal.
  • Choose the content type (Live, Movies, Series). Composite proxies also let you filter by source proxy before editing.
  • Use the Available/Enabled lists to drag-and-drop or double-click categories between columns. The counts update in real time.
  • Apply a Global Prefix to prepend text (e.g., [US]) to every enabled category at once. Individual overrides remain untouched.
  • Select a category to edit its prefix and custom display name. The preview shows the final label.
  • Click Save Changes to persist the new order and labels back to config.json.

Dashboard Category Manager & EPG Automation Features

The Xtream player modal provides tooling that matches the configuration fields described above:

  • Category Manager: Accessible from each proxy/composite row. It writes back to categoryPreferences or categories, depending on context, and shows the Last Updated timestamp pulled from updatedAt metadata.
  • EPG Timeline: The EPG button in the player toggles a timeline view for the currently selected category. Auto-refresh keeps programme data up to date when epgAutoRefresh is enabled.
  • On-demand Refresh: Even without auto-refresh, opening the timeline fetches EPG data for visible channels and caches it temporarily.
  • Status Badges: Proxies with EPG auto-refresh enabled display an EPG Auto badge in the dashboard list so you can confirm scheduling at a glance.

Xtream Services (XtremeServiceConfig)

Xtream Services expose a full Xtream Codes-compatible API backed by groups, channels, and users you define directly in config.json. They are ideal when you need to curate a custom lineup or resell access without relying on an upstream Xtream provider. You can instruct tunlx to auto-populate channel groups from the public iptv-org catalog, or continue managing channels manually. Use the --xtremeWizard command or the dashboard import modal to walk through the workflow. Key configuration fields:

  • name / description / welcomeMessage: Identify the service and customise the login banner presented to clients.
  • thisServerHost / thisServerPort: Control where the service listens locally. Xtream Services advertise this host/port combination directly unless the host is a wildcard, in which case tunlx falls back to the incoming request host.
  • route: Routing policy for upstream connections (e.g., when proxying streams). Supports system (alias public), vpn, tsexit, or direct, identical to standard proxies — see the Proxy Settings route field above for the full behaviour.
  • sourceIP (required for direct): IP address bound when the direct route is selected.
  • strictEgress (optional): Boolean that overrides the global networking.failClosed setting for this specific service. When true, prevents silent IP leaks when the underlying interface drops by forcing a 503 error.
  • mediaFlowEnabled / mediaFlowURL: Enable MediaFlow Proxy integration for streams served by this service. See MediaFlow Proxy Integration for details.
  • groups: Array of group objects, each containing:
  • id: Unique identifier for the group.
  • name: Display name for the group (category).
  • description (optional): Internal description for the group.
  • type (optional): Content type (live, vod, series). Defaults to live if omitted.
  • order (optional): Explicit ordering index for the group.
  • channels: Array of XtremeServiceChannel objects:
    • id: Unique channel identifier.
    • name: Display name.
    • streamUrl: URL of the stream source.
    • logo (optional): URL to the channel logo.
    • epgChannelId (optional): XMLTV ID for EPG matching.
    • country (optional): 2-letter country code (e.g., US, GB).
    • contentType (optional): Overrides the group's content type (live, vod, series).
    • order (optional): Explicit ordering index for the channel.
    • enabled (optional): Boolean to enable/disable the channel (default: true).
    • loop (optional): When true, loops the stream (useful for placeholder videos).
    • epgOverride (optional): Object with title and description to force specific EPG data.
  • iptvOrgImports (optional): Array of templates that dynamically build groups from the iptv-org catalog. Each entry requires:
  • name: Display name for the generated group.
  • query (optional): Case-insensitive text filter matched against channel names, alternate names, and catalog IDs (e.g., "bbc").
  • countries (optional): Array of country codes (e.g., ["US", "GB"]) to filter channels.
  • categories (optional): Array of categories (e.g., ["news", "sports"]) to filter channels.
  • limit (optional): Maximum number of channels to import. Defaults to 200 if omitted or set to 0.
  • includeNsfw (optional): Whether to include adult content (default: false).
  • description (optional): Internal description for the import rule.
  • users: Array of subscribers. Each user object contains:
  • username: Login username.
  • password: Bcrypt-hashed password.
  • expiryDate (optional): ISO 8601 timestamp for account expiration.
  • maxConnections (optional): Limit on concurrent streams (default: unlimited).
  • active: Boolean to enable/disable the user.
  • notes (optional): Internal notes or description for the user.
  • createdAt (read-only): Timestamp when the user was created.
  • verboseLogging (optional): Emit debug logs scoped to this service without enabling global debug mode.
  • remuxHlsStreams (optional): When true, tunlx spawns a per-request ffmpeg process to remux .m3u8 or .mp4 sources into MPEG-TS. It automatically uses -bsf:v hevc_mp4toannexb for HEVC streams or h264_mp4toannexb otherwise. Streams that already end in .ts bypass ffmpeg.

The official Docker images ship with ffmpeg already installed so the remux toggle works out of the box. Bare-metal deployments should install ffmpeg and keep it available in the system PATH.

Tip: Run ./tunlx --xtremeWizard to launch an interactive wizard that creates an Xtream service backed by iptv-org categories and demo users. The wizard safely updates config.json and can replace existing services after confirmation.

Command Line Arguments

Alternatively, you can use command line arguments to override or set certain configurations.

Example Command:

./tunlx -configFile=config.json

Command Line Options

  • -configFile: Specify the path to the config.json file. If not provided, tunlx will look for the default configuration in the current directory.

Environment Variables

  • TUNLX_DEBUG: Set to true to enable verbose debug logging.
  • TUNLX_DASHBOARD_PORT: Override the dashboard port exposed by tunlx (default: 6060).
  • TUNLX_SESSION_SECRET: Supply the same 32-byte value you would place in sessionSecret without editing the JSON file.
  • TUNLX_WG_IFACE: WireGuard interface name to use when route is vpn (default: wg0).
  • TUNLX_WG_AUTOSTART: Set to true (or 1, yes, on) to enable systemd auto-start for the WireGuard interface (Linux only).
  • TUNLX_WG_MARK: Firewall mark (integer) to set on WireGuard sockets (SO_MARK). Useful for policy routing.
  • TUNLX_WG_CONF: Path to the WireGuard configuration file (default: /etc/wireguard/<iface>.conf).
  • TUNLX_MEDIAFLOW_BASE_URL: Default MediaFlow base URL to use when mediaFlowURL is missing in config.
  • API_PASSWORD (primary) or MEDIAFLOW_API_PASSWORD (fallback): Default API password to use for MediaFlow requests if not specified in the URL.

Additional environment variables can override configuration settings, but none are required by default.

Dashboard Access

Once tunlx is running, you can access the dashboard via the configured dashboardPort. By default, it is accessible at:

http://<thisServerHost>:<dashboardPort>


For a complete starter config, use examples/config.example.json in the repository's examples/ directory.