• Login
  • Register
  • Login Register
    Login
    Username/Email:
    Password:
    Or login with a social network below
  • Forum
  • Website
  • GitHub
  • Status
  • Translation
  • Features
  • Team
  • Rules
  • Help
  • Feeds
User Links
  • Login
  • Register
  • Login Register
    Login
    Username/Email:
    Password:
    Or login with a social network below

    Useful Links Forum Website GitHub Status Translation Features Team Rules Help Feeds
    Jellyfin Forum Support Troubleshooting SOLVED: MKV files wont play in Android client app when accessed through NGINX reverse proxy

     
    • 0 Vote(s) - 0 Average

    SOLVED: MKV files wont play in Android client app when accessed through NGINX reverse proxy

    stiw47
    Offline

    Junior Member

    Posts: 3
    Threads: 1
    Joined: 2024 Oct
    Reputation: 0
    Country:Serbia
    #1
    2025-02-24, 10:32 AM (This post was last modified: 2025-02-24, 07:34 PM by stiw47. Edited 1 time in total.)
    TBH, I am not quite sure if this is Jellyfin related, or NGINX related or SSO-Auth plugin related, but I spent lot of time yesterday, was not able to figure it on my own, and decided to ask for help.
    In short:
    1. I am using jellyfin-plugin-sso: https://github.com/9p4/jellyfin-plugin-sso for authentication through Authentik. I already removed all internal users in Jellyfin, and only users from Authentik have access to the Jellyfin. Authentication works without issue. True, as we already know, it is not possible to login to Android Jellyfin client with SSO, but here I am using quick connect, and it is pretty stable, logged in session persist across phone reboot, etc. TBH, I'm not sure if this SSO login is related with the actual issue at all, but since I started using it 2-3 weeks ago, and not sure if issue started at the same time (noticed issue yesterday), I meant maybe is worthy to mention.

    2. Jellyfin is running on 192.168.0.21:8096 in local network. It is docker installation on Archlinux host. Docker image is one from linuxserver.io: https://docs.linuxserver.io/images/docker-jellyfin/, and it is almost always on latest version, since I am doing docker compose pull && docker compose up -d almost every day. Anyway, current Jellyfin server version is 10.10.6. Docker compose will be provided later in TL;DR. At this point, everything is ok. If I connect Jellyfin Android client to http://192.168.0.21:8096 in home LAN, and login with quick connect, I can play any media file from Jellyfin libraries. Ok, "any media file" is little overrated, since I have .mkv containers, .webm, and .mp4 containers in my libraries, but ok, it can play both of them.

    3. Since I enabled SSO and 2FA, I want that my Jellyfin server being publicly accessible on internet. I already have my valid domain name, and valid Let's Encrypt certificate, and as little more background it is not first time to do something like this, I have a lot more services open to internet, and accessed in similar way like this Jellyfin through NGINX reverse proxy. So we coming to the part. Let's say my domain is e.g. example.com ( <- btw, this is Authentik address). And let's say my Jellyfin subdomain configured in NGINX is jellyfin.example.com. As said, it is configured as reverse proxy in NGINX, will provide conf file later in TL;DR, and it is working. I can access Jellyfin, I can browse all libraries, I can play any file .mp4 or .mkv when Jellyfin is accessed via subdomain and from web browser, regardless that web browser is on Windows PC, Linux PC, Android phone, etc.

    THE ISSUE: I cannot play .mkv files in Android Jellyfin client, when Jellyfin is accessed via subdomain from Android client.
    The error message in UI/player is pretty generic one, same as when codec is not supported:

    Playback error Playback failed due to a fatal player error.
    [Image: Screenshot_20250224-102450_Jellyfin.png]

    Let's just remind on point 2. above, and underline that there is no any issue with mkv file play, when Jellyfin Android client connects to 192.168.0.21:8096, instead to https://jellyfin.example.com
    Also, .mp4 and .webm files have no issue with playing from Android client and accessed via subdomain.

    Even more, and just as additional info, there is Android app called Findroid, unofficial Jellyfin client. This app has no issue with playing anything when connected via my subdomain. But it would be another topic why this app does not fit me and I cannot take it as full replacement.

    TL;DR

    My Jellyfin is part of big docker compose stack, including a lot of *arr apps and other, so below I will paste Jellyfin only related part from docker-compose.yaml:
    Code:
    services:
      media-jellyfin:
        image: lscr.io/linuxserver/jellyfin:latest
        container_name: media-jellyfin
        environment:
          - PUID=1000
          - PGID=1000
          - TZ=Europe/Belgrade
        volumes:
          - ./jellyfin/conf:/config
          - ./jellyfin/web-config.json:/usr/share/jellyfin/web/config.json
          - ./jellyfin/assets:/usr/share/jellyfin/web/assets
          - /mergerfs-media/jellystarr/media:/data
        runtime: nvidia
        deploy:
          resources:
            reservations:
              devices:
                - driver: nvidia
                  count: 1
                  capabilities: [gpu]
        ports:
          - 8096:8096/tcp
          - 8920:8920/tcp
          - 7359:7359/udp
        devices:
          - "/dev/nvidia0:/dev/nvidia0"
          - "/dev/nvidiactl:/dev/nvidiactl"
          - "/dev/nvidia-uvm:/dev/nvidia-uvm"
          - "/dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools"
        restart: unless-stopped


    This is my NGINX reverse proxy, /etc/nginx/conf.d/jellyfin.conf. Few stuffs changed yesterday in trials to make it work. Anyway, below is current version:
    Code:
    server {
        listen 80;
        server_name jellyfin.example.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        http2 on;
        server_name jellyfin.example.com;
        include /etc/nginx/_templates/common-error.conf;
        proxy_buffers 8 16k;
        proxy_buffer_size 32k;
       
        location / {
            proxy_pass http://192.168.0.21:8096;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Host $http_host;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $http_connection;
            proxy_buffering off;
            #proxy_cookie_path / "/; Secure; HttpOnly; SameSite=Strict";
            proxy_intercept_errors on;
        }
    }


    Since above jellyfin.conf inherits some settings from main nginx.conf, maybe worthy to mention that part from nginx.conf. It is in http block:
    Code:
        # Basic Security Headers
        add_header X-Frame-Options SAMEORIGIN always;
        add_header X-Content-Type-Options nosniff always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Referrer-Policy "no-referrer" always;
        add_header X-Robots-Tag "none" always;

        ## SSL/TLS Configuration
        ssl_certificate /etc/nginx/certs/certificatechain.pem;
        ssl_certificate_key /etc/nginx/certs/privatekey.pem;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        resolver 192.168.0.21 9.9.9.9 1.1.1.1 1.0.0.1 valid=30s;
        resolver_timeout 5s;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_trusted_certificate /etc/nginx/certs/certificatechain.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        #ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES';
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1d;
        ssl_session_tickets off;
        ssl_buffer_size 1400;
        ssl_ecdh_curve X25519:prime256v1:secp384r1;
        ssl_dhparam /etc/nginx/dhparam.pem;


    Btw, NGINX is running also in docker, and it is pretty basic and standard installation, without additional modules, etc. and from official NGINX alpine image latest.

    This is what I can see in Jellyfin logs when I start playback of .mkv video (docker logs -f media-jellyfin):
    Code:
    [11:02:11] [INF] [27] Jellyfin.Plugin.LocalIntros.IntroProvider: Selecting intros based on criteria, 30 intros found
    [11:02:11] [INF] [27] Jellyfin.Plugin.LocalIntros.IntroProvider: Selecting intro from 0 to 30, selected index: 4
    [11:02:11] [INF] [27] Jellyfin.Plugin.LocalIntros.IntroProvider: Selected intro: a66af8f8-76fb-433d-8256-ba6e20758254
    [11:02:11] [INF] [27] Jellyfin.Plugin.LocalIntros.IntroProvider: Selected intro ID: a66af8f8-76fb-433d-8256-ba6e20758254
    [11:02:11] [INF] [27] Jellyfin.Plugin.LocalIntros.IntroProvider: Selected intro name: 85
    [11:02:11] [INF] [27] Jellyfin.Plugin.LocalIntros.IntroProvider: Selected intro path: /data/intros/85.webm
    [11:02:11] [INF] [23] Jellyfin.Api.Helpers.MediaInfoHelper: User policy for stiw47-full. EnablePlaybackRemuxing: True EnableVideoPlaybackTranscoding: True EnableAudioPlaybackTranscoding: True
    [11:02:19] [INF] [23] Emby.Server.Implementations.Session.SessionManager: Playback stopped reported by app Jellyfin Android 2.6.2 playing 85. Stopped at 6695 ms
    [11:02:20] [INF] [24] Jellyfin.Api.Helpers.MediaInfoHelper: User policy for stiw47-full. EnablePlaybackRemuxing: True EnableVideoPlaybackTranscoding: True EnableAudioPlaybackTranscoding: True
    [11:02:21] [INF] [27] Jellyfin.Api.Helpers.MediaInfoHelper: User policy for stiw47-full. EnablePlaybackRemuxing: True EnableVideoPlaybackTranscoding: True EnableAudioPlaybackTranscoding: True
    [11:02:21] [INF] [24] Jellyfin.Api.Helpers.MediaInfoHelper: User policy for stiw47-full. EnablePlaybackRemuxing: True EnableVideoPlaybackTranscoding: True EnableAudioPlaybackTranscoding: True
    [11:02:23] [INF] [24] Emby.Server.Implementations.Session.SessionManager: Playback stopped reported by app Jellyfin Android 2.6.2 playing Алфа и Омега. Stopped at 0 ms

    I am using Local Intros plugin, and we can see ^ that intro 85.webm is playing successfully before movie (as said before, .webm has not issue). However, when .mkv should be played, it is stopped immediatelly on 0ms, without any further error.

    This is the specification of the above .mkv video:
    Code:
    < 🥩 stiw47@archmedia: Alfa i Omega 🥓 > $ ffprobe -hide_banner -i Alpha.and.Omega.2010.1080p.x264.SR.HR.EN.RU.mkv
    Input #0, matroska,webm, from 'Alpha.and.Omega.2010.1080p.x264.SR.HR.EN.RU.mkv':
      Metadata:
        title          : Alpha and Omega
        LANGUAGE        : Srpski // Hrvatski // English // Русский
        ENCODER        : Lavf59.27.100
      Duration: 01:27:51.27, start: 0.000000, bitrate: 3348 kb/s
      Stream #0:0(Srpski // Hrvatski // English // Русский): Video: h264 (High), yuv420p(tv, bt709, progressive), 1916x1080 [SAR 1:1 DAR 479:270], 24 fps, 24 tbr, 1k tbn (default) (forced)
          Metadata:
            title          : Alpha and Omega
            DURATION        : 01:27:44.437000000
      Stream #0:1(Srpski): Audio: aac (LC), 48000 Hz, stereo, fltp (default) (forced)
          Metadata:
            title          : Alfa i Omega
            DURATION        : 01:27:44.468000000
      Stream #0:2(Hrvatski): Audio: aac (LC), 48000 Hz, 5.1, fltp
          Metadata:
            title          : Alfa i Omega
            DURATION        : 01:27:44.468000000
      Stream #0:3(English): Audio: aac (LC), 48000 Hz, 5.1, fltp
          Metadata:
            title          : Alpha and Omega
            DURATION        : 01:27:44.468000000
      Stream #0:4(Русский): Audio: aac (LC), 48000 Hz, 6 channels, fltp
          Metadata:
            title          : Альфа и Омега
            DURATION        : 01:27:51.274000000

    As we can see, nothing exotic. H264 video stream with 4 aac audio tracks, i.e. something should be able to play anywhere. For test purpose, I copied it to .mp4 container, with keep all codecs same:
    Code:
    $ ffmpeg -i Alpha.and.Omega.2010.1080p.x264.SR.HR.EN.RU.mkv -map 0 -c copy Alpha.and.Omega.2010.1080p.x264.SR.HR.EN.RU.mp4
    This is specification of the new one, exactly the same as previous one, just .mp4 container instead:
    Code:
    < 😜 stiw47@archmedia: Alfa i Omega 🛂 > $ ffprobe -hide_banner -i Alpha.and.Omega.2010.1080p.x264.SR.HR.EN.RU.mp4
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'Alpha.and.Omega.2010.1080p.x264.SR.HR.EN.RU.mp4':
      Metadata:
        major_brand    : isom
        minor_version  : 512
        compatible_brands: isomiso2avc1mp41
        title          : Alpha and Omega
        encoder        : Lavf61.7.100
      Duration: 01:27:51.27, start: 0.000000, bitrate: 3356 kb/s
      Stream #0:0[0x1]: Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1916x1080 [SAR 1:1 DAR 479:270], 2452 kb/s, 24 fps, 24 tbr, 16k tbn (default) (forced)
          Metadata:
            handler_name    : VideoHandler
            vendor_id      : [0][0][0][0]
      Stream #0:1[0x2]: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 221 kb/s (default) (forced)
          Metadata:
            handler_name    : SoundHandler
            vendor_id      : [0][0][0][0]
      Stream #0:2[0x3]: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 221 kb/s
          Metadata:
            handler_name    : SoundHandler
            vendor_id      : [0][0][0][0]
      Stream #0:3[0x4]: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 221 kb/s
          Metadata:
            handler_name    : SoundHandler
            vendor_id      : [0][0][0][0]
      Stream #0:4[0x5]: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 6 channels, fltp, 224 kb/s
          Metadata:
            handler_name    : SoundHandler
            vendor_id      : [0][0][0][0]

    And this .mp4 file play successfully in Android client accessed via subdomain:
    Code:
    [11:21:20] [INF] [97] Jellyfin.Plugin.LocalIntros.IntroProvider: Selecting intros based on criteria, 30 intros found
    [11:21:20] [INF] [97] Jellyfin.Plugin.LocalIntros.IntroProvider: Selecting intro from 0 to 30, selected index: 25
    [11:21:20] [INF] [97] Jellyfin.Plugin.LocalIntros.IntroProvider: Selected intro: cfa84f52-edc4-4f69-8941-7500fbdae868
    [11:21:20] [INF] [97] Jellyfin.Plugin.LocalIntros.IntroProvider: Selected intro ID: cfa84f52-edc4-4f69-8941-7500fbdae868
    [11:21:20] [INF] [97] Jellyfin.Plugin.LocalIntros.IntroProvider: Selected intro name: 106
    [11:21:20] [INF] [97] Jellyfin.Plugin.LocalIntros.IntroProvider: Selected intro path: /data/intros/106.webm
    [11:21:20] [INF] [26] Jellyfin.Api.Helpers.MediaInfoHelper: User policy for stiw47-full. EnablePlaybackRemuxing: True EnableVideoPlaybackTranscoding: True EnableAudioPlaybackTranscoding: True
    [11:21:23] [INF] [90] Emby.Server.Implementations.Session.SessionManager: Playback stopped reported by app Jellyfin Android 2.6.2 playing 106. Stopped at 1892 ms
    [11:21:23] [INF] [28] Jellyfin.Api.Helpers.MediaInfoHelper: User policy for stiw47-full. EnablePlaybackRemuxing: True EnableVideoPlaybackTranscoding: True EnableAudioPlaybackTranscoding: True
    [11:21:39] [INF] [28] Emby.Server.Implementations.Session.SessionManager: Playback stopped reported by app Jellyfin Android 2.6.2 playing Alpha and Omega. Stopped at 13416 ms

    ^^ Stopped at 13416 ms <- manually by me.

    I tried to disable/re-enable HW transcoding - no success (I did not expected, since this is h264 and shouldn't be related)
    I tried to spin up one more Jellyfin container, with the difference on port 8097 instead of 8096, and created related NGINX reverse proxy with jellyfin2.example.com pointing to it. This container has no SSO, login with internal user, and I'm also not able to play .mkv h264 in android app.
    I tried to add video/x-matroska mkv; to nginx mime.types file - no success.
    Tried also to append mkv to existing mime type video/webm webm mkv; - no success.
    Of course, nginx restarted when mime.types edited.

    Appreciate any help, and ready to provide any additional info. thanks.
    Go to solution
    TheDreadPirate
    Offline

    Community Moderator

    Posts: 15,374
    Threads: 10
    Joined: 2023 Jun
    Reputation: 460
    Country:United States
    #2
    2025-02-24, 01:46 PM (This post was last modified: 2025-02-24, 01:46 PM by TheDreadPirate. Edited 1 time in total.)
    Remove these security options.

    Code:
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Frame-Options SAMEORIGIN always;

    These are both known to be problematic with some clients.

    This one MIGHT also be an issue.

    Code:
    add_header Referrer-Policy "no-referrer" always;

    https://jellyfin.org/docs/general/networ...exampleorg

    Also make sure your phone is set to use the integrated player and not the web player.  Settings > Client settings.
    Jellyfin 10.10.7 (Docker)
    Ubuntu 24.04.2 LTS w/HWE
    Intel i3 12100
    Intel Arc A380
    OS drive - SK Hynix P41 1TB
    Storage
        4x WD Red Pro 6TB CMR in RAIDZ1
    [Image: GitHub%20Sponsors-grey?logo=github]
    stiw47
    Offline

    Junior Member

    Posts: 3
    Threads: 1
    Joined: 2024 Oct
    Reputation: 0
    Country:Serbia
    #3
    2025-02-24, 02:14 PM
    Wov, thank you very much @TheDreadPirate.
    Since I'm watching some movie now, I done just quick test. Commented out all security headers:

        # Basic Security Headers
        #add_header X-Frame-Options SAMEORIGIN always;
        #add_header X-Content-Type-Options nosniff always;
        #add_header X-XSS-Protection "1; mode=block" always;
        #add_header Referrer-Policy "no-referrer" always;
        #add_header X-Robots-Tag "none" always;



    Restarted NGINX container, and it works, in web player. Cannot remember now why I don't like integrated player, and why I prefer web player, but will check this later as well. Btw, I am sure that yesterday I also tried to comment out all above headers and restarted NGINX, but the difference is that I cleared cache and data of Android client today additionally and it started work.
    Later will check in more detail line by line, what header(s) exactly was(were) troublesome, and mark thread solved.

    Thx.
    stiw47
    Offline

    Junior Member

    Posts: 3
    Threads: 1
    Joined: 2024 Oct
    Reputation: 0
    Country:Serbia
    #4
    2025-02-24, 07:31 PM
    Ok, after more trial and errors, I found it. Actually, it was not related to any of the:
    Code:
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Frame-Options SAMEORIGIN always;
    add_header Referrer-Policy "no-referrer" always;

    And all 3 ^ are uncommented now, mkv play is working. It was related to the CSP which I skipped to post here. Yeah, I have it also, and it is (IMHO) little idiotic long, TBH I am still learning about it and trying to find some optimal way....
    Anyway, started ADB logcat to live monitor Jellyfin apk log when reproduce mkv error:
    Code:
    $ adb logcat | grep -F "`adb shell ps | grep org.jellyfin.mobile | tr -s [:space:] ' ' | cut -d' ' -f2`"

    Found this in log:
    Code:
    02-24 19:29:24.082 14351 14351 E WebView : Refused to load media from 'blob:https://jellyfin.example.com/e48a257b-0c37-4e73-951f-5d5f9abce829' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'media-src' was not explicitly set, so 'default-src' is used as a fallback.

    After several trials and errors where and what should be put, ended with this in NGINX CSP:
    Code:
    add_header Content-Security-Policy "default-src 'self'; media-src 'self' blob: https://example.com https://*.example.com; img-src.... etc. etc. insanely long....

    Will need to check/monitor now what else will be broken 😂, since I did not used media-src in CSP before 😂.
    « Next Oldest | Next Newest »

    Users browsing this thread: 2 Guest(s)


    • View a Printable Version
    • Subscribe to this thread
    Forum Jump:

    Home · Team · Help · Contact
    © Designed by D&D - Powered by MyBB
    L


    Jellyfin

    The Free Software Media System

    Linear Mode
    Threaded Mode