Install phlix-server on Kubernetes โ
TL;DR โ
phlix-server is a PHP 8.3+ media server with HLS streaming, WebSocket real-time sync, DLNA, and a Smarty web portal. This guide deploys it on Kubernetes via Helm in roughly 10 minutes.
Minimum requirements: Kubernetes 1.21+, Helm 3.8+, a default or named StorageClass, 2 CPU / 4 GB RAM per pod.
Quick one-liner:
helm repo add phlix https://charts.phlix.media && helm repo update
helm install phlix phlix/phlix \
--set config.database_password=SECRET \
--set config.secret_key=YOUR_KEY \
--set ingress.enabled=true \
--set ingress.hosts[0].host=phlix.example.comThen open https://phlix.example.com in your browser.
Screenshots TBD
This guide is text-first. Screenshots will be added in a follow-up.
1. Prerequisites โ
| Component | Minimum version | Notes |
|---|---|---|
| Kubernetes | 1.21+ | |
| Helm | 3.8+ | |
| Ingress controller | nginx-ingress or Traefik | with cert-manager for automated TLS |
| StorageClass | default or named | Required for PVCs |
| NVIDIA GPU (optional) | Driver 525+ | For hardware transcoding |
| MySQL (optional) | External or in-cluster | Or use the chart's embedded DB |
2. Add the Helm repository โ
helm repo add phlix https://charts.phlix.media
helm repo update
helm search repo phlix/phlix # confirm latest chart version3. Minimal values.yaml โ
replicaCount: 1
image:
repository: ghcr.io/detain/phlix-server
pullPolicy: IfNotPresent
tag: "latest" # pin to a specific release tag in production
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/proxy-read-timeout: "86400"
nginx.ingress.kubernetes.io/proxy-send-timeout: "86400"
nginx.ingress.kubernetes.io/upstream-hdrs: "Upgrade"
nginx.ingress.kubernetes.io/websocket-services: "phlix-websocket"
hosts:
- host: phlix.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: phlix-tls
hosts:
- phlix.example.com
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
persistence:
media:
enabled: true
storageClass: "" # uses default StorageClass; set to "nfs" or "local-path" if needed
size: 100Gi
readOnly: true
data:
enabled: true
storageClass: ""
size: 10Gi
config:
enabled: true
storageClass: ""
size: 1Gi
config:
database_host: "mysql.default.svc.cluster.local"
database_port: 3306
database_name: phlix
database_user: phlix
database_password: "REPLACE_WITH_STRONG_PASSWORD"
secret_key: "REPLACE_WITH_32_CHAR_KEY"
log_level: info
# Optional: GPU node scheduling for hardware transcoding
nodeSelector:
gpu: "nvidia"
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"Save as values.yaml and install with:
helm install phlix phlix/phlix -f values.yaml4. Required PersistentVolumeClaims โ
The Helm chart creates three PVCs automatically:
kubectl get pvc | grep phlix| PVC name | Purpose | Default size | Access mode |
|---|---|---|---|
phlix-media | Media files (read-only mount) | 100 Gi | ReadWriteOnce |
phlix-data | Application data (DB, watch history) | 10 Gi | ReadWriteOnce |
phlix-config | Config directory | 1 Gi | ReadWriteOnce |
StorageClass: If your cluster has no default StorageClass, you must set
persistence.media.storageClassexplicitly (e.g.,local-path,nfs,cephfs). Using a StorageClass that supportsReadWriteMany(e.g., NFS) is required for the media PVC to be mounted read-only by multiple pods.
5. Service type โ
5a. ClusterIP (default โ requires Ingress) โ
service:
type: ClusterIP
http:
port: 80Access via Ingress at https://phlix.example.com.
5b. LoadBalancer โ
service:
type: LoadBalancer
http:
port: 80Exposes phlix directly on a cloud LB. For on-premises, MetalLB can provide this.
5c. NodePort โ
service:
type: NodePort
http:
port: 80
nodePort: 32400Access at http://<any-node-ip>:32400. Not recommended for production.
6. Ingress annotations โ
nginx-ingress (recommended) โ
ingress:
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/proxy-read-timeout: "86400"
nginx.ingress.kubernetes.io/proxy-send-timeout: "86400"
# WebSocket proxying
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/upstream-hdrs: "Upgrade"
nginx.ingress.kubernetes.io/websocket-services: "phlix-websocket"
nginx.ingress.kubernetes.io/use-regex: "true"Traefik โ
ingress:
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
traefik.ingress.kubernetes.io/router.entrypoints: "websecure"
traefik.ingress.kubernetes.io/router.http-services: "phlix-http"
traefik.ingress.kubernetes.io/router.headers.customrequestheaders: "Upgrade: websocket"If using Traefik's IngressRoute CRD instead of plain Ingress, see the Traefik docs.
7. Environment variables โ
The chart passes these to the pod automatically via PHLIX_* env vars:
| Env var | Description | Example |
|---|---|---|
PHLIX_DATABASE_HOST | MySQL host | mysql.default.svc.cluster.local |
PHLIX_DATABASE_PORT | MySQL port | 3306 |
PHLIX_DATABASE_NAME | Database name | phlix |
PHLIX_DATABASE_USER | Database user | phlix |
PHLIX_DATABASE_PASSWORD | Database password | from Kubernetes Secret |
PHLIX_SECRET_KEY | JWT/signing key | from Kubernetes Secret |
PHLIX_LOG_LEVEL | Log verbosity | info, debug |
PHLIX_HTTP_PORT | Internal HTTP port | 80 |
Set passwords/keys via the chart's secrets mechanism (required):
helm install phlix phlix/phlix \
--set config.database_password=STRONG_PASSWORD \
--set config.secret_key=YOUR_32_CHAR_SECRETOr pre-create a Kubernetes Secret and reference it in values.yaml.
8. GPU node scheduling (NVIDIA) โ
For hardware-accelerated transcoding on NVIDIA GPUs:
# Install the NVIDIA device plugin (one-time per cluster)
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.5/nvidia-device-plugin.ymlThen in values.yaml:
nodeSelector:
nvidia.com/gpu: "true"
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"The container automatically detects and uses NVENC/NVDEC when available.
9. Helm upgrade process โ
When a new chart or image version is released:
# Update chart repo
helm repo update
# Check what would change
helm diff upgrade phlix phlix/phlix -f values.yaml
# Apply the upgrade
helm upgrade phlix phlix/phlix -f values.yaml
# Roll back if needed
helm rollback phlixFor zero-downtime upgrades, the chart uses RollingUpdate strategy with maxSurge: 1 and maxUnavailable: 0. Ensure readinessProbe is properly configured (it is by default).
To update only the Docker image tag:
helm upgrade phlix phlix/phlix --set image.tag=v1.2.3What can go wrong โ
PVC pending โ storage class not found โ
- Symptom:
kubectl get pvcshows all PVCsPending - Cause: Cluster has no default StorageClass, or the named StorageClass (
nfs,cephfs, etc.) does not exist - Fix: Check available StorageClasses:
kubectl get storageclass. Then set it explicitly invalues.yaml:yamlpersistence: media: storageClass: "local-path" - Verify:
kubectl describe pvc <name>showsWaiting for a volume to be created either by the external provisioner
OOMKilled โ memory limit too low โ
- Symptom: Pod is
OOMKilledshortly after starting, especially during first-run metadata fetch or FFmpeg probe - Cause: Default memory limit of
2Gimay be insufficient for libraries with large watch histories or concurrent transcoding - Fix: Increase memory limits in
values.yaml:yamlresources: limits: memory: 4Gi requests: memory: 1Gi - Verify:
kubectl top pod phlix-xxxxxxxxx(requires metrics-server) or checkkubectl describe podforLast State: Terminated, Reason: OOMKilled
Ingress 502 โ ingress controller not found or WebSocket misconfiguration โ
- Symptom: HTTP requests return 502, or WebSocket connections fail immediately
- Cause 1: No ingress controller is installed in the cluster
- Fix: Install nginx-ingress:
helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace
- Fix: Install nginx-ingress:
- Cause 2: WebSocket annotations missing from Ingress (required for the WebSocket port 3473)
- Fix: Ensure the ingress annotations include the WebSocket proxy directives listed in ยง6
- Verify:
kubectl describe ingress phlix-xxxxshows backend services correctly; check nginx-ingress logs:kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
Next steps โ
- First-run wizard โ complete the browser-based setup at
https://phlix.example.com - Linux install โ alternative install method on bare metal
- Docker install โ alternative install method using containers
- Hardware transcoding โ configure NVENC/VAAPI for GPU-accelerated transcoding on Kubernetes nodes
- Helm chart source (O.3) โ report chart issues or contributing improvements