Skip to content

Environment variables

Reference list of every environment variable read by the Phlix Media Server, its default, and a one-line description. Each entry links back to the file that consumes it.

Container & bootstrap

VariableDefaultDescription
PHLIX_CONTAINER_COMPILEunsetWhen truthy (1, true, yes, on) enables PHP-DI's compiled-container cache in var/cache/container/. Disabled by default for dev parity. See Phlix\Common\Container\ContainerFactory.

Events

VariableDefaultDescription
PHLIX_DEBUG_EVENTS0When truthy (1, true, yes, on) it (1) wraps the PSR-14 dispatcher in Tukio's DebugEventDispatcher, which logs every dispatched event class at debug level on the events channel, and (2) enables the events log handler so those records are actually written to .logs/events.log. When off, events.log stays empty. Useful for tracing plugin behaviour; leave off in production. See Phlix\Common\Events\EventDispatcherFactory, config/logger.php, and docs/dev/event-reference.md.

Plugins

VariableDefaultDescription
PHLIX_PLUGINS_ALLOW_HTTP0When truthy (1, true, yes, on) lets the plugin loader accept plain http:// source URLs. Default off — HTTPS or file:// only. See Phlix\Plugins\Installer\HttpInstaller.
PHLIX_PLUGINS_REQUIRE_SIGNATURE0When truthy, the plugin loader refuses to install unsigned plugins and refuses signatures missing from the trusted-key allowlist. Default off, which means unsigned plugins install with a warning on the plugins log channel. See Phlix\Plugins\Signature\SignatureVerifier.
PHLIX_PLUGINS_COMPOSER_TIMEOUT120Hard timeout (seconds) on the per-plugin composer install --no-dev subprocess. See Phlix\Plugins\Installer\ComposerRunner.
PHLIX_PLUGINS_CATALOG_REF(unset)Overrides the git ref the official catalog (detain/phlix-plugins) resolves to — a release tag or commit. Highest precedence: wins over the plugins.catalog.channel setting and over the built-in OFFICIAL_PINNED_REF default (precedence: env > setting > default). Use it to pin a newer catalog release or roll back without a code change. See Plugin Catalog → Release channel and Phlix\Plugins\Catalog\CatalogSourceResolver.
PHLIX_PLUGINS_ALLOW_UNVERIFIED0Default-deny override. When unset, the loader refuses to install a plugin whose source is remote and whose catalog entry carries no pinned artifact sha256, throwing PluginInstallException. When truthy (1, true, yes, on) the install proceeds and a warning is logged on the plugins channel. file:// and scheme-less sources are exempt — the gate never applies to them — and a source that is digest-pinned bypasses it regardless of this variable. See Phlix\Plugins\PluginLoader::assertVerifiedOrOverride().
PHLIX_GITHUB_TOKEN(unset)GitHub OAuth token seeded into the per-plugin COMPOSER_HOME/auth.json (mode 0600) so composer install --no-dev can reach private or rate-limited GitHub repositories. Checked first, then GITHUB_TOKEN, then GH_TOKEN. With none set the token-less path stays fully functional. See Phlix\Plugins\Installer\ComposerRunner::discoverGithubToken().
GITHUB_TOKEN(unset)Second-priority fallback for the plugin composer GitHub token. See PHLIX_GITHUB_TOKEN.
GH_TOKEN(unset)Third-priority fallback for the plugin composer GitHub token. See PHLIX_GITHUB_TOKEN.
PHLIX_ANIDB_CACHE_DIRsys_get_temp_dir()/phlix-plugin-anidbWritable directory outside the plugin tree where the AniDB plugin writes its title_index.json title-dump cache. The packaged systemd unit exports it as /var/cache/phlix/anidb and adds it to ReadWritePaths, because ProtectSystem=strict would otherwise block the write. Resolution order: constructor argument → the cache_dir plugin setting → this variable → sys_get_temp_dir(). Read by the AniDB plugin, not by the server itself.

Auth

VariableDefaultDescription
JWT_SECRETdefault-secret-change-meHMAC secret used to sign / verify JWT access and refresh tokens. The default is intentionally insecure so a missing env var fails closed in production deployments. Read by Phlix\Common\Container\Providers\AuthServicesProvider.
PHLIX_SIGNED_URL_SECRETderived from JWT_SECRETHMAC key for the signed media URLs that gate the binary/streaming endpoints (/media/{id}/stream, /hls/**, /dash/**, book/audiobook/photo bytes). When unset it is derived from JWT_SECRET via a domain-separated HMAC, so a leaked stream token can never be replayed as a JWT (and vice-versa). Set an explicit value to rotate stream tokens independently of JWTs. Read by Phlix\Auth\SignedUrl::fromEnv().
PHLIX_SIGNED_URL_TTL21600 (6 h)Lifetime, in seconds, of a minted signed media URL before it expires. Must be a positive integer. Read by Phlix\Auth\SignedUrl::fromEnv().

Auth rate limiting (SV-4.15)

The previously-unlimited auth surfaces (register, refresh, WebAuthn login start+finish, the public JWKS endpoint, and WS-connect on :8097) are rate-limited per surface. HTTP surfaces reply 429 Too Many Requests with a Retry-After header and body {"error":"Too Many Requests","code":"rate_limited"}; WS-connect rejects the handshake. login keeps its own IP-keyed DB-backed limiter (migration 074) and is not configured here. Read by config/server.phprate_limit and Phlix\Common\RateLimit\RateLimitProfiles.

Each surface's max (attempts) and window (seconds) are overridable by a pair of env vars named for the surface. <SURFACE>REGISTER, REFRESH, WEBAUTHN_START, WEBAUTHN_FINISH, JWKS, WS_CONNECT.

VariableDefaultDescription
RATE_LIMIT_REGISTER_MAX / _WINDOW5 / 600Registration attempts per window.
RATE_LIMIT_REFRESH_MAX / _WINDOW30 / 60Token-refresh attempts per window.
RATE_LIMIT_WEBAUTHN_START_MAX / _WINDOW10 / 60WebAuthn login-ceremony start attempts per window.
RATE_LIMIT_WEBAUTHN_FINISH_MAX / _WINDOW10 / 60WebAuthn login-ceremony finish attempts per window.
RATE_LIMIT_JWKS_MAX / _WINDOW120 / 60Public JWKS (/.well-known/jwks.json) requests per window.
RATE_LIMIT_WS_CONNECT_MAX / _WINDOW30 / 60WebSocket (:8097) connection attempts per window.
TRUSTED_PROXIESloopback only (127.0.0.1, ::1)Comma-separated IP/CIDR list of the reverse-proxy hops in front of Phlix. Used to derive the real client IP from X-Forwarded-For/X-Real-IP for rate-limit keys and the DLNA IP allowlist. Must list every non-loopback proxy hop (nginx/HAProxy) — otherwise IP-keyed limits bucket every request under the proxy address (or trust a client-forged header), and a non-loopback proxy fronting DLNA makes every request appear to come from the proxy. The stock install fronts Phlix over loopback, so the default is correct. Read by Phlix\Common\Http\TrustedProxyResolver. See /advanced/reverse-proxy.

Register / refresh / WebAuthn use a shared DB-backed limiter (migration 085_rate_limit_buckets.sql) so the budget is truly global across all HTTP workers. JWKS and WS-connect use a worker-local in-memory limiter (JWKS is cache-frontable; the :8097 WS worker runs count=1, so per-worker equals global there). Apply migration 085 on deploy.

HLS / segment cache

VariableDefaultDescription
HLS_MIN_DISK_SPACE_BYTES524288000 (500 MiB)Free-space floor for the HLS segment-cache directory (config/server.phphls.min_disk_space_bytes). When free space on the segment-cache filesystem drops below this, the server sweeps the cache and returns 503 with Retry-After: 3 rather than failing an encode with ENOSPC.

Hub / Pairing (phlix-server)

VariableDefaultDescription
PHLIX_HUB_URLunsetBase URL of the Phlix Hub to pair with (e.g. https://hub.example.com). When set, the server initiates pairing automatically on startup if enrolled. See Phlix\Hub\HubClient and config/hub.php.
PHLIX_HUB_JWKS_URLunsetURL of the hub's JWKS endpoint for validating hub-issued JWTs. Typically set automatically during enrollment. See Phlix\Hub\HubJwtValidator and config/hub.php.
PHLIX_HUB_ENROLLMENT_TOKENunsetWhen set, overrides the enrollment token read from config/hub-enrollment.json. Mostly useful for automation / container orchestration. See Phlix\Hub\HubClient::loadEnrollment().
PHLIX_HUB_HEARTBEAT_INTERVAL60Interval in seconds between hub heartbeat calls. Must be between 30 and 3600. See Phlix\Hub\HubClient::startHeartbeatLoop() and config/hub.php.
PHLIX_SUBDOMAIN_AUTO_CLAIM1When truthy (1, true, yes, on) automatically claims a *.phlix.media subdomain from the hub after enrollment. See Phlix\Hub\SubdomainClient and config/hub.php.
PHLIX_TLS_ENABLED1When truthy enables TLS/HTTPS for the server's public hostname. Requires a subdomain to be allocated. See config/hub.php.
PHLIX_DOMAINunset (config/hub.php substitutes phlix.media for its own hub.domain)This server's public authority — a host, optionally with a port (media.example.com, media.example.com:8443). No scheme, no path, no trailing dot. scripts/install.sh --domain <domain> writes it to the env file the systemd unit reads. Two jobs: (1) the base domain for server subdomains (e.g. abc12345.phlix.media) that config/hub.php composes into hub.domain / hub.public_url; (2) the allowlist for deriving the OAuth2/OIDC redirect_uri — see below.

PHLIX_DOMAIN and external sign-in

/auth/oidc/authorize and /auth/github/authorize must send the provider an absolute redirect_uri. Phlix builds <scheme>://<Host><callback path> from the request only when the request's Host equals PHLIX_DOMAIN — the port is part of the comparison, with the scheme's default port (:443 https, :80 http) normalised away on both sides. Host is client-supplied, so an unvouched-for value could otherwise be turned into a redirect_uri pointing at an attacker's host.

It fails closed. If PHLIX_DOMAIN is unset or malformed, nothing is derived and the authorize endpoint answers 503 callback_url_not_configured — no Location, no cookie, no OAuth state row. A malformed value is treated as unconfigured, never as an allowlist that cannot match: https://media.example.com/, media.example.com/app, media.example.com:, media.example.com., media.example.com:99999, media.example.com:https and whitespace all mean "no derivation".

The escape hatch is a per-provider absolute redirect_uri setting, which takes priority and works with PHLIX_DOMAIN unset. Full setup, the misconfiguration response and when to prefer each option: Single Sign-On → Callback URLs and PHLIX_DOMAIN.

Hub / Server (phlix-hub)

These environment variables apply when running phlix-hub itself (not when the server connects to a hub).

HTTP worker (config/server.php)

VariableDefaultDescription
HUB_HOST0.0.0.0Bind address for the Workerman HTTP worker.
HUB_PORT8800TCP port the worker listens on.
HUB_WORKERS2Number of worker processes Workerman should fork.
HUB_WORKERMAN_LOG<repo>/.logs/workerman.logPath Workerman writes its master-log to. Directory must exist or be writable.

Database (config/database.php)

VariableDefaultDescription
HUB_DB_HOST127.0.0.1MySQL host the hub connects to.
HUB_DB_PORT3306MySQL port.
HUB_DB_USERphlix_hubMySQL username.
HUB_DB_PASSWORDphlix_hubMySQL password. Override in any non-dev env.
HUB_DB_NAMEphlix_hubDatabase name.

Auth (config/auth.php)

VariableDefaultDescription
HUB_JWT_SECRET(dev fallback)HMAC-SHA256 secret for issuing JWTs. Required in production — must be ≥32 bytes. Falls back to a random per-process secret in dev.
HUB_JWT_ACCESS_TTL3600Access-token lifetime in seconds (default 1 hour).
HUB_JWT_REFRESH_TTL604800Refresh-token lifetime in seconds (default 7 days).

When HUB_JWT_SECRET is unset, the hub generates a random secret at container-build time. Tokens issued with that secret are valid only for the lifetime of the current PHP process — restarting the worker invalidates every existing session. Always set this var explicitly in production.

Container caching

VariableDefaultDescription
PHLIX_HUB_CONTAINER_COMPILEunsetWhen truthy (1, true, yes, on), PHP-DI writes compiled definitions to var/cache/container/ for faster cold-start. Off for dev.

Hub / Arr Integration

Controls Radarr (movies) and Sonarr (series) connectivity for the Hub's media-request system. The hub uses these to push approved requests into the appropriate Arr instance. Both instances must be reachable from the Hub host and have API v3 enabled.

VariableDefaultDescription
HUB_RADARR_URLhttp://localhost:7878Base URL of the Radarr instance (API v3).
HUB_RADARR_API_KEYemptyRadarr API key. Generate in Radarr → Settings → General → Security → API Key.
HUB_RADARR_ENABLED0When truthy (1, true, yes, on) enables Radarr integration. When falsy, movie approvals fail with approve_failed.
HUB_SONARR_URLhttp://localhost:8989Base URL of the Sonarr instance (API v3).
HUB_SONARR_API_KEYemptySonarr API key. Generate in Sonarr → Settings → General → Security → API Key.
HUB_SONARR_ENABLED0When truthy (1, true, yes, on) enables Sonarr integration. When falsy, series approvals fail with approve_failed.

Tip: Both Arr instances must have at least one quality profile and root folder configured before requests can be approved. The hub uses the first available profile and root folder automatically.

See docs/hub/requests.md for the full media-request workflow.

Relay tunnel

VariableDefaultDescription
PHLIX_RELAY_ENABLED0When truthy (1, true, yes, on) enables the persistent relay tunnel to the hub. Requires the server to be enrolled. See Phlix\Hub\RelayConfig and config/relay.php.
PHLIX_RELAY_HUB_URLwss://hub.example.com/api/v1/servers/{id}/relayWebSocket URL of the hub relay endpoint. {id} is replaced with the server's UUID from enrollment. See Phlix\Hub\RelayConsumer and config/relay.php.
PHLIX_RELAY_HUB_WS_URLempty (derived from enrollment)Explicit hub server-tunnel WS endpoint (config key relay.hub_relay_ws_url). Highest-precedence override — when empty the URL is derived from the enrollment's hub_base_url at start time. The transport keys off the scheme: a ws:// URL is plaintext, a wss:// URL is TLS. If you set a wss:// URL here, also set PHLIX_RELAY_TLS=1 so the cert/verify vars apply. See Phlix\Hub\RelayConfig and config/relay.php.
PHLIX_RELAY_TLSfalseWhen truthy (1, true, yes, on) the derived relay scheme becomes wss:// and the tunnel connects with TLS. Default is false (plaintext ws://), mirroring the hub's HUB_RELAY_TLS default — the hub relay listener (:8802) is plaintext unless HUB_RELAY_TLS=true is set on the hub. A TLS relay deploy requires both PHLIX_RELAY_TLS=1 here and HUB_RELAY_TLS=true on the hub. Independent of the server's public HTTP TLS. Config key relay.relay_tls. See Phlix\Hub\RelayConfig and config/relay.php.
PHLIX_RELAY_TLS_VERIFYtrueWhether to verify the hub's presented relay TLS certificate. Default is secure (on). Set to 0/false to accept a self-signed hub relay cert (verify_peer=false + allow_self_signed=true, mirroring the hub's permissive relay server context). Production should use a CA-signed cert and leave verification on. Config key relay.relay_tls_verify. See Phlix\Hub\RelayConfig and config/relay.php.
PHLIX_RELAY_TLS_CAFILE/etc/ssl/certs/ca-certificates.crtCA bundle used to verify the hub's relay TLS certificate when PHLIX_RELAY_TLS_VERIFY is on. Config key relay.relay_tls_cafile. See Phlix\Hub\RelayConfig and config/relay.php.
PHLIX_RELAY_TUNNEL_HOSTNAMEemptyPublic hostname assigned to this server's relay tunnel (e.g. my-server.phlix.media). See Phlix\Hub\RelayConfig and config/relay.php.
PHLIX_RELAY_RECONNECT_DELAY5Seconds to wait before attempting to reconnect after the relay tunnel is disconnected. See Phlix\Hub\RelayConfig and config/relay.php.
PHLIX_RELAY_PING_INTERVAL30Seconds between keep-alive ping frames sent over the relay tunnel. See Phlix\Hub\RelayConfig and config/relay.php.
PHLIX_RELAY_PING_TIMEOUT10Seconds to wait for a pong response before considering the relay connection dead. See Phlix\Hub\RelayConfig and config/relay.php.

Port forwarding / remote access

VariableDefaultDescription
PHLIX_PORT_FORWARD_AUTO1When truthy (1, true, yes, on) enables automatic port forwarding via UPnP-IGD on startup. See Phlix\Network\PortForwardService and config/port-forward.php.
PHLIX_EXTERNAL_PORT32400Port to use for automatic port forwarding. Both external and internal ports use this value by default. See Phlix\Network\PortForwardService and config/port-forward.php.
PHLIX_EXTERNAL_HTTP_PORT8080External HTTP port for the web portal when accessed remotely. See config/port-forward.php.
PHLIX_EXTERNAL_HTTPS_PORT8443External HTTPS port for the web portal when accessed remotely. See config/port-forward.php.
PHLIX_UPNP_ENABLED1When truthy enables UPnP-IGD port mapping attempts. When falsy, only STUN-based external IP detection is used. See Phlix\Network\UpnpIgdClient and config/port-forward.php.
PHLIX_STUN_SERVERstun.l.google.comSTUN server hostname for discovering the server's public IP address. See Phlix\Network\StunClient and config/port-forward.php.
PHLIX_STUN_PORT19302STUN server port. See Phlix\Network\StunClient and config/port-forward.php.

The port-forwarding default does not match the port the server listens on

PHLIX_EXTERNAL_PORT defaults to 32400 and is used as both the external and the internal port of the UPnP/NAT-PMP mapping — the router is told to forward WAN 32400 to <server-lan-ip>:32400. phlix-server listens on 8096 (config/server.php server.port), so with both defaults left alone the mapping points at a port nothing is bound to and direct remote access will not work.

Set PHLIX_EXTERNAL_PORT to the port the server actually listens on:

bash
PHLIX_EXTERNAL_PORT=8096

The same value is what phlix portforward status advertises to the Hub as this server's hostname candidates, so getting it wrong makes those candidates unreachable too.

Server

VariableDefaultDescription
PHLIX_PUBLIC_URLunsetPublic URL used in Hub relay and DLNA announcements. Must be set if the server is behind a reverse proxy. See Phlix\Server\Core\Application.
PHLIX_LOG_LEVELinfoMinimum log level for application logs written to .logs/app.log. Valid values (in order of verbosity): debug, info, notice, warning, error, critical, alert, emergency. See config/logger.php.

PHLIX_HTTP_PORT does not exist — if you have it set, it is doing nothing

Earlier revisions of this page listed PHLIX_HTTP_PORT as the way to change the HTTP listen port. It was never implemented. The name appears nowhere in phlix-server — not in the current source and not in any commit in its history — so exporting it, or putting it in a .env file, has no effect whatsoever. The server is still listening on whatever config/server.php says.

There is no environment variable for the HTTP port. To change it:

  • edit server.port in config/server.php — the default is 8096; or
  • pass --http-port PORT to scripts/install.sh at install time, which writes that value into the config and into the generated HAProxy backend.

Both take effect on the next server restart.

Database

These are the production runtime connection parameters. config/database.php reads every one of them from the environment, each with a localhost default that targets a stock single-host install (the install.sh-managed phlix MySQL user on 127.0.0.1). A default install only needs to set DB_PASSWORD; override any of the others when your database is remote or renamed. See config/database.php.

VariableDefaultDescription
DB_HOST127.0.0.1MySQL host consumed by config/database.php connections.mysql.host.
DB_PORT3306MySQL port consumed by config/database.php connections.mysql.port.
DB_DATABASEphlixDatabase name consumed by config/database.php connections.mysql.database. Legacy alias: DB_NAME (used only when DB_DATABASE is unset).
DB_USERphlixDatabase username consumed by config/database.php connections.mysql.username. Legacy alias: DB_USERNAME (used only when DB_USER is unset).
DB_PASSWORDemptyDatabase password consumed by config/database.php connections.mysql.password via getenv('DB_PASSWORD'). Set this on every non-dev install.
DB_POOL_ENABLED1The per-worker coroutine connection pool is on by default (Stream Quality/ABR step S9): each coroutine leases its own connection so independent queries within a worker run in parallel instead of serialising on one shared socket. Set DB_POOL_ENABLED=0 (or false/no/off) to opt back into the single-connection mutex path. See config/database.php.
DB_POOL_SIZE8Per-worker connection-pool ceiling while DB_POOL_ENABLED is on (the default). The server-wide max is roughly (worker count × pool size); keep it under MySQL max_connections. See config/database.php.

Test overrides: phpunit.xml's <env> block overrides these same DB_* vars for the integration test suite (e.g. DB_DATABASE=phlix_test, DB_USER=root, plus APP_ENV=testing). Those values apply only when running the test suite — they are not the production defaults shown above.

PHLIX_DATABASE_* aliases

VariableDefaultDescription
PHLIX_DATABASE_HOST127.0.0.1MySQL host; maps to config/database.php connections.mysql.host.
PHLIX_DATABASE_PORT3306MySQL port; maps to config/database.php connections.mysql.port.
PHLIX_DATABASE_NAMEphlixDatabase name; maps to config/database.php connections.mysql.database.
PHLIX_DATABASE_USERphlixDatabase username; maps to config/database.php connections.mysql.username.
PHLIX_DATABASE_PASSWORDemptyDatabase password. Alias for the DB_PASSWORD env var consumed by config/database.php. Prefer setting DB_PASSWORD to avoid confusion.

Transcoding / Hardware acceleration

VariableDefaultDescription
PHLIX_HWACCELnonePreferred hardware acceleration. Valid values: nvidia, vaapi, videotoolbox, qsv, amf, v4l2, none. Overridden by config/ffmpeg.php hwaccel.vendor_priority. See config/ffmpeg.php.

Timezone

VariableDefaultDescription
TZsystem TZPHP date_default_timezone_set() value. Controls timestamps in logs and EPG data. Set to your local timezone (e.g., America/New_York, Europe/London).

The production database credentials live in config/database.php (which reads DB_PASSWORD from the environment via getenv('DB_PASSWORD')).

BSD-3-Clause