Skip to content

Troubleshooting

First-response checks for the most common operational issues.

Quick diagnostics

# tunlx metrics endpoint (also doubles as the container health check)
curl -i http://localhost:6060/metrics

# What does egress look like right now?
curl -s http://localhost:6060/outbound-ip
curl -s http://localhost:6060/outbound-ip/non-vpn

# Tailscale status (if enabled)
curl -s http://localhost:6060/tailnet/status

# Container logs
docker logs --tail=200 tunlx

# Compose service state
docker compose ps

Symptom checklist

Symptom Likely cause Action
Dashboard unreachable Wrong bind IP/port, firewall, container not running Verify container status, host firewall, and dashboardPort
Streams fail in built-in player Upstream credential mismatch or blocked route Recheck Xtream credentials and route mode
VPN-mode streams fail WireGuard interface or rules unhealthy wg show, validate interface, keys, and routing marks
EPG not updating Missing Xtream creds or epgAutoRefresh off Set credentials and enable epgAutoRefresh
Remote clients can't play Missing or wrong publicBaseURL Set public URL to a reachable hostname/port
Tailnet-only mode unreachable tsnet not logged in / state dir not persisted Check /tailnet/status, confirm stateDir, re-auth if needed
Stream tester reports all fail Route mode points to a tunnel that's down Switch the proxy to system, re-test, then bring the tunnel back up
Player works locally, not remote Internal hostname leaks into redirects Set publicBaseURL; tunlx prefers it for redirect/playlist URLs
route: vpn but egress is host Container missing NET_ADMIN / NET_RAW / /dev/net/tun Add capabilities + tun device, restart

Route verification

When using route: vpn, route: tsexit, or route: direct:

  1. Confirm host networking and required capabilities are present.
  2. Validate the relevant interface / address on the host.
  3. Test one known-good stream before broad rollout.

For VPN specifically:

# Inside the container or host
wg show

# Verify egress IP differs from host
docker exec tunlx curl -s https://api.ipify.org

For Tailscale exit-node egress:

curl -s http://localhost:6060/tailnet/status | jq
curl -s http://localhost:6060/tailnet/peers | jq

Stream format problems

If playback fails for .ts or .m3u8 channels:

  • Test the same channel in both Proxy and Direct URL modes in the built-in player.
  • Confirm MediaFlow is reachable when enabled.
  • Inspect upstream responses for HTML / error payloads where video is expected.
  • For Xtream services with .m3u8 or .mp4 sources, try remuxHlsStreams: true so tunlx remuxes to MPEG-TS.

Anti-block sanity checks

If a freshly-added upstream returns 403 / 451 / weird HTML:

  • Set upstreamUserAgent to a normal browser UA.
  • Try normalizeUpstreamXtreamHeaders: true for VLC-style headers.
  • Enable forceStreamReferer: true if the upstream gates on Referer.
  • Set utlsFingerprint to chrome (or firefox, ios, safari, edge, android, randomized) for Cloudflare-fronted origins.
  • Last resort: enable redirectStreams: true so the client connects to the upstream directly.

Safe recovery steps

  1. Switch the affected proxy's route back to system.
  2. Disable optional acceleration features (MediaFlow, remux, redirect).
  3. Verify baseline playback.
  4. Re-enable features one at a time, testing after each.

Logs and debugging

  • TUNLX_DEBUG=true for verbose startup logging.
  • verboseLogging: true on a specific proxy/service for scoped debug.
  • verboseNonProxyLogging: true for background workers (EPG, MediaFlow bridge, Xtream helpers).
  • verboseUserActivityLogging: true plus a matching user activity policy for per-request audit trails.

Toggle the last two at runtime from Activity & Telemetry in the dashboard — no restart needed.

Configuration sanity

  • examples/config.example.json is the canonical reference. Diff against it when a value isn't behaving as expected.
  • Generate your own sessionSecret. tunlx rejects the well-known sample key and falls back to an ephemeral key that breaks sessions on restart.
  • Bcrypt passwords with htpasswd -nbB user pass. Plaintext passwords are rejected.

Still stuck

  • Capture recent logs with timestamps (docker logs --since 30m tunlx).
  • Export a sanitized config.json (strip secrets, account numbers, WireGuard keys, session secret, Xtream passwords).
  • Open an issue: github.com/eyupio/tunlx/issues.