My issue: I have Jellyfin installed on a local machine. When I connect directly (http://192.168.7.8:8096) to it, everything works perfectly fine. However, when I connect through the proxy (https://jellfyin.mydomain.com/) I can access my home page just fine and browse all the media. It also plays some HD content. However, when I try to play the very same 4K content that works fine via the direct connection, it stutters and plays half a second every 60-90 seconds.
Solutions I’ve tried: I don’t recall all the various configs I have tried, but nothing worked. And the config I have now is basically a direct copy from the Jellyfin site.
Version of NGINX or NGINX adjacent software (e.g. NGINX Gateway Fabric):
nginx version: nginx/1.24.0 (Ubuntu)
Deployment environment:
Directly installed in a Virtual Machine (VirtualBox) on Ubuntu 24.04 LTS
This is my config for this site:
server {
server_name jellyfin.mydomain.com;
## The default `client_max_body_size` is 1M, this might not be enough for some posters, etc.
client_max_body_size 20M;
# use a variable to store the upstream proxy
set $jellyfin 192.168.7.8;
# Security / XSS Mitigation Headers
add_header X-Content-Type-Options "nosniff";
# Permissions policy. May cause issues with some clients
add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), battery=(), bluetooth=(), camera=(), clipboard-read=(), display-capture=(), document-domain=(), encrypted-media=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), i>
# Content Security Policy
# See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
# Enforces https content and restricts JS/CSS to origin
# External Javascript (such as cast_sender.js for Chromecast) must be whitelisted.
add_header Content-Security-Policy "default-src https: data: blob: ; img-src 'self' https://* ; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.gstatic.com https://www.youtube.com blob:; worker-src 'self' blob>
location / {
# Proxy main Jellyfin traffic
proxy_pass http://$jellyfin: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-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
# Disable buffering when the nginx proxy gets very resource heavy upon streaming
proxy_buffering off;
}
location /socket {
# Proxy Jellyfin Websockets traffic
proxy_pass http://$jellyfin:8096;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
access_log /var/log/nginx/jellyfin.mydomain.com-access.log;
error_log /var/log/nginx/jellyfin.mydomain.com-error.log info;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/jellyfin.mydomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/jellyfin.mydomain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = jellyfin.mydomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 http2;
server_name jellyfin.mydomain.com;
return 404; # managed by Certbot
}
NGINX access/error log: *
*
2026/06/09 15:58:16 [warn] 1225#1225: *47019 could not allocate new session in SSL session shared cache “le_nginx_SSL” while SSL handshaking, client: 192.168.7.3, server: 0.0.0.0:443
2026/06/09 15:58:59 [info] 1225#1225: *47022 client canceled stream 371 while reading upstream, client: 192.168.7.3, server: jellyfin.mydomain.com, request: “GET /Playback/BitrateTest?Size=500000 HTTP/2.0”, upstream: “http://192.168.7.8:8096/Playback/BitrateTest?Size=500000”, host: “jellyfin.mydomain.com”
2026/06/09 15:59:13 [info] 1225#1225: *47022 client canceled stream 385 while reading upstream, client: 192.168.7.3, server: jellyfin.mydomain.com, request: “GET /Playback/BitrateTest?Size=500000 HTTP/2.0”, upstream: “http://192.168.7.8:8096/Playback/BitrateTest?Size=500000”, host: “jellyfin.mydomain.com”
2026/06/09 16:00:15 [info] 1225#1225: *47022 client canceled stream 409 while reading upstream, client: 192.168.7.3, server: jellyfin.mydomain.com, request: “GET /videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported HTTP/2.0”, upstream: “http://192.168.7.8:8096/videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported”, host: “jellyfin.mydomain.com”
2026/06/09 16:00:35 [info] 1225#1225: *47022 client canceled stream 425 while reading upstream, client: 192.168.7.3, server: jellyfin.mydomain.com, request: “GET /videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported HTTP/2.0”, upstream: “http://192.168.7.8:8096/videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported”, host: “jellyfin.mydomain.com”
2026/06/09 16:00:55 [info] 1225#1225: *47022 client canceled stream 431 while reading upstream, client: 192.168.7.3, server: jellyfin.mydomain.com, request: “GET /videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported HTTP/2.0”, upstream: “http://192.168.7.8:8096/videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported”, host: “jellyfin.mydomain.com”
2026/06/09 16:01:15 [info] 1225#1225: *47022 client canceled stream 439 while reading upstream, client: 192.168.7.3, server: jellyfin.mydomain.com, request: “GET /videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported HTTP/2.0”, upstream: “http://192.168.7.8:8096/videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported”, host: “jellyfin.mydomain.com”
2026/06/09 16:01:35 [info] 1225#1225: *47022 client canceled stream 445 while reading upstream, client: 192.168.7.3, server: jellyfin.mydomain.com, request: “GET /videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported HTTP/2.0”, upstream: “http://192.168.7.8:8096/videos/d2ffec13-e9aa-882f-1bfb-b4e0b4049153/main.m3u8?DeviceId=a1a133f3fbf4ffa9dd77376740e944f9a24aea37b82c0dca&MediaSourceId=d2ffec13e9aa882f1bfbb4e0b4049153&VideoCodec=h264,vp9&AudioCodec=aac&AudioStreamIndex=2&VideoBitrate=139616000&AudioBitrate=384000&MaxFramerate=24&SegmentContainer=mp4&MinSegments=1&BreakOnNonKeyFrames=False&PlaySessionId=370b4a838c154b048d21fa036909026b&ApiKey=c523df6a7d504c228fd0ed06faedff8e&TranscodingMaxAudioChannels=2&RequireAvc=false&EnableAudioVbrEncoding=true&Tag=9c8500c71c5d44b4a6ed64637ebf0b91&hevc-level=150&hevc-videobitdepth=10&hevc-profile=main10&h264-profile=high,main,baseline,constrainedbaseline&h264-level=41&TranscodeReasons=AudioCodecNotSupported”, host: “jellyfin.mydomain.com”
What else could I try to get this to work smoothly through the proxy?