jellyfin / jellyfin

The Free Software Media System
https://jellyfin.org
GNU General Public License v2.0
34.77k stars 3.17k forks source link

Docker error when bind-mounting config files in named volume: permission denied #12961

Closed SilasPeters closed 7 hours ago

SilasPeters commented 8 hours ago

This issue respects the following points:

Description of the bug

TL;DR

I want to run a jellyfin docker container with mounted config files on my device, but it seems that doing so during the first-time-setup of the container (when any mounted named volumes are yet empty) breaks jellyfin.

Full story

When starting the docker container using docker compose without bind mounting any files into /config/config, with mounting /config under a named volume, everything works. However, if I include a bind mount which mounts a file into /config/config, I get the following error:

Error (first ever output after attaching to container)

``` jellyfin | Unhandled exception. System.UnauthorizedAccessException: Access to the path '/config/config/logging.default.json' is denied. jellyfin | ---> System.IO.IOException: Permission denied jellyfin | --- End of inner exception stack trace --- jellyfin | at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError) jellyfin | at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException) jellyfin | at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException) jellyfin | at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode) jellyfin | at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize) jellyfin | at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options) jellyfin | at Jellyfin.Server.Helpers.StartupHelpers.InitLoggingConfigFile(IApplicationPaths appPaths) jellyfin | at Jellyfin.Server.Helpers.StartupHelpers.InitLoggingConfigFile(IApplicationPaths appPaths) jellyfin | at Jellyfin.Server.Program.StartApp(StartupOptions options) jellyfin | at Jellyfin.Server.Program.

(String[] args) jellyfin exited with code 0 ```

This is my compose file:

services:
  jellyfin:
    container_name: jellyfin
    image: jellyfin/jellyfin:latest
    ports:
      - '8030:8096'
      - '8031:8090'
    user: "30033:30033"
    restart: on-failure:1
    volumes:
      - jellyfin-config:/config
      - jellyfin-cache:/cache
      - ./config/web-config.json:/jellyfin/jellyfin-web/config.json
      - ./config/network.xml:/config/config/network.xml
      - ./config/system.xml:/config/config/system.xml
      - type: bind
        source: ./movies
        target: /movies
        read_only: false
        bind:
          create_host_path: true
      - type: bind
        source: ./shows
        target: /shows
        read_only: false
        bind:
          create_host_path: true

volumes:
  jellyfin-config:
    name: 'jellyfin-config'
  jellyfin-cache:
    name: 'jellyfin-cache'

Work-around

I resolve the issue by first doing everything exactly the same, but without the bind-mounts of ./config/* into /config/config/*, let the container start, do it's migrations and such, let the named volumes be saturated, and then adding back the mounts in the compose file and call docker compose up a second time. The result is everything working as intended, with the provided config files properly read.

My suspicion

I believe that the container cannot start if the /config/config directory already contains a (my) file, and not all other files generated during first-time setup. Somehow, I first need to let the program generate all the files to then replace two of them of my own.

Reproduction steps

  1. Replicate my docker compose file
  2. Create a folder called config next to the file, and in it three files (names can be found in the compose file)
  3. Ensure that the uid:gid matches the ones of the files (or just run as root)
  4. Do docker compose up, ensuring that no volumes called jellyfin-{config|cache} exist yet.
  5. It breaks, giving the error specified.
  6. Comment out the lines declaring the mount binds to the files
  7. Docker compose down, remove the just created (and half-saturated) volumes
  8. Docker compose up, and everything works without the wished for config
  9. Stop the container
  10. Uncomment the lines declaring the mount binds to the files
  11. Docker compose up
  12. We have what we want to have: everything working with proper config file contents.

What is the current bug behavior?

Jellyfin does not start properly if a bind-mount is specified into /config/config.

What is the expected correct behavior?

Jellyfin always starts properly, regardless of any bind-mounted config files, and does not overwrite said files. It results in a started jellyfin with specified config files.

Jellyfin Server version

10.10.0+

Specify commit id

No response

Specify unstable release number

No response

Specify version number

No response

Specify the build version

Can't open the dashboard as of now

Environment

Jellyfin logs

jellyfin  | Unhandled exception. System.UnauthorizedAccessException: Access to the path '/config/config/logging.default.json' is denied.
jellyfin  |  ---> System.IO.IOException: Permission denied
jellyfin  |    --- End of inner exception stack trace ---
jellyfin  |    at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
jellyfin  |    at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
jellyfin  |    at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
jellyfin  |    at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
jellyfin  |    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
jellyfin  |    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
jellyfin  |    at Jellyfin.Server.Helpers.StartupHelpers.InitLoggingConfigFile(IApplicationPaths appPaths)
jellyfin  |    at Jellyfin.Server.Helpers.StartupHelpers.InitLoggingConfigFile(IApplicationPaths appPaths)
jellyfin  |    at Jellyfin.Server.Program.StartApp(StartupOptions options)
jellyfin  |    at Jellyfin.Server.Program.<Main>(String[] args)
jellyfin exited with code 0

FFmpeg logs

No response

Client / Browser logs

No response

Relevant screenshots or videos

No response

Additional information

felix920506 commented 7 hours ago

This is a problem with your configuration. Please head to our forum or chat rooms for troubleshooting. https://jellyfin.org/contact