Have I mentioned I have discovered Jellyfin ?
Everyone wants their own home media server to avoid having to locate that elusive DVD you want to watch again, which may have degraded to the point it is unwatchable anyway so should have been backed up to disk in the first place. Of course backing it up to disk may still mean you have to move a disk to the TV you want to watch it on, so still moving things around. A media server solves that.
There are quite a few about, Kodi has existed for what seems like forever and is probably the gold standard, Plex has been around for a while, and I have found Jellyfin.
I chose to use remote external hard drives to host my media and I had to work through some issues for that so I have a section on the issues you will hit and how to work around them at the end of this post, they were not issues with Jellyfin but with permissions.
A bonus for me is that the Jellyfin client application can be installed on Chromecast devices (I have two) and Android tablets (I have one) and smart android based TVs which can access your Jellyfin media server just using your home network internal 192.168.x.x address (note: Android tablets can cast to the chromecast using the Jellyfin app, the the Linux Jellyfin app cannot… and web browsers cannot cast to chromecast on internal network addresses either so probably the google library was used; lots of internet search results saying that is because google requires you to cast to a DNS name secured by https (presumably via its DNS servers) so having a client installable on the chromecast (or smart TV) that can locate the media only by local ip-address was essential to me).
Note: google searches while investigating the case issue show PLEX is not affected… because PLEX routed through the PLEX servers; not sure exactly how that works but I wanted something that could use 192.168.1.nnn addresses and not go near the internet so chose Jellyfin.
Jellyfin and other similar media library implementations will helpfully try to locate movie covers, cast biographies, and a lot of other stuff by querying internet servers such as IMDB for every movie or show you add. To get any useful information from those queries it relies on you having a directory stucture and naming standard each solution expects and none of us tend to backup in the expected naming standard so expect a lot of folder renaming and file relocations just to get it to look like you spent some time on it and expect to have to locate DVD covers manually, Jellyfin will try to work out how to display your media backups as they are if possible and also has a “folder” view that can be enabled, but that is not as pretty as taking the time into sorting them into movies and shows (assuming you already backup in categories here).
I would say if you are copying in a huge archive of backups to a media server for the first time let it do the lookups (in my case it populated about 5% of my titles) and then turn external lookups off and just enter everything yourself going forward; a bit of effort in locating media covers and movie info but easier than trying to rename a decades worth or archives and constantlt rescanning.
Anyway, why did I chose Jellyfin over the others
- It has a damn very footprint. I created a new Debian12 VM with only 1Gb memory assigned, with 4Tb of movies and shows (on a remote external disk) for it to scan/manage and it is using zero swap… but I did create a new VM rather and install natively than use a container (jellyfin provide a docker container) as that best suited how I wanted to use it
- Even if naming standards are not followed it can still in many cases work out shows and movies
- They have implemented a optional “folder view” facility, not brilliant but it can find and handle some edge cases with a lot of directories to traverse; not especially well but it beats having to rename a decades worth of collected backups
- Easy to manually edit images and metadata to put DVD cover pictures and year of release etc into the displays, if you remember to tick the store images locally option for each library
- There is a jellyfin client that can be installed on ChromeCast devices (and presumably any android TV) that can directly use the Jellyfin server by internal network ipaddress
- Media can be added via local directories, nfs or samba (you really should read my notes on remote disks below first)
- It can be installed on Debian12 simply by running the install script, full instructions at https://jellyfin.org/docs/general/installation/linux/
, after which updates are pulled as part of a normal apt update
How I decided to use it
I chose a VM rather than a container as a lot of information (apart from ticking save images in folders and some metadta) is not stored in the directories on the media library disk themselves and as it takes a lot of effort to locate and setup images I would not want to lose all that info which I would if I deleted a container in order to start it on another machine; moving a VM disk to another machine will not lose any info (moving a VM disk I find easier than snapshotting containers and volumes and trying to move them about). I also store a copy of the VM disk on each media external disk.
While Jellyfin allows the use of remote disks within the application itself (I think it can mount samba/CIFS directories itself) I decided to use only local filesystem mount points such as /mnt/media1 /mnt/media2 etc and mount remote disks manually so I have control over what remote disks are mounted and can move the external disks between machines as needed without needing to reconfigure jellyfin as the application will always refer to the same mountpoints (plus I would prefer to use NFS rather than CIFS); so both the disks and VM are portable and do not need to be on the same physical machine :-). Be sure to read my notes on Samba/CIFS and NFS issues you will hit below.
Another advantage of using a VM is that I can keep a resonably up to date copy of the VM disk image on the external media disk itself so as long as I backup the media disk I can spin it up anywhere (yes a snapshot of a container could have been taken if I had gone the container way; containers are a lot harder to upgrade without losing data however).
So my key requirements were
- must not need to go anywhere near the internet, all streaming to be confined to my 192.168.1.x network
- must have a small footprint (I have so many VMs I am maxing out all my dedicated VM machines)
- must be usable on ChromeCast [due to casting limitations of the google APIs that means must have a client app]
- must allow me to move external library disks about; I’m exhausting available USB slots in physical machines and despite whatever anyone tells you USB powered disks (even on on a powered USB hub) just won’t work well on a USM hub, so I have to move them about machines as needed
- must be easy to setup and use
On the last… while easy to setup and use it requires a specific directory structure which my backup disks do not use. As my backup disks are in a structure that makes sense to me and I choose not to change those I needed another disk to re-layout files for Jellyfin (actually another two, backup everything !, a copy of the VM image is also backed up on the disks providing the libraries which is another advantage of using a VM).
Also on the easy to use the web interface can also easily update DVD cover images from localy saved images (ie: from imdb that may have media cover shots or something snapped from a camera) and easy to edit the metadata fields.
While I am a strong believer in backup everything identically; out of pure habbit all my initial testing was on a 2TB external disk LUKS encrypted with an ext4 filesystem (nfs mounted to the Jellyfin VM). When I needed to move to a 4Tb I left it as FAT32 so I could test for any issues with CIFS/Samba and see how it compared to NFS (result: CIFS works OK, NFS seems to be faster and have less pauses; all my interfaces and switches are 1Gb but the chomecasts attached to the TVs are using wireless, so the only difference was a change from NFS to CIFS ands I only see pausing using CIFS but the pausing is infrequent so certainly usable.
OK, so how to do it
Create a new Debian12 VM (as noted only 1Gb of memory is needed, I allocated 2 vCPUs but it can probably work with 1); then refer to https://jellyfin.org/docs/general/installation/linux/ for the install script, and after it is installed for my use I must “systemctl stop jellyfin;systemctl disable jellyfin”.
The stop and diable of the jellyfin service you may be curious about… remember my media libraries are on external disks that may be on remote machines (always remote for a VM actually), I need to mount them onto /mnt/mediaN for my setup before manually starting jellyfin on a VM reboot. One important note here is that if a “apt upgrade” also upgrades jelleyfin it is set to enabled and started so I have to remember to disable it again, and make sure the disk is mounted so it is available when the upgrade starts jellyfin.
Then copy some files in using the Movies/Shows filesystem structure; “systemctl start jellyfin”; use the Web interface to add Libraries (I kept shows and movies in seperate libraries as recommended). Jellyfin will scan the libraries as they are added but it will take a while.
To add additional media later you can just copy them into the folders already added to libraries (I had turned off the automatic regular scans for new files but it either does it daily anyway or I missed turning it off in at least one library I copied files into later). You can either wait for them to be detected over time or from the Web interface dashboard request a library scan queued.
Oh yes, you should also create a new user/admin id and remove the default. You can also add additional non-admin users such as kids in which case you can limit what media libraries they can see… I found that pointles as I hit remember me on the chromecast app to automatically log on as me each time anyway but if you have kids and R+ media you would probably not do that and logoff each time and make them use their own userids.
Thats it. You can now watch media using the web browser interface. Obviously you want a lot more than that so install the official Jellyfin client application on your tablets, TVs and chromecasts… note when you install the client apps they expect your jellyfin server to be running and will search for it on your home network at install time at which point I find just confirming the ipaddr found is correct and manually entering username/password works better
that trying to run back to the admin gui to look for some hot-plug OK button that never seems to appear. From personal experience I find the client app really useful on the chromecast/smart-TVs, but on small tablet screens the app is painful and a web browser is better although having said that I do not use a tablet for viewing and only tried that to see what it looked like,
Then enjoy the benefit of having your media available anywhere… and what I really like is just being able to pause and back-arrow out of something I am watching in the living room and exit the app, and starting the app in the bedroom and going to the “continue watching” section and resume where I left off; don’t know how I lived without it.
And a seperate section on the issues of using remote disks
Disk labels
Lots of external disks have default disk labels with spaces in the name (ie: “One Touch” for seagate one touch drives); that is difficult to manage for entries in fstab, exports and samba. Install gparted, unmount the disk, use gparted on the partition (ie: gparted /dev/sdc2) right click on the partition and change the label; this does it non-destructively. That is a lot esier than trying to figure out where quotes and backslashes are needed in configuration files… and not all config files allow spaces at all.
Disk mount locations, permissions and issues
What you must remember for all these example discussed here is that how I have decided to use Jellyfin is with a remote disk (as my Jellyfin instance runs in a VM the disk will always be remote even if plugged into the same physical machine as the VM) and to avoid having to reconfigure the VM whenever the disk is moved Jellyfin within the VM is always configured to look for its libraries at /mnt/media1. All discussions and examples are related to getting the disk available at /mnt/media1 and writeable by the jellyfin user in the VM.
It should also probably be noted that as things like image uploads seem to be stored in locations within the VM rather than the media disk by default [do check the store images in folders option on every library you create to alter that] the media disk(s) probably does not have to be writeable for Jellyfin use but as I had issues with permissions with CIFS shares everything here discusses writeable as it will probably be helpful to know for other unrelated projects as well.
On Linux machines manually plugging in an external disk will normally place it under the logged on users /media/username directory (Debian) or /run.media/username (rhel based). for FAT32 disks (the default for large external HDs) all the files will be set to the ownership of the logged on user; for EXT4 disks I think ownership of permissions is treated as for a normal ext4 filesystem but of course only the logged on user can traverse the initial /media/username directory path.
On Linux machines a FAT32 disk/directory must be exported using Samba (NFS cannot export FAT32). Samba can probably also export an EXT4 filesystem so you may think it easier just to go with Samba; just bear in mind EXT4/NFS is faster and in my experience more stable.
On Windows machines even though disks may get a different drive letter they seem to remember when a drectory has been set to shared on them, but it always pays to check each time.
If you plug in your “Library” disk to a Windows machine it must be FAT32/NTFS and can only be shared via CIFS. If plugging into a Linux machine you can use EXT4 shared by either NFS or Samba or if a FAT32 disk it can only be shared by Samba.
My preference is for EXT4 filesystems as I like to LUKS encrypt all my external drives. I also dislike the need to install and configure Samba on each machine I might want to plug the external disk into when I already have NFS on all the Linux ones anyway.
The main issues with using EXT4 filesystems is that they must be attached to a Linux machne and user ownership and permissions are correctly maintained; an issue in that the Jellyfin processes are not going to be running under the same userid you used to populate the files on your disk, if mounted using samba that can be bypassed (see Samba notes below) but if NFS mounting you must change ownership of all the directories and files to the jellyfin user, which makes it difficult to add additional files using your own userid.
The issues with FAT32 filesystems are that while they can be plugged into both Windows and Linux machines while easy to share from a Windows machine on Linux you will have to install and configure Samba on each machine you might plug it into. You must remember to override the ownership of the remote mount as discussed below on Samba mounts.
On the Jellyfin VM you need to install either the NFS or CIFS tools (or both) depending on what you will use.
Using NFS mounts
You must ensure all the directories on the remote disk are traversable/updateable by the Jellyfin user. But actulally mounting a EXT4 disk using NFS is simple.
Examples are for a EXT4 filesystem with a disk label of JELLYFIN so it is mounted under /media/mark, my Library folders are all under an Exported directory.
An /etc/exports entry on the Linux server exporting the disk (the Jellyfin VM is named jellyfin), when updating/changing it remember to “systemctl restart nfs-mountd.service”.
/media/mark/JELLYFIN/Exported jellyfin(rw,sync,no_subtree_check,no_root_squash)
Also on the server exporting the disk (only has to be done once) “firewall-cmd –add-service nfs;firewall-cmd –add-service nfs –permanent”.
An /etc/fstab entry on the Jellyfin VM, when updating fstab remember to “systemctl daemon-reload”. Note that I use noauto as I choose to manually mount my remote media.
vmhost3:/media/mark/JELLYFIN/Exported /mnt/media1 nfs noauto,nofail,noexec,nosuid,noatime,nolock,intr,tcp,actimeo=1800 0 0
Using CIFS/Samba mounts to a disk on a Windows machine
Examples are for a FAT32 filesystem, my Library folders are all under an Exported directory.
On the Windows machine use file explorer to select the Exported directory, right click on it and select properties, select the sharing tab and share the directory with a name of Exported.
Critical notes: to avoid having to enter Windows user credentials each mount use a creditials file as shown below; and even more importantly the mounted files will be default only be updateable by root so use the the fstab CIFS mount options uid/gid to set owndership (as far as the VM mounting it is concerned) to the jellyfin UID and GID (values for you install can be obtained by grepping jellyfin from passwd and group). With those set correctly a “ls -la” of the mounted filesystem will show owner:group as jellyfin which is required.
An /etc/fstab entry on the Jellyfin VM, when updating fstab remember to “systemctl daemon-reload”.
//192.168.1.178/Exported /mnt/media1 cifs noauto,uid=103,gid=110,credentials=/home/jellyfin/smb_credfile_windows.txt
An example of a credentials file for a Win10 Home machine being used to “share” the directory
username=windozeuser
password=userpassword
domain=
Using CIFS/Samba mounts to a disk on a Linux machine running Samba
Obviously the first step on the machine you will be plugging the disk into would be “apt install samba -y” (or dnf install if on a rhel type OS).
Then “systemctl stop smbd;systemctl disable smbd”. Required as not only do we need to edit the config remember that we are using external disks that may not be plugged in so lets not allow Samba to automatically start.
At this time may as well also “firewall-cmd –add-service samba;firewall-cmd –add-service samba –permanent”.
Critical notes: remembering that externally mounted disks are normally mounted under /media/username and only username can traverse the path you do not want any defaults when the directory is shared by samba to anonymous users (anonymous users will be treated as user nobody which will not have permissions which is why normally Samba mounts are on world writeable directories or secured to a group/user in smbpasswd but we do not want to waste time with that here), so you must use the force_user entry to the user that owns the files on the server which in my case is always going to me me (mark) for disks under /media/mark.
Example of share needed to be added to /etc/samba/smbd.conf (after changes “systemctl restart smbd”).
[Exported]
path = /media/mark/JELLYFIN/Exported
browseable = yes
writable = yes
read only = no
guest ok = yes
force user = mark
Critical notes: to avoid having to enter Windows user credentials each mount use a creditials file as shown below; and even more importantly the mounted files will be default not be uodateable by the jellyfin user so use the the fstab CIFS mount options uid/gid to set ownership (as far as the VM mounting it is concerned) to the jellyfin UID and GID (values for you install can be obtained by grepping jellyfin from passwd and group). With those set correctly a “ls -la” of the mounted filesystem will show owner:group as jellyfin which is required.
An /etc/fstab entry on the Jellyfin VM, when updating fstab remember to “systemctl daemon-reload”.
//192.168.1.179/Exported /mnt/media1 cifs noauto,uid=103,gid=110,credentials=/home/jellyfin/smb_credfile_samba.txt
An example of a credentials file for a Linux machine with default samba setup (default domain is WORKGROUP) and the Exported directory above (Yes it does prompt for user root and an empty password (on Debian12 with the default setup anyway; probably need to use smbpasswd to setup groups/users but not for this jellyfin post)
username=some_valid_linux_userid
password=
domain=WORKGROUP
CIFS/Samba troubleshooting notes
On the client server you are going to mount onto you must “apt install cifs-utils” (DFebian12, rhel may use a different package name). It installs a lot of stuff so you may want to remove it again after testing.
To list shares available on the remote server using/testing a credential file
smbclient --authentication-file=/home/jellyfin/smb_credfile_samba.txt --list 192.168.1.179
To list shares available on the remote without a credential file (will be prompted for empty ROOT password)
smbclient --list 192.168.1.179
To manually mount/test a mount works before adding it to fstab
Below prompts for password for ROOT@ipaddr, which is just enter anyway
mount -t cifs -o uid=103,gid=110 //192.168.1.179/Exported /mnt/media1
Or with a credential file with root and blank password skips that prompt
mount -t cifs -o uid=103,gid=110,credentials=/home/jellyfin/smb_credfile_samba.txt //192.168.1.179/Exported /mnt/media1
On the Samba server side logs are kept in /var/log/samba and any mount errors if the client was able to contact the server will be in a file named log.servername (so in my case log.jellyfin as jellyfin is the client servername) or if the server name is not resolveable log.ipaddress if you have left the rest of the default samba configuration file untouched.
Update: 09Apr2024
I have discovered using the default FAT32 file system that comes on standard 4Gb external disks either doesn’t like large files or Linux doesn’t play well with that filesystem type; I for some reason (porability) decided to use the default filesystem on a seasgate 4Tb external drive mounted to Linux; a directory containing large files became corrupt [Linux showed “d?????????”; plugging it into a windows machine windows found no errors but when trying to delete the damaged directory windows even though file explorer showed it, it also said the directory did not exist and may have been moved when trying to delete; none if the hits on solutions a google google found on that windows error (there were many, this issue seems to be common for FAT32) worked].
A disk format fixed it, which is why you need to backup your media disk. So I would recomend using EXT4 over FAT32, however I myself are still using FAT32 and CIFS because as it does not have all the consistency blocks, inodes, journalling (and LUKS encryption stuff] of EXT4 it means CIFS disks can store more media files (which is a noticable space differentce on a 4TB drive). My backup drive is 4TB LUKS+EXT4 and it is a few 100GB short of being able to hold all the data on my “live” FAT32 drive.
Up to you of course.
Update: 06Jul2025
There does seem to be a file limit somewhere. I hit a point where the jellyfin logs showed new media I was added was being scanned by ffmpeg but the media never made it to the point of being visible to the application. The only way I could esolve that was turing off all the external lookup checkboxes in the libraries after which the new media files were presented to the application correctly. Irritating but metadata can be added maually anyway.