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?
- Feature Tour — what features exist
- Inbound & Outbound, WireGuard, Tailscale — networking guides
- Xtream Services, Composite, Standard Proxies — per-blueprint guides
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.

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

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 thetunlxweb interface.username: Username for login.password: Bcrypt-hashed password for login. Generate a hash usinghtpasswd -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 thetunlxdashboard for monitoring and configuration.verboseNonProxyLogging(optional): Enables verbose logging for background services (MediaFlow bridge, Xtream helpers, EPG refreshers) even whenTUNLX_DEBUGis not set. Use the Non-proxy logs toggle inside the dashboard's Activity & telemetry modal to flip this at runtime.enforceHttps(optional): Whentrue, automatically redirects HTTP requests to HTTPS using a 301 Moved Permanently response. This respectsX-Forwarded-Protoheaders 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 readssetup.dashboardWizardCompletedto decide whether to launch the wizard.
Networking¶
The networking object selects global inbound and outbound modes:
inbound— one ofpublic,tailscale,both. Controls which interfaces listeners bind to.outbound— one ofpublic,vpn,tsexit. Controls how egress leaves the host (per-proxyrouteoverrides this for individual proxies).failClosed(optional): Whentrue, 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.json → TUNLX_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:manualorprovider.manual: Use an existing WireGuard config file.provider: Use a VPN provider API (e.g. Mullvad) to fetch configurations.autoStartOnBoot: Whentrue, 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 onlymullvadis 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: Iftrue, 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 whichtunlxforwards 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, aliaspublic): use the system/default routing table.vpn: on Linux, bind sockets to the WireGuard interface (SO_BINDTODEVICE), defaultwg0. See WireGuard / VPN.tsexit: route this proxy's egress through the configured Tailscale exit node. See Tailscale Access.direct: bind outbound sockets tosourceIPso host policy routing can bypass VPN.sourceIP(required fordirect): IP address bound when thedirectroute is selected.strictEgress(optional): Boolean that overrides the globalnetworking.failClosedsetting for this specific proxy. Whentrue, 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): Whentrue, 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 whenepgAutoRefreshis enabled. No default value is applied.categoryPreferences(optional): Stores the enabled categories and their order forlive,vod, andseriescontent. Each entry contains aselectedarray of objects withid, optionalnameoverride, and optionalprefix. 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): Whentrue, send VLC-style request headers on Xtream paths. Often sidesteps WAF rules on Cloudflare-fronted upstreams.forceStreamReferer(optional): Preserve the originalRefererheader through to the upstream. Helpful for hotlink-protected sources.utlsFingerprint(optional): TLS ClientHello fingerprint. One ofchrome,firefox,safari,ios,edge,android,randomized. Replaces Go's stdlib TLS handshake to defeat JA3 / JA4 detection.redirectStreams(optional): Whentrue, 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 (0disabled, 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 whenredirectStreamsis 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.phpresponses 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
publicBaseURLwhen building redirect links so devices outside your LAN can connect. performEPGRefreshcan fetch EPG data without prompting for credentials.
Category Preferences¶
Category preferences keep the dashboard and API responses tidy:
categoryPreferences.live.selectedholds the enabled Live TV categories in display order.categoryPreferences.vod.selectedandcategoryPreferences.series.selectedmirror 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:
- Validates that Xtream credentials are present.
- Performs an initial refresh at startup (if none recorded).
- Fetches and caches XMLTV data on the configured interval.
- Updates
epgLastRefreshinconfig.jsonfor visibility.
Note on EPG caching: To reduce memory usage and ensure only relevant data is retained,
tunlxstrictly 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, orxtreme-service). Effectively ignored if a proxy with the specifiednameexists, as the system prioritizes name-based resolution. Defaults tostandardif 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 anyplayer_api.phpaction (acts as a wildcard for allplayer_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: Matchesget.phpplaylist requests. (Note: You must configure this asplaylist:getorplaylist. Configuringget.phpdirectly 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_apiaction acts as a wildcard for allplayer_api:*actions. However, there is nostreamwildcard. If you want to capture all streaming activity, you must specifystream:live,stream:vod, andstream:seriesindividually.
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 Xtreammessagefield 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 ownprefixorname.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¶
- Define at least one standard proxy with a working Xtream upstream.
- 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.
- Supply
xtreamUsername/xtreamPasswordif you want to present a custom login to clients. Otherwise, tunlx relays the username presented by the client to the source proxy. - Optionally set
publicBaseURLto issue playlists and redirect URLs that match your public hostname. - Restart tunlx or click Reload Config in the dashboard. The composite appears in the proxy table with a
Compositebadge 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
categoryPreferencesorcategories, depending on context, and shows the Last Updated timestamp pulled fromupdatedAtmetadata. - 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
epgAutoRefreshis 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). Supportssystem(aliaspublic),vpn,tsexit, ordirect, identical to standard proxies — see the Proxy Settingsroutefield above for the full behaviour.sourceIP(required fordirect): IP address bound when thedirectroute is selected.strictEgress(optional): Boolean that overrides the globalnetworking.failClosedsetting for this specific service. Whentrue, 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 toliveif omitted.order(optional): Explicit ordering index for the group.channels: Array ofXtremeServiceChannelobjects: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): Whentrue, loops the stream (useful for placeholder videos).epgOverride(optional): Object withtitleanddescriptionto 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): Whentrue, tunlx spawns a per-requestffmpegprocess to remux.m3u8or.mp4sources into MPEG-TS. It automatically uses-bsf:v hevc_mp4toannexbfor HEVC streams orh264_mp4toannexbotherwise. Streams that already end in.tsbypassffmpeg.
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 --xtremeWizardto launch an interactive wizard that creates an Xtream service backed by iptv-org categories and demo users. The wizard safely updatesconfig.jsonand can replace existing services after confirmation.
Command Line Arguments¶
Alternatively, you can use command line arguments to override or set certain configurations.
Example Command:
Command Line Options¶
-configFile: Specify the path to theconfig.jsonfile. If not provided,tunlxwill look for the default configuration in the current directory.
Environment Variables¶
TUNLX_DEBUG: Set totrueto 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 insessionSecretwithout editing the JSON file.TUNLX_WG_IFACE: WireGuard interface name to use whenrouteisvpn(default:wg0).TUNLX_WG_AUTOSTART: Set totrue(or1,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 whenmediaFlowURLis missing in config.API_PASSWORD(primary) orMEDIAFLOW_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.