## 此文件只需要更改 cache,periodics 相关配置,和 includes 下 listen, SSL 配置 ## Load the njs script js_path /etc/nginx/conf.d/; js_import config from constant.js; js_import emby2Pan from emby.js; js_import periodics from common/periodics.js; js_import embyItems from modules/emby-items.js; js_import embyLive from modules/emby-live.js; js_import embySearch from modules/emby-search.js; js_import embySystem from modules/emby-system.js; js_import embyTranscode from modules/emby-transcode.js; js_import embyVMedia from modules/emby-v-media.js; ## Memory Cache, workers shared values, memory is allocated based on actual usage, since njs 0.8.0 js_shared_dict_zone zone=transcodeDict:4M timeout=4h evict; js_shared_dict_zone zone=routeL1Dict:8M timeout=15m evict; js_shared_dict_zone zone=routeL2Dict:16M timeout=15m evict; # js_shared_dict_zone zone=routeL3Dict:32M timeout=15m evict; js_shared_dict_zone zone=idemDict:512K timeout=10s evict; js_shared_dict_zone zone=tmpDict:512K timeout=60s evict; js_shared_dict_zone zone=versionDict:32M timeout=11h evict; ## FileSystem Cache, images, subtitles proxy_cache_path /var/cache/nginx/emby/images levels=1:2 keys_zone=emby_images:100m max_size=10g inactive=30d use_temp_path=off; proxy_cache_path /var/cache/nginx/emby/subtitles levels=1:2 keys_zone=emby_subtitles:10m max_size=1g inactive=30d use_temp_path=off; ## ReqLimit, the processing rate of requests coming from a single IP address # limit_req_zone $binary_remote_addr zone=one:1m rate=1r/s; ## ConnLimit, the number of connections from a single IP addres # limit_conn_zone $binary_remote_addr zone=one:1m; ## Include the server groups include /etc/nginx/conf.d/includes/server-group.conf; ## Start of actual server blocks server { js_set $emby config.getEmbyHost; #emby/jellyfin address js_set $transcodeEnable config.getTranscodeEnable; js_set $transcodeType config.getTranscodeType; js_set $imageCachePolicy config.getImageCachePolicy; js_set $usersItemsLatestFilterEnable config.getUsersItemsLatestFilterEnable; ## Include the http and https configs, better don't use same port include /etc/nginx/conf.d/includes/http.conf; # include /etc/nginx/conf.d/includes/https.conf; ## Include the proxy headers include /etc/nginx/conf.d/includes/proxy-header.conf; proxy_http_version 1.1; ## js_fetch SETTINGS resolver 8.8.8.8 114.114.114.114 [2001:4860:4860::8888] [2400:3200::1]; js_fetch_verify off; # internal use only, off this fetch https:// ## Compresses the content to the client, speeds up client browsing. gzip on; gzip_disable "msie6"; gzip_comp_level 6; gzip_min_length 1100; gzip_buffers 16 8k; gzip_proxied any; gzip_types text/plain text/css text/js text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/rss+xml image/svg+xml; ## The default `client_max_body_size` is 1M, this might not be enough for some posters, etc. client_max_body_size 20M; # This default is either 4K or 8K, depending on a platform subrequest_output_buffer_size 4M; # hide nginx version info server_tokens off; # # Security / XSS Mitigation Headers # add_header X-Frame-Options "SAMEORIGIN"; # add_header X-XSS-Protection "1; mode=block"; # add_header X-Content-Type-Options "nosniff"; # aliDrive direct stream need no-referrer add_header 'Referrer-Policy' 'no-referrer'; # Only emby Proxy the basehtmlplayer.js location /web/modules/htmlvideoplayer/basehtmlplayer.js { client_body_in_file_only clean; js_content emby2Pan.modifyBaseHtmlPlayer; add_header X-Proxy-Success true; # for debug } # Only jellyfin Proxy the front-end files location ~ /web/html(Video|Audio)Player-plugin.(.*).chunk.js$ { proxy_pass $emby; proxy_set_header Accept-Encoding ""; sub_filter '.crossOrigin' '.crossOrigin = null, window.XSubFilter '; sub_filter_last_modified on; sub_filter_once off; sub_filter_types *; add_header X-Proxy-Success true; # for debug } # Proxy sockets traffic for jellyfin-mpv-shim and webClient location ~* /(socket|embywebsocket) { # Proxy emby/jellyfin Websockets traffic proxy_pass $emby; ## WEBSOCKET SETTINGS ## Used to pass two way real time info to and from emby and the client. proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_connect_timeout 1h; proxy_send_timeout 1h; proxy_read_timeout 1h; tcp_nodelay on; ## Sends data as fast as it can not buffering large chunks, saves about 200ms per request. } # vSubtitlesAdepter location ~* /videos/(.*?)(virtual)(.*)/Subtitles { js_content embyVMedia.vSubtitlesAdepter; add_header X-Handle-Success true; # for debug } # Cache the Subtitles location ~* /videos/(.*)/Subtitles { proxy_pass $emby; proxy_cache emby_subtitles; proxy_cache_revalidate on; proxy_cache_lock_timeout 10s; proxy_cache_lock on; proxy_cache_valid 200 30d; proxy_cache_key $request_uri; add_header X-Cache-Status $upstream_cache_status; # This is only to check if cache is working } # NJS used internal redirect location ~ ^(.*)/proxy(/.*)$ { internal; # internal use only gunzip on; # Jellyfin/Plex has gzip,need this,Emby no gzip but compatible proxy_set_header Accept-Encoding ""; # subrequest need this client_body_in_file_only clean; rewrite ^(.*)/proxy(/.*)$ $1$2 break; proxy_pass $emby$request_uri; # Emby/Plex need $request_uri,Jellyfin not need but compatible proxy_pass_request_body on; proxy_pass_request_headers on; add_header X-Proxy-Success true; # for debug } # conf used internal redirect location ~ ^(.*)/conf-proxy(/.*)$ { internal; # internal use only rewrite ^(.*)/conf-proxy(/.*)$ $1$2 break; proxy_pass $emby; add_header X-Conf-Proxy-Success true; # for debug } # Proxy PlaybackInfo location ~* /Items/(.*)/PlaybackInfo { client_body_in_file_only clean; js_content emby2Pan.transferPlaybackInfo; add_header X-Proxy-Success true; # for debug } # Proxy Users Items Info location ~* /Users/(.*)/Items$ { proxy_set_header Accept-Encoding ""; set $apiType ""; if ($arg_SortBy ~* Random) { set $apiType "searchSuggest"; } if ($arg_ImageTypes ~* Backdrop) { set $apiType "backdropSuggest"; } # if ($arg_GenreIds) { # set $apiType "genreSearch"; # } if ($apiType) { js_content embyItems.itemsFilter; add_header X-Modify-Success true; # for debug break; } # useProxy mark for subrequest or internalRedirect if ($args ~* "useProxy=1") { proxy_pass $emby; break; } # search inteface custom handle if ($args ~* SearchTerm) { js_content embySearch.searchHandle; add_header X-Handle-Success true; # for debug break; } proxy_pass $emby; } # Proxy UsersItemsLatest location ~* /Users/(.*)/Items/Latest$ { proxy_set_header Accept-Encoding ""; if ($usersItemsLatestFilterEnable = true) { js_content embyItems.usersItemsLatestFilter; add_header X-Modify-Success true; # for debug break; } proxy_pass $emby; } # Proxy Items Similar location ~* /Items/(.*)/Similar$ { proxy_set_header Accept-Encoding ""; set $apiType "itemSimilar"; if ($args !~* GroupProgramsBySeries) { js_content embyItems.itemsFilter; add_header X-Modify-Success true; # for debug break; } proxy_pass $emby; } # Proxy SystemInfo location ~* /system/info$ { proxy_set_header Accept-Encoding ""; js_content embySystem.systemInfoHandler; add_header X-Modify-Success true; # for debug } # Redirect the stream to njs location ~* /videos/(.*)/(stream|original) { set $apiType "VideoStreamPlay"; # limit_req zone=one; # some packaged 3rd party players called intent has bug, concurrent 2 req, disable one of them # if ($http_user_agent ~* "dandanplay/android") { # return 200; # } rewrite ^(.*)/stream/(.*)$ $1/stream break; # revert modified path "/stream/xxx.mp4" if ($request_method = "HEAD") { proxy_pass $emby; } # Cache alist direct link add_header Cache-Control max-age=3600; js_content emby2Pan.redirect2Pan; } # Redirect the live to njs location ~* /videos/(.*)/live { set $apiType "VideoLiveTranscodePlay"; # Do't merge, conf not supports, or and, || && if ($request_method = "HEAD") { proxy_pass $emby; break; } # useProxy mark if ($args ~* "useProxy=1") { proxy_pass $emby; break; } js_content embyLive.directLive; } location ~* /videos/(.*)/master { set $apiType "VideoMasterTranscodePlay"; # Do't merge, conf not supports, or and, || && if ($request_method = "HEAD") { proxy_pass $emby; break; } # useProxy mark if ($args ~* "useProxy=1") { proxy_pass $emby; break; } # transcodeConfig set $flag ""; if ($transcodeEnable = true) { set $flag "${flag}1"; } if ($transcodeType = nginx) { set $flag "${flag}1"; } if ($flag = "11") { add_header X-Upstream-Addr $upstream_addr; # for debug proxy_pass http://transcode_group; break; } if ($flag = "1") { js_content embyTranscode.transcodeBalance; break; } js_content embyLive.directLive; } # Stops an active encoding location ~* /Videos/ActiveEncodings { if ($transcodeEnable = true) { js_content embyTranscode.syncDelete; break; } proxy_pass $emby; } # Sessions Playing State location ~* /Sessions/Playing { if ($transcodeEnable = true) { js_content embyTranscode.syncPlayState; break; } proxy_pass $emby; } # Redirect Audio the stream to njs location ~* /Audio/(.*)/(universal|stream) { set $apiType "AudioStreamPlay"; if ($request_method = "HEAD") { proxy_pass $emby; break; } # Cache alist direct link add_header Cache-Control max-age=3600; js_content emby2Pan.redirect2Pan; } # for webClient download,android is SyncService api location ~* /Items/([^/]+)/Download { set $apiType "ItemsDownload"; rewrite ^(.*)/Download/(.*)$ $1/Download break; # revert modified path "/Download/xxx.mp4" if ($request_method = "HEAD") { proxy_pass $emby; break; } # Cache alist direct link add_header Cache-Control max-age=3600; js_content emby2Pan.redirect2Pan; } # Emby for android download,this is SyncService api only Emby location ~* /Sync/JobItems/(.*)/File { set $apiType "SyncDownload"; if ($request_method = "HEAD") { proxy_pass $emby; break; } # Cache alist direct link add_header Cache-Control max-age=3600; js_content emby2Pan.redirect2Pan; } # Cache the images location ~ /Items/(.*)/Images { # Disable nginx Cache first if ($imageCachePolicy = 3) { # proxy_pass $emby; break; not stop location, need rewrite last rewrite ^(.*)$ /conf-proxy$1 last; } # imageCachePolicy js_set $dict_nocache embySearch.getNocache; set $tmp_proxy_cache_key $uri; set $tmp_remove_args false; if ($imageCachePolicy = 1) { set $tmp_proxy_cache_key $request_uri; } set $tmp_args &${args}; if ($tmp_args ~* ^(.*)(&maxHeight=\w*)(.*)$) { set $tmp_args $1$3; } if ($tmp_args ~* ^(.*)(&maxWidth=\w*)(.*)$) { set $tmp_args $1$3; } if ($tmp_args ~* ^(.*)(&quality=\w*)(.*)$) { set $tmp_args $1$3; } if ($tmp_args ~* ^&(.*)$) { set $tmp_args $1; } if ($imageCachePolicy = 2) { set $args $tmp_args; set $tmp_remove_args true; # for debug } # this need compile proxy_cache_purge module # if ($uri ~* ^(.*)/Primary/Delete$) { # set $tmp_proxy_cache_key $1/Primary; # set $purge_method 1; # } proxy_pass $emby; proxy_cache emby_images; proxy_cache_revalidate on; proxy_cache_lock_timeout 10s; proxy_cache_lock on; proxy_cache_valid 200 30d; proxy_cache_key $tmp_proxy_cache_key; proxy_cache_bypass $arg_nocache $dict_nocache; add_header X-Cache-Key $tmp_proxy_cache_key; # for debug add_header X-Remove-Args $tmp_remove_args; # for debug add_header X-Modifly-Args $args; # for debug add_header X-Bypass-Args "arg_nocache=$arg_nocache, dict_nocache=$dict_nocache"; # for debug add_header X-Cache-Status $upstream_cache_status; # This is only to check if cache is working # this need compile proxy_cache_purge module # proxy_cache_purge $purge_method; # add_header X-Cache-Purge $purge_method; # for debug } ## Disables access to swagger/openapi interface location ~* /(swagger|openapi) { # js_set default convert Boolean to String js_set $flag config.getDisableDocs; # nginx conf default is String match if ($flag = true) { return 404; } proxy_pass $emby; } # customeLocations must before default location / include custome/location/*.conf; location / { # Proxy main emby/jellyfin traffic proxy_pass $emby; # client_max_body_size 1000M; ## Allows for mobile device large photo uploads. ## ADDITIONAL SECURITY SETTINGS ## ## Optional settings to improve security ## ## add these after you have completed your testing and ssl setup ## ## NOTICE: For the Strict-Transport-Security setting below, I would recommend ramping up to this value ## ## See https://hstspreload.org/ read through the "Deployment Recommendations" section first! ## # add_header 'Referrer-Policy' 'origin-when-cross-origin'; # add_header Strict-Transport-Security "max-age=15552000; preload" always; # add_header X-Frame-Options "SAMEORIGIN" always; # add_header X-Content-Type-Options "nosniff" always; # add_header X-XSS-Protection "1; mode=block" always; } location @root { # Proxy main emby/jellyfin traffic proxy_pass $emby; } # global schedule task, since njs 0.8.1 # location @periodics { # # to be run at 7 day intervals in worker process 0 # js_periodic periodics.logHandler interval=7d; # } }