Jellyfin Forum
Mounting Local Storage in Linux + Linux Permissions Primer - Printable Version

+- Jellyfin Forum (https://forum.jellyfin.org)
+-- Forum: Support (https://forum.jellyfin.org/f-support)
+--- Forum: Guides, Walkthroughs & Tutorials (https://forum.jellyfin.org/f-guides-walkthroughs-tutorials)
+--- Thread: Mounting Local Storage in Linux + Linux Permissions Primer (/t-mounting-local-storage-in-linux-linux-permissions-primer)



Mounting Local Storage in Linux + Linux Permissions Primer - TheDreadPirate - 2024-08-30

Search for "configuring fstab" to skip the permissions primer.



A common question and common problem for Linux beginners is the vastly different file system structure of Linux and how storage is managed.  In Windows every storage device, RAID array, partition, or network share is treated individually.  Each assigned a drive letter (optional for network shares) and each essentially their own independent file structure.

Linux, on the other hand, has one hierarchy starting with "/", aka "root".  Every SSD/HDD, every RAID array, every partition, all network shares fall under root.  And where you place each logical storage volume can be arbitrary and customizable.

However, most modern Linux distros, especially when a GUI is installed, will auto-mount your additional storage devices.  Usually in /media/{insertUserName}, but it varies with some distros (Arch).  Super convenient and good enough for most use cases.

Until another user needs to access it.  Like Jellyfin, for example.  For package installations (apt, pacman, dnf, etc.) of Jellyfin will create a "jellyfin" user.  The Jellyfin service, and all processes it spawns, run as the "jellyfin" user.

And this is where a lot of users run into trouble.  Their media drives were auto-mounted and Jellyfin can't access them.

Why is that?

Before we get into how to fix that, we're going to talk about Linux permissions so we understand the "why" of the problem.  For simplicity's sake, we're only going to talk about permissions when using a native Linux file system on a locally attached drive.  The most common Linux file systems being EXT4, XFS, and ZFS.  And this guide will be from a command line perspective.

There are two permission types: "Basic" permissions and the more versatile ACL (access control lists).  99.999% of Jellyfin users do not need the additional functionality of ACLs, though ACLs are related to the problem above.  We'll get to that.

Both basic permissions and ACLs essentially share the same permissions break down.  There are 3 entity types and each entity type can be assigned 3 types of permissions.

The 3 entity types are "owner", "group", and "others".  The 3 permissions types are "read", "write", and "execute".  And the permission types are assigned a numerical value.

Read ( r ) - 4
Write ( w ) - 2
Execute ( x ) - 1

You've probably seen tutorials where someone runs a "chmod" command followed by some numbers, like "750".  The numbers are a combination of the 3 types summed together, or none at all.  Though, some values aren't valid in practice.

0 - No permissions
1 - Execute only (doesn't work, in practice, since you can't read the file to execute it)
2 - Write only (technically works, I can't think of a real world use case)
3 (2+1) - Write and execute (same as 1 and 2, doesn't really make sense)
4 - Read only
5 (4 + 1) - Read and execute
6 (4 + 2) - Read and write
7 (4 + 2 +1) - Read, write, and execute

Now let's talk about the example chmod value above, "750".  The position of each number in that represents one of the 3 entity types.

7 - The first position represents the permissions you are assigning the "owner" entity.  In this case full "rwx" permissions.
5 - The second position represents the permissions you are assigning the "group" entity.  In this case "r-x" permissions.  The group entity can represent more than one individual user, if that group has more than one user.  Whereas the "owner" represents an individual user.
0 - The third position represents "others".  Any user that isn't the individual owner nor a member of the group entity.

That is pretty much it for the basics.  Now let's look at an example and practice decoding it.

Code:
chris@rat-trap:/media/library/Anime Movies/5 Centimeters per Second (2007)$ ls -l
total 3495198
drwxr-x---  2 chris jellyfin          3 Apr  1 07:37  ./
drwxr-x--- 80 chris jellyfin        80 Aug  1 13:30  ../
-rw-r-----  1 chris jellyfin 5060199791 Aug 16  2022 '5 Centimeters per Second.mkv'

Let's focus on the MKV file.  "chris" is the owner, "jellyfin" is the group.  And the permissions are that "chris" has read and write permissions, "jellyfin" has read only permissions, "others' have no permissions.

Simple enough.  Now let's talk about what ./ and ../ mean since it can be useful to know what they are.

./ - this essentially means "this directory", " 5 Centimeters per Second (2007)".  Same permissions as the MKV but with execute permissions for both the owner and group.
../ - this means the parent directory, "Anime Movies".  Again, same as the MKV plus execute for the owner and group.

Seems simple enough when looking at individual files and folders.  But one the most common things I see is some variation of "I ran 'chmod 777' on my library and Jellyfin still can't see my files".  And that is rooted in a fundamental misunderstanding of Linux permission concepts.  Specifically the concept that for a user to be able to access a particular file they need permission to navigate through every single folder leading to the file.

Here is an example of a broken permission structure that would block jellyfin from reading a video.  Let's practice finding where the problem lies, why, and how to fix them.

Code:
-rwxr-xr-x  1 chris jellyfin 4096 Aug 16  2022 /media
-rwxr-x---  1 root chris    19 Aug 16  2022 /media/library
-rwxr-----  1 chris jellyfin 80 Aug 16  2022 /media/library/Anime Movies
-rwxr-x---  1 chris chris 3 Aug 16  2022 /media/library/Anime Movies/5 Centimeters Per Second (2007)
-rwxrwxrwx  1 chris jellyfin 5060199791 Aug 16  2022 '5 Centimeters per Second.mkv'

5 Centimeters per Second.mkv has 777 permissions, Jellyfin can read it, right?  Definitely not.  Remember, the Jellyfin user needs to be able to read and navigate EVERY folder leading to the video.  Little known fact, the "cd" command (change directory) requires execute permissions since you are technically "executing" from a permissions stand point.

With that in mind, let's break down where the permissions in the above example would block jellyfin from proceeding.

/media/library - This directory has 750 permissions with the owner and group set to "root", the group is set to "chris", and the "others" has no permission.  Jellyfin can get to the media folder, but can't get into the library folder.  How would we fix this?  There are two commands we could use to fix this, but we'll focus on the first one for this folder.

chown - "change owner" can change both the owner entity and the group entity.  It is usually used when you need to change both entities at the same time.  Since I want my user to own the files, we'll use chown here.

Code:
sudo chown chris:jellyfin /media/library

Whenever you change users you either need to be root or use sudo.  If you are changing the group, you also need to use sudo but only if you are not a member of the group.  If either circumstance is true, become root or use sudo.

/media/library/Anime Movies - This directory is set to give "chris" full rwx permissions and Jellyfin read only permissions.  So what's the hold up here?  Remember I said that "cd" is technically "executing".  And this doesn't just apply to you typing "cd" on the command line.  While the jellyfin user can navigate into the "Anime Movies" folder it cannot navigate to subfolders due to not having execute permissions.  So how do we fix this?

chmod - "change mode" is used to set read, write, and execute permissions on a file or folder.  There are multiple ways we can go about giving the jellyfin group execute permissions on the Anime Movies folder.

Code:
chmod 750 "/media/library/Anime Movies"
chmod g+x "/media/library/Anime Movies"

Either one of those works.  If you use the numerical values, you have to specify all three.  The second variation you can individually set permissions.

Before the plus, the options are u (owner), g (group), and o (other).  After the plus, the options are r, w, and x.  Use a plus if you want to add permissions and use a minus if you want to take away permissions.  And you can use more than one of each category.  Like "sudo chmod ug+rwx /folder" to give both owner and group rwx permissions.

You do not need to use sudo if you are the OWNER of the file.  If you have permissions to a file or folder via group membership you will need to use sudo, or become root, to chmod a file or folder.

/media/library/Anime Movies/5 Centimeters Per Second (2007) - This folder has "chris" as both the owner and group.  The owner is set with full permissions and group has read and execute permissions.  It should be pretty obvious why Jellyfin can't navigate past here.  Which brings us to the second command I mentioned could change group ownership

chgrp - "change group" does exactly that and only that.

Code:
sudo chgrp jellyfin "/media/library/Anime Movies/5 Centimeters Per Second (2007)"

Sudo is required if you are not a member of the group.

NOW the jellyfin user can access the MKV file.

Now that we've got the basics down how does this apply to the problem I described in the beginning?  Why is the jellyfin user unable to access auto-mounted drives.

This is where ACL's come in.  ACLs override basic permissions and when drives are auto-mounted by Linux the directory they are mounted in is protected by an ACL.  Auto mounted drives are usually mounted in a subfolder in /media/{yourUsername}.  The {yourUsername} directory has an ACL that only allows your user to access it.

So how do we tell if there is an ACL?  ACL's are denoted by a "+" at the end of the rwx permissions.  An example of an auto-mounted drive is below.

Code:
drwxr-xr-x 19 chris jellyfin  19 Aug 19 10:40 /media
drwxr-x---+ 19 chris chris 19 Aug 19 10:40 /media/chris
drwxr-x--- 19 chris chris 19 Aug 19 10:40 /media/chris/3TBWDRED

/media/chris has the ACL.  The "ls -l" command only shows that there is an ACL, not what permissions are in the ACL.  The contents of the ACL is retrieved with the "getfacl" command.  The output would look like this.

Code:
chris@rat-trap:~$ getfacl /media/chris
getfacl: Removing leading '/' from absolute path names
# file: chris
# owner: chris
# group: chris
user::rwx
group::rwx
other::---

Even if you were to use "chgrp" to make jellyfin the group entity on /media/chris, the ACL would override that.

So how do we fix this?  You COULD remove the ACL.  The problem is that removing the ACL will be temporary.  The next time you reboot or plugin another USB drive the ACL will be re-applied.  (Double checking on this bit, will edit if needed)

So how do you auto-mount a drive on boot, without an ACL, and can be configured to mount almost anywhere?  This is where /etc/fstab comes in.

The fstab file contains the parameters for all the drives that Linux will mount on boot.  The drive your Linux OS is installed on is already in there.

***Configuring fstab***

Before we start modifying fstab, we need to gather some information first.   Some "minimal" installs of Linux won't include fdisk.  Install the "fdisk" package from your distro's package manager.

Code:
sudo fdisk -lx

Fdisk will list out all of the locally attached drives and the partitions on them.  It's a bit hard to give specific instructions, but you'd be looking for the model of drive you want mounted (I'm assuming its a different model from your boot drive).

Here is an example drive from my system.

Code:
chris@rat-trap:~$ sudo fdisk -x /dev/sdd
Disk /dev/sdd: 2.73 TiB, 3000592982016 bytes, 5860533168 sectors
Disk model: WDC WD30EFRX-68N
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 524790FD-E3D1-4F80-B9A1-F0582FA72E06
First usable LBA: 34
Last usable LBA: 5860533134
Alternative LBA: 5860533167
Partition entries starting LBA: 2
Allocated partition entries: 128
Partition entries ending LBA: 33

Device    Start        End    Sectors Type-UUID                            UUID                                Name Attrs
/dev/sdd1  2048 5860533134 5860531087 0FC63DAF-8483-4772-8E79-3D69D8477DE4 63C1787F-E1A3-B34A-AE05-EB66F240E17D   

The piece of info from this that we need is the UUID, 63C1787F-E1A3-B34A-AE05-EB66F240E17D.  "sdd" is the drive, "sdd1" is the first partition on it (there can be more than one), and UUID is the unique identifier.  Why use the UUID and not /dev/sdd1?  The "sdd" designation is not statically assigned to the drive and can change if you were to, for example, change what SATA port your hard drive is plugged into.  But the UUID (universally unique identifer) won't change and is the ideal identifier for fstab.

Now we to want to verify the file system type.

Code:
lsblk -o PATH,FSTYPE,MOUNTPOINT /dev/sdd1

Which outputs this.

Code:
PATH      FSTYPE MOUNTPOINT
/dev/sdd1 ext4  /media/chris/3TBWDRED

It is an ext4 file system.

Now we can construct the parameters for fstab.  When you open /etc/fstab for editing you will need to use sudo or become root.  The example for my system is below.

Code:
UUID=7FC13470-0D40-8E4A-9A52-04C4CFE9CA8E /media/storage2 ext4 defaults 0 0

UUID=7FC13470-0D40-8E4A-9A52-04C4CFE9CA8E -  The first parameter is the disk you want mounted.  It can be the /dev/sdd1 identifier, but we are using the guaranteed unchanging UUID.

/media/storage2 - The second parameter is where in the file system you want the drive mounted.  This is arbitrary.  You can mount a drive anywhere.  But you have to make sure that the directory exists already and is empty.  DO NOT MOUNT YOUR MEDIA DRIVE IN YOUR HOME DIRECTORY.  Shared files do not belong in your /home directory.

ext4 - The third parameter is the file system on that disk.

defaults - The fourth are the mount options.  This is a bit advanced, but "defaults" is what we'll be putting in and is fine for locally attached drives.

The fifth (0 or 1) and sixth fields (0, 1, or 2) are switches are for advanced uses, both will be 0.

Save and quit.

You can choose to either unmount your drive from the current location or simply reboot and it will get mounted into its new location.

To unmount from the current location.

Code:
sudo umount /media/chris/3TBWDRED

Note that the command is "umount" without the first n.

Then re-mount it.

Code:
sudo mount -a

This command reads in the fstab file and mounts all the drives defined in it.  If you messed up, you will find out here.