Jellyfin post
This commit is contained in:
parent
0791f417f3
commit
542e432596
@ -1,9 +1,193 @@
|
|||||||
+++
|
+++
|
||||||
title = "Jellyfin"
|
title = "Jellyfin"
|
||||||
date = 2024-10-03
|
date = 2024-10-03
|
||||||
description = "My Jellyfin docker based instance"
|
description = "Hosting a Jellyfin Instance with Docker and Docker Compose"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
This is an post about my docker based Jellyfin instance
|
# Hosting a Jellyfin Instance with Docker and Docker Compose
|
||||||
|
Running your own media server is a great way to have complete control over your media library, and Jellyfin is one of the best open-source media server solutions available today. With Docker and Docker Compose, you can efficiently manage and scale your Jellyfin instance, along with useful companion services like Jellyseerr and Jellystat for enhanced functionality.
|
||||||
|
|
||||||
|
In this article, I’ll walk through my setup of a Jellyfin media server, hosted in Docker using Docker Compose. This assumes you already have Docker and Docker Compose installed and are comfortable with Linux environments. I’ll cover the configuration of Jellyfin, hardware transcoding, and the integration of supporting services like Jellyseerr and Jellystat to manage requests and track server statistics.
|
||||||
|
|
||||||
|
## Docker Compose Configuration Breakdown
|
||||||
|
Here’s the Docker Compose file I use to deploy Jellyfin and its associated services.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
jellyfin:
|
||||||
|
image: jellyfin/jellyfin:latest
|
||||||
|
container_name: jellyfin
|
||||||
|
user: 1000:1000
|
||||||
|
restart: 'unless-stopped'
|
||||||
|
devices:
|
||||||
|
- /dev/dri:/dev/dri # for hardware transcoding
|
||||||
|
- /dev/dri/renderD128:/dev/dri/renderD128
|
||||||
|
#- /dev/kfd:/dev/kfd # Remove this device if you don't use the OpenCL tone-mapping
|
||||||
|
group_add:
|
||||||
|
- "103" # render gid
|
||||||
|
- "27" # video gid
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
ports:
|
||||||
|
- 5100:8096
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- ./cache:/cache
|
||||||
|
- /mnt/media/torrent:/media:ro
|
||||||
|
- /dev/shm:/data/transcode # Offload transcoding to RAM if you have enough RAM
|
||||||
|
environment:
|
||||||
|
- JELLYFIN_PublishedServerUrl=https://your.host.com
|
||||||
|
|
||||||
|
jellyseerr:
|
||||||
|
image: fallenbagel/jellyseerr:latest
|
||||||
|
container_name: jellyseerr
|
||||||
|
environment:
|
||||||
|
- LOG_LEVEL=debug
|
||||||
|
- TZ=Europe/Prague
|
||||||
|
ports:
|
||||||
|
- 5280:5055
|
||||||
|
volumes:
|
||||||
|
- ./jellyseerr-config:/app/config
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
jellystat-db:
|
||||||
|
image: postgres:15.2
|
||||||
|
container_name: jellystat-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: <password>
|
||||||
|
volumes:
|
||||||
|
- ./jellystat-db:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
jellystat:
|
||||||
|
image: cyfershepard/jellystat:latest
|
||||||
|
container_name: jellystat
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: <password>
|
||||||
|
POSTGRES_IP: jellystat-db
|
||||||
|
POSTGRES_PORT: 5432
|
||||||
|
JWT_SECRET: <jwt_secret>
|
||||||
|
TZ: Europe/Prague
|
||||||
|
volumes:
|
||||||
|
- ./jellystat-data:/app/backend/backup-data
|
||||||
|
ports:
|
||||||
|
- "5110:3000"
|
||||||
|
depends_on:
|
||||||
|
- jellystat-db
|
||||||
|
```
|
||||||
|
|
||||||
|
## Jellyfin Service
|
||||||
|
The core of this setup is the jellyfin service. This container runs the Jellyfin server itself, and the configuration is designed to optimize performance and security.
|
||||||
|
|
||||||
|
### Hardware Transcoding
|
||||||
|
For efficient media transcoding, I’ve configured Jellyfin to leverage the hardware capabilities of the host machine. Specifically, I’ve mounted the /dev/dri device to the container for Intel or AMD GPU transcoding:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
devices:
|
||||||
|
- /dev/dri:/dev/dri
|
||||||
|
- /dev/dri/renderD128:/dev/dri/renderD128
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don’t need OpenCL tone-mapping, you can skip the /dev/kfd device. By adding the necessary GIDs (103 for render and 27 for video), the container has access to GPU resources.
|
||||||
|
|
||||||
|
Additionally, I’ve offloaded transcoding operations to the system’s RAM by mounting /dev/shm as the transcode directory:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- /dev/shm:/data/transcode
|
||||||
|
```
|
||||||
|
|
||||||
|
This is particularly useful if you have sufficient RAM, as it improves transcoding performance by avoiding disk I/O overhead.
|
||||||
|
|
||||||
|
### Storage
|
||||||
|
In the `volumes` section, I’ve mounted the following directories:
|
||||||
|
|
||||||
|
- `./config:/config`: Stores Jellyfin’s configuration data.
|
||||||
|
- `./cache:/cache`: Holds cache data to improve performance.
|
||||||
|
- `/mnt/media/torrent:/media:ro`: This is the read-only mount where Jellyfin accesses my media library. It’s pointed to my torrent directory, ensuring that Jellyfin can index and serve files from there but not modify them.
|
||||||
|
|
||||||
|
### Network and Ports
|
||||||
|
|
||||||
|
The Jellyfin server is exposed on port `5100` (mapped to Jellyfin’s default 8096 internal port). I also set the JELLYFIN_PublishedServerUrl environment variable to make sure the correct public URL is used for generating media links and external access.
|
||||||
|
|
||||||
|
## Jellyseerr for Media Requests
|
||||||
|
|
||||||
|
Jellyseerr is a companion service to Jellyfin, allowing users to request new content directly from the web interface. Here’s how I’ve integrated it:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jellyseerr:
|
||||||
|
image: fallenbagel/jellyseerr:latest
|
||||||
|
container_name: jellyseerr
|
||||||
|
environment:
|
||||||
|
- LOG_LEVEL=debug
|
||||||
|
- TZ=Europe/Prague
|
||||||
|
ports:
|
||||||
|
- 5280:5055
|
||||||
|
volumes:
|
||||||
|
- ./jellyseerr-config:/app/config
|
||||||
|
restart: unless-stopped
|
||||||
|
```
|
||||||
|
|
||||||
|
I’ve exposed Jellyseerr on port `5280` and linked it to the default timezone (`Europe/Prague` in my case). It’s important to store the Jellyseerr configuration separately in the `./jellyseerr-config` directory to persist user settings and requests.
|
||||||
|
|
||||||
|
## Jellystat for Tracking Server Stats
|
||||||
|
|
||||||
|
Jellystat adds another layer of utility, giving you the ability to track detailed statistics about your Jellyfin server usage, including playback metrics, user activity, and media insights.
|
||||||
|
|
||||||
|
It relies on a PostgreSQL database (`jellystat-db` service) to store all the data. I’ve configured it like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jellystat-db:
|
||||||
|
image: postgres:15.2
|
||||||
|
container_name: jellystat-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: <password>
|
||||||
|
volumes:
|
||||||
|
- ./jellystat-db:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Jellystat then communicates with the PostgreSQL instance:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jellystat:
|
||||||
|
image: cyfershepard/jellystat:latest
|
||||||
|
container_name: jellystat
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: <password>
|
||||||
|
POSTGRES_IP: jellystat-db
|
||||||
|
POSTGRES_PORT: 5432
|
||||||
|
JWT_SECRET: <jwt_secret>
|
||||||
|
TZ: Europe/Prague
|
||||||
|
volumes:
|
||||||
|
- ./jellystat-data:/app/backend/backup-data
|
||||||
|
ports:
|
||||||
|
- "5110:3000"
|
||||||
|
depends_on:
|
||||||
|
- jellystat-db
|
||||||
|
```
|
||||||
|
|
||||||
|
In this configuration, Jellystat is exposed on port `5110`, and I’ve configured the necessary environment variables to link it to the `jellystat-db` container. The JWT secret is used to authenticate requests between Jellystat and Jellyfin.
|
||||||
|
|
||||||
|
# Optimizing and Securing the Setup
|
||||||
|
## 1. Automatic Restart
|
||||||
|
Each service is configured with `restart: unless-stopped`, ensuring that the containers are restarted automatically if they crash or the host reboots. This adds reliability to the deployment, minimizing downtime.
|
||||||
|
|
||||||
|
## 2. Using RAM for Transcoding
|
||||||
|
Offloading transcoding operations to RAM using `/dev/shm` significantly boosts the performance of Jellyfin, especially when dealing with multiple simultaneous streams or high-bitrate media.
|
||||||
|
|
||||||
|
## 3. Resource Isolation and Security
|
||||||
|
By specifying the `user: 1000:1000` directive in the Jellyfin container, I’ve ensured that the Jellyfin service runs as a non-root user on the host. This enhances security by limiting the container's privileges. Also, mounting `/media` in read-only (`ro`) mode ensures that the Jellyfin service cannot modify the media files directly, reducing the risk of accidental data corruption.
|
||||||
|
|
||||||
|
# Conclusion
|
||||||
|
This Docker Compose setup offers a robust Jellyfin media server that takes full advantage of hardware transcoding, secure media access, and useful companion services like Jellyseerr for content requests and Jellystat for usage tracking. Docker makes it easy to maintain, update, and scale this setup with minimal hassle, ensuring you have full control over your media experience.
|
||||||
|
|
||||||
|
With this configuration, you can efficiently manage and monitor your media server, adding a layer of automation and insight to your Jellyfin instance.
|
||||||
|
|
||||||
|
@ -20,4 +20,5 @@
|
|||||||
.project-wrapper {
|
.project-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 2.5rem;
|
gap: 2.5rem;
|
||||||
|
margin: 0 5rem;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user