{{ template "chart.header" . }} {{ template "chart.deprecationWarning" . }} {{ template "chart.badgesSection" . }} {{ template "chart.description" . }} {{ template "chart.homepageLine" . }} ## Steps to Use a Helm Chart ### 1. Add a Helm Repository Helm repositories contain collections of charts. You can add an existing repository using the following command: ```bash helm repo add jellyfin https://jellyfin.github.io/jellyfin-helm ``` ### 2. Install the Helm Chart To install a chart, use the following command: ```bash helm install my-jellyfin jellyfin/jellyfin ``` ### 3. View the Installation You can check the status of the release using: ```bash helm status my-jellyfin ``` ## Customizing the Chart Helm charts come with default values, but you can customize them by using the --set flag or by providing a custom values.yaml file. ### 1. Using --set to Override Values ```bash helm install my-jellyfin jellyfin/jellyfin --set key1=value1,key2=value2 ``` ### 2. Using a values.yaml File You can create a custom values.yaml file and pass it to the install command: ```bash helm install my-jellyfin jellyfin/jellyfin -f values.yaml ``` {{ template "chart.maintainersSection" . }} {{ template "chart.sourcesSection" . }} {{ template "chart.requirementsSection" . }} {{ template "chart.valuesSection" . }} {{ template "helm-docs.versionFooter" . }} ## Gateway API HTTPRoute This chart supports the Kubernetes Gateway API HTTPRoute resource as a modern alternative to Ingress. To use HTTPRoute, you need to have Gateway API CRDs installed in your cluster and a Gateway resource configured. Example configuration: ```yaml httpRoute: enabled: true annotations: {} parentRefs: - name: my-gateway namespace: gateway-system sectionName: https hostnames: - jellyfin.example.com rules: - matches: - path: type: PathPrefix value: / ``` For more information about Gateway API, see: ## Hardware acceleration Out of the box the pod does not have the necessary permissions to enable hardware acceleration (HWA) in Jellyfin. Adding the following Helm values should make it enable you to use hardware acceleration features. Some settings may need to be tweaked depending on the type of device (Intel/AMD/NVIDIA/...) and your container runtime. Please refer to the Jellyfin upstream documentation for more information about hardware acceleration: ```yaml securityContext: capabilities: add: - "SYS_ADMIN" drop: - "ALL" privileged: false extraVolumes: - name: hwa hostPath: path: /dev/dri extraVolumeMounts: - name: hwa mountPath: /dev/dri ``` ## Network Security Jellyfin chart supports Kubernetes NetworkPolicy for network isolation and security hardening. NetworkPolicy allows you to control which pods can access Jellyfin (ingress) and what external connections Jellyfin can make (egress). ### Requirements - **CNI Plugin**: NetworkPolicy requires a Container Network Interface (CNI) plugin that supports NetworkPolicies, such as: - Calico - Cilium - Weave Net - Canal Check with your cluster administrator if NetworkPolicy is supported in your cluster. - **DLNA Incompatibility**: NetworkPolicy cannot be enabled when `enableDLNA: true` or `podPrivileges.hostNetwork: true` is set, as pods using `hostNetwork` bypass NetworkPolicy rules. The chart will fail deployment with a clear error message if both are enabled. ### Basic Usage By default, NetworkPolicy is disabled to maintain backward compatibility. To enable basic network isolation: ```yaml networkPolicy: enabled: true ``` This will create a NetworkPolicy with the following defaults: - **Ingress**: Allow connections from any pod in any namespace - **Egress**: Allow DNS resolution and all internet access (required for metadata) ### Production Configuration - Restrict to Ingress Controller For production environments, you typically want to restrict access to only allow traffic through the Ingress controller: ```yaml networkPolicy: enabled: true ingress: allowExternal: false namespaceSelector: matchLabels: name: ingress-nginx podSelector: matchLabels: app.kubernetes.io/name: ingress-nginx ingress: enabled: true className: nginx hosts: - host: jellyfin.example.com paths: - path: / pathType: Prefix ``` ### High Security Configuration - Restricted Egress For security-conscious deployments that need to limit outbound connections: ```yaml networkPolicy: enabled: true ingress: allowExternal: false podSelector: matchLabels: jellyfin-client: "true" # Only pods with this label can access egress: allowDNS: true # Always needed allowAllEgress: false # Block unrestricted internet restrictedEgress: allowMetadata: true # Allow HTTPS/443 for metadata providers (TMDB, etc.) allowInCluster: false # Block pod-to-pod communication ``` **Note**: With this configuration, Jellyfin can only: - Resolve DNS queries - Connect to HTTPS (port 443) endpoints for metadata providers - Cannot connect to other pods in the cluster - Cannot access non-HTTPS services ### Monitoring Integration If you're using Prometheus for monitoring, the chart automatically allows ingress from Prometheus pods when metrics are enabled: ```yaml networkPolicy: enabled: true metrics: enabled: true serviceMonitor: enabled: true ``` By default, the chart allows ingress from pods with label `app.kubernetes.io/name: prometheus`. If your Prometheus uses different labels, customize the selector: ```yaml networkPolicy: enabled: true metrics: namespace: monitoring # If Prometheus is in a different namespace podSelector: app: my-prometheus ``` ### Advanced Configuration #### Multiple Namespaces Access Allow access from multiple namespaces using custom rules: ```yaml networkPolicy: enabled: true ingress: allowExternal: false customRules: # Frontend namespace - from: - namespaceSelector: matchLabels: name: frontend podSelector: matchLabels: access-jellyfin: "true" ports: - protocol: TCP port: 8096 # Admin tools namespace - from: - namespaceSelector: matchLabels: name: admin-tools ports: - protocol: TCP port: 8096 ``` #### Custom Egress Rules Allow connections to specific external services: ```yaml networkPolicy: enabled: true egress: allowAllEgress: false restrictedEgress: allowMetadata: true allowedCIDRs: - 10.0.0.0/8 # Internal network - 192.168.0.0/16 # Another internal network customRules: # Allow connection to external database - to: - ipBlock: cidr: 203.0.113.0/24 ports: - protocol: TCP port: 5432 ``` ### Security Considerations 1. **Metadata Providers**: Jellyfin requires internet access to download metadata (movie posters, descriptions, etc.) from: - TheMovieDB (api.themoviedb.org) - TheTVDB (api.thetvdb.com) - OpenSubtitles (api.opensubtitles.com) - Fanart.tv (fanart.tv) If you use `restrictedEgress.allowMetadata: true`, these will work as they all use HTTPS (port 443). 2. **DNS Access**: DNS resolution is critical for Jellyfin operation. The chart prevents accidental DNS blocking by defaulting `allowDNS: true`. 3. **Local Metadata**: If you want to completely block internet access, you can use local metadata (NFO files and local images). This requires manual setup and is not the default Jellyfin behavior. 4. **Testing**: Always test NetworkPolicy changes in a development environment first. Misconfigured policies can block legitimate traffic. ### Troubleshooting **Jellyfin can't download metadata/images:** - Check that `egress.allowAllEgress: true` or `restrictedEgress.allowMetadata: true` is set - Verify DNS egress is allowed: `egress.allowDNS: true` **Can't access Jellyfin web interface:** - Verify ingress rules allow traffic from your access point (Ingress controller, LoadBalancer, etc.) - Check NOTES.txt after deployment for detailed NetworkPolicy status **Prometheus can't scrape metrics:** - Ensure `metrics.enabled: true` and `metrics.serviceMonitor.enabled: true` - Verify `networkPolicy.metrics.podSelector` matches your Prometheus labels - Set `networkPolicy.metrics.namespace` if Prometheus is in a different namespace **Deployment fails with "NetworkPolicy cannot be enabled...":** - You have both `networkPolicy.enabled: true` and `hostNetwork: true` (or `enableDLNA: true`) - NetworkPolicy doesn't work with host networking - Either disable NetworkPolicy or disable host networking For more configuration options, see the full values documentation in [values.yaml](values.yaml). ## Troubleshooting ### inotify Instance Limit Reached **Problem:** Jellyfin crashes with error: ``` System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached ``` **Root cause:** The Linux kernel has a limit on inotify instances (file system watchers) per user. Jellyfin uses inotify to monitor media libraries for changes. **Proper solution (recommended):** Increase the inotify limit on the Kubernetes nodes: ```bash # Temporary (until reboot) sysctl -w fs.inotify.max_user_instances=512 # Permanent echo "fs.inotify.max_user_instances=512" >> /etc/sysctl.conf sysctl -p ``` Recommended values: - `fs.inotify.max_user_instances`: 512 or higher - `fs.inotify.max_user_watches`: 524288 or higher (if you have large media libraries) **Workaround (if you cannot modify host settings):** If you're running on a managed Kubernetes cluster where you cannot modify node-level settings, you can force Jellyfin to use polling instead of inotify. **Note: This is less efficient and may increase CPU usage and delay change detection.** ```yaml jellyfin: env: - name: DOTNET_USE_POLLING_FILE_WATCHER value: "1" ``` This workaround disables inotify file watching in favor of periodic polling, which doesn't require inotify instances but is less efficient. ## IPv6 Configuration This chart supports IPv6 and dual-stack networking configurations out of the box. Health probes use httpGet by default for compatibility with both IPv4 and IPv6. ### IPv6-only Configuration For IPv6-only clusters: ```yaml service: ipFamilyPolicy: SingleStack ipFamilies: - IPv6 ``` ### Dual-stack Configuration For dual-stack clusters (both IPv4 and IPv6): ```yaml service: ipFamilyPolicy: PreferDualStack # or RequireDualStack ipFamilies: - IPv4 - IPv6 # First family in the list is the primary ``` For more information about Kubernetes dual-stack networking, see: