Jump to content

HOW TO: emby with NGINX - With Windows Specific Tips and CSP options


pir8radio

Recommended Posts

All, 
  FYI, I am moving my network back behing a Pfsense Whitebox firewall after living on Fortigate while I was studying for my fortinet NSE certification. I really like the Fortigate firewalls.  I am at the point that I need an OpenVPN Client on my firewall again and Fortigate doesn't really support that well.  I also have a hardware limitation on the 60F as it doesn't have a 10Gbps interface for my internal network VLANs. 
  I decided to keep NGINX as it has been working so phenomenally well since last October I don't really want to go back to HAProxy on my Pfsense firewall.  My NGINX system also has Cert bot for Let's encrypt Certificate integration and has been able to keep my Emby service up and running flawlessly since build.  I literally have done nothing to keep it going. 

After i switched back to PFsense from Fortigate I ran into a problem where external clients were not able to access Emby through pfsense even though i could confirm that the NAT and firewall rules were working.  I then switched my internal network split brain DNS back to a WAN Hairpin (both external clients and Internal clients access my Emby server via the WAN port and the NAT).  At this point internal clients could access but clients on the public Internet could not. 

my PAT configuration on the NAT is as follows: NAT from the WAN public IP on https port 443 to the NGINX server on port 443.  The NGINX.conf file is set to access the Emby server on port 8096 (I really just don't want to manage certs on the Emby server and my Server VLAN is locked down pretty tight).  I also have defined LANT Networks for all my VLANs in Emby "Settings - Network LAN Networks:".   

  It took me a couple days of off-hours diagnostics but I found the problem.  the source of my frustration was my configuration on the firewall and NGINX using port 443 then passing traffic to emby on port 8096 can conflict with an Emby server setting "Settings - Network - Secure connection mode" if it is equal to "Required for all Remote Connections" because PFsense doesn't re-write the the inbound packet's source IP with the firewall's internal IP address, the NGINX Server also was not setup to re-write the packet's source IP with the NGINX server IP.  Thus Emby saw the traffic as external and denied the traffic as it was not secured on port 8096.

In my case I set "Settings - Network - Secure connection mode" equal to "Handled by Reverse Proxy" which fixed my problem.  

Edited by Tur0k
  • Like 1
Link to comment
Share on other sites

One Question I do have.  Is it possible to have my NGINX proxy a couple of other internal web services but only allow access from my internal subnets?

Link to comment
Share on other sites

On 1/25/2022 at 2:12 PM, pir8radio said:

who's config are you using..   most of the apps REQUIRE you to enter  "https"   and port "443" to actually use https..  at unless something has changed recently..  i suspect you are connecting using http    and port 80        if using my config i think i have it set to force users to https...    in that case you would have gotten a connection error if trying to use http/80.   no real way in emby to tell if your client is using http or https..   that would be in the nginx logs if they are configured in your nginx config..   

I'm using Ngnix Proxy Manager in a container inside of Home Assistant.  There's no real config files, just the UI itself.   Once I enabled websockets support and used https as opposed to relying on the http redirect, all seems fine.  The only strange thing after connecting my users over the reverse proxy is that emby wont automatically log into their accounts any more.   Each time they open the app, they have to sign in again.

Link to comment
Share on other sites

HarryMuscle

In the first post it mentions that a sub directory based example was gonna be provided also, however, I did a quick scan through all the pages in this thread and didn't notice one.  Any chance anyone has a working sub directory based (not sub domain based) Nginx configuration they would be willing to share?

Thanks,

Harry

Link to comment
Share on other sites

pir8radio
21 hours ago, HarryMuscle said:

In the first post it mentions that a sub directory based example was gonna be provided also, however, I did a quick scan through all the pages in this thread and didn't notice one.  Any chance anyone has a working sub directory based (not sub domain based) Nginx configuration they would be willing to share?

Thanks,

Harry

it would be pretty much the same except the location block might look something like:

location ~/app2(.*)$ {
    proxy_pass http://127.0.0.1:8096$1;
blah..blah...rest of the code.
}

what that does is takes    yourdomain.com/app2/otherURLstuff/index.html

and sends only this to the emby backend server:    127.0.0.1:8096/otherURLstuff/index.html

 

but as before i warn you that some things will be broken when using sub directories, on some apps... not all..  web browser will usually work fine. 

Link to comment
Share on other sites

  • 4 weeks later...
  • 4 weeks later...
dual-o
9 hours ago, TristenP said:

@pir8radio hello i have an issue with emby im disconnect random from emby can you help ? im using ure nginx config

 

best regards

Do you have check your nginx access and error logs?
Do you have this issue when you bypass nginx and access emby direct too?
Some more informations about your infrastructure would be nice.

btw: open up a new thread with your issue would be helpful.

Edited by dual-o
Link to comment
Share on other sites

TristenP
2022/03/01 06:08:47 [error] 1802#1802: *122316 connect() failed (111: Connection refused) while connecting to upstream, client: xxxxxx, server: xxxxxx, request: "GET /emby/System/Info?X-Emby-Client=Emby%20Web&X-Emby-Device-Name=Safari%20iOS&X-Emby-Device-Id=xxxxxxxx&X-Emby-Client-Version=4.7.0.25&X-Emby-Token=xxxxxx HTTP/2.0", upstream: "http://xxxxxxxx/emby/System/Info?X-Emby-Client=Emby%20Web&X-Emby-Device-Name=Safari%20iOS&X-Emby-Device-Id=xxxxxxxxxx&X-Emby-Client-Version=4.7.0.25&X-Emby-Token=xxxxxx", host: "xxxxxx", referrer: "xxxxxxxxxxxxxxxxx/web/index.html"


2022/03/14 20:32:29 [error] 1760#1760: *1 upstream prematurely closed connection while reading response header from upstream, client: xxxxxxxx, server: xxxxxxxxx, request: "GET /embywebsocket?api_key=xxxxxxxx&deviceId=xxxxxxaed HTTP/1.1", upstream: "http://xxxxxxxx/embywebsocket?api_key=xxxxxxx&deviceId=xxxxxx", host: "xxxxxxx"

this says error log

nginx config is from @pir8radio 

Edited by TristenP
Link to comment
Share on other sites

pir8radio
19 hours ago, TristenP said:
2022/03/01 06:08:47 [error] 1802#1802: *122316 connect() failed (111: Connection refused) while connecting to upstream, client: xxxxxx, server: xxxxxx, request: "GET /emby/System/Info?X-Emby-Client=Emby%20Web&X-Emby-Device-Name=Safari%20iOS&X-Emby-Device-Id=xxxxxxxx&X-Emby-Client-Version=4.7.0.25&X-Emby-Token=xxxxxx HTTP/2.0", upstream: "http://xxxxxxxx/emby/System/Info?X-Emby-Client=Emby%20Web&X-Emby-Device-Name=Safari%20iOS&X-Emby-Device-Id=xxxxxxxxxx&X-Emby-Client-Version=4.7.0.25&X-Emby-Token=xxxxxx", host: "xxxxxx", referrer: "xxxxxxxxxxxxxxxxx/web/index.html"


2022/03/14 20:32:29 [error] 1760#1760: *1 upstream prematurely closed connection while reading response header from upstream, client: xxxxxxxx, server: xxxxxxxxx, request: "GET /embywebsocket?api_key=xxxxxxxx&deviceId=xxxxxxaed HTTP/1.1", upstream: "http://xxxxxxxx/embywebsocket?api_key=xxxxxxx&deviceId=xxxxxx", host: "xxxxxxx"

this says error log

nginx config is from @pir8radio 

error 111 is a linux error, are you running on linux or windows?   well i should say its more common seeing in on linux..

websocket error most likely do you have these parts in your config in the HTTP section?: 

    proxy_connect_timeout 1h;
    proxy_send_timeout 1h;
    proxy_read_timeout 1h;

 

Edited by pir8radio
Link to comment
Share on other sites

Skyfay

First of all thanks for your work and sharing your configuration.
Shouldn't tls1 and tls1.1 be gradually removed and tls 1.3 activated instead?
I think it should be done from a safety point of view. 
And the devices that do not support tls 1.2 are very old.

  • Agree 1
Link to comment
Share on other sites

  • 1 month later...
koldnitz

I have followed this guide and everything works great.

I use Nginx on a Linux server to forward to Emby on another Linux server.

I am using cloudflare to forward to my router so that random IPs cant connect to my actually net facing IP...it all works thanks for the great write up.

My problem is that after moving the Emby server off the Linux server with Nginx on it, I can no longer use split dns to forward across my internal network.

Everything works from outside.  I can access the Emby server from http://myserveraddress.com:8096, but i can no longer use a host override to forward from https://emby.mywebsite.com from inside my network.

Does anyone know how to do this using Nginx from within my network?

I think it not working because it expects either a cloudflare website or a port other than 443 from inside network, but I'm not sure.

Thanks in advance,

Link to comment
Share on other sites

koldnitz
1 hour ago, koldnitz said:

I have followed this guide and everything works great.

I use Nginx on a Linux server to forward to Emby on another Linux server.

I am using cloudflare to forward to my router so that random IPs cant connect to my actually net facing IP...it all works thanks for the great write up.

My problem is that after moving the Emby server off the Linux server with Nginx on it, I can no longer use split dns to forward across my internal network.

Everything works from outside.  I can access the Emby server from http://myserveraddress.com:8096, but i can no longer use a host override to forward from https://emby.mywebsite.com from inside my network.

Does anyone know how to do this using Nginx from within my network?

I think it not working because it expects either a cloudflare website or a port other than 443 from inside network, but I'm not sure.

Thanks in advance,

I figured it out.

I cannot use the Emby dashboard WAN access link from inside my network.

I can however use emby.mywebsite.com from inside my network, my opnsense host override send its to Nginx server which then works it magic making it https://emby.website.com and connects me to my Emby server through the reverse proxy.

Link to comment
Share on other sites

koldnitz
3 minutes ago, koldnitz said:

figured it out.

I cannot use the Emby dashboard WAN access link from inside my network.

I can however use emby.mywebsite.com from inside my network, my opnsense host override send its to Nginx server which then works it magic making it https://emby.website.com and connects me to my Emby server through the reverse proxy.

Actually this whole problem is probably due to an interaction with the TTL of unbound dns on my opnsense server.

I dunno long of the short of it is everything is working again, and it was must likely a function of the TTL on the DNS records of my unbound server.

This might help someone in the future, but it also seems extraneous (since the Nginx setup was fine) so please remove these posts if you feel it necessary.

Link to comment
Share on other sites

  • 5 weeks later...
SalluMe10

Not sure why but I am still getting "F" for my site scan

I am running NGINX as service using NSSM

image.png.1521495c7d2aa0d58f84542649348bd3.png

 

Below is my script:

worker_processes  auto;

error_log  logs/error.log;

events {
    worker_connections  8192;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    server_names_hash_bucket_size 64;
    server_tokens off;

    ## The below will create a separate log file for your emby server which includes
    ## userId's and other emby specific info, handy for external log viewers.
    ## Cloudflare users will want to swap $remote_addr in first line below to $http_CF_Connecting_IP
    ## to log the real client IP address
    log_format  emby  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" $request_time $server_port "$http_x_emby_authorization"';


    log_format default '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" $request_time $server_port';

    sendfile        off;  ## Sendfile not used in a proxy environment.

    gzip on;   ## Compresses the content to the client, speeds up client browsing.
    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;

    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.

    ## The below will force all nginx traffic to SSL, make sure all other server blocks only listen on 443
server {
    listen 80 default_server;
    server_name _;

    return 301 https://$host$request_uri;
}

    ## Start of actual server blocks
server {

    listen [::]:443 ssl http2;    ## Listens on port 443 IPv6 with http2 and ssl enabled
    listen 443 ssl http2;    ## Listens on port 443 IPv4 with http2 and ssl enabled
    proxy_buffering off;        ## Sends data as fast as it can not buffering large chunks.

    server_name www.mydomain.ml mydomain.ml;    ## enter your service name and domain name here example emby.domainname.com

    access_log  logs/emby.log  emby;  ## Creates a log file with this name and the log info above.

     ## SSL SETTINGS ##
        ssl_session_timeout 30m;
        ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_certificate      SSL/cert.pem;  ## Location of your public PEM file.
    ssl_certificate_key  SSL/private.pem;  ## Location of your private PEM file.
        ssl_session_cache shared:SSL:10m;

     location ^~ /swagger {   ## Disables access to swagger interface
        return 404;
}

     location ~/app2(.*)$ {
         proxy_pass http://192.168.0.34:11130$1;  ## Enter the IP and port of the backend emby server here.

    proxy_hide_header X-Powered-By;     ## Hides nginx server version from bad guys.
    proxy_set_header Range $http_range;  ## Allows specific chunks of a file to be requested.
    proxy_set_header If-Range $http_if_range;  ## Allows specific chunks of a file to be requested.
    proxy_set_header X-Real-IP $remote_addr;  ## Passes the real client IP to the backend server.
        #proxy_set_header X-Real-IP $http_CF_Connecting_IP;  ## if you use cloudflare un-comment this line and comment out above line.
        proxy_set_header Host $host;  ## Passes the requested domain name to the backend server.
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  ## Adds forwarded IP to the list of IPs that were forwarded to the backend server.

     ## 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;

     ## 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;
    }
}
}

Edited by SalluMe10
Link to comment
Share on other sites

SalluMe10

ok so I think I made some progress, I am using port 443 for my domain and I am able to access my domain remotely also but I see this now:

image.png.29a68bb5c544e6e6de64586dc3c75031.png

my script is still the same all I changed is this part:


     location ~/app2(.*)$ {
         proxy_pass 35.73.3.119:443$1;  ## Enter the IP and port of the backend emby server here.

    proxy_hide_header X-Powered-By;     ## Hides nginx server version from bad guys.

 

Link to comment
Share on other sites

t123thomas

I am poised to set up my system with NGIXN, following the instructions on the first post I went to this page http://nginx-win.ecsds.eu/  but I am not sure which of the file to download from this link  nginx-win.ecsds.eu/download/

Any suggestions?

 

Link to comment
Share on other sites

mwongjay

I use Cloudflare for remote clients, but also wanted caching on my local network for all the various clients. Below is my working config. In testing with multiple clients I've seen requests drop from 700ms - 1.5s down to ~30ms or less.

nginx.conf

http {
	# Other settings removed for brevity
    
	# Map the Cloudflare ip or remote_addr if Cloudflare ip doesn't exist to $real_ip
	map $http_CF_Connecting_IP $real_ip {
    	default $http_CF_Connecting_IP;
        ""      $remote_addr;
	}
    
	# Cache
	proxy_cache_path /mnt/cache levels=1:2 keys_zone=unraid_cache:20m max_size=20g inactive=120m use_temp_path=off;
}

proxy.conf

# Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

# Proxy Connection Settings
proxy_buffers 32 4k;
proxy_connect_timeout 240;
proxy_headers_hash_bucket_size 128;
proxy_headers_hash_max_size 1024;
proxy_http_version 1.1;
proxy_read_timeout 240;
proxy_redirect  http://  $scheme://;
proxy_send_timeout 240;

# Proxy Cache and Cookie Settings
proxy_cache_bypass $cookie_session;
#proxy_cookie_path / "/; Secure"; # enable at your own risk, may break certain apps
proxy_no_cache $cookie_session;

# Proxy Header Settings
proxy_hide_header X-Powered-By;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Early-Data $ssl_early_data;
proxy_set_header Host $host;
proxy_set_header Proxy "";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Real-IP $real_ip;
proxy_set_header Range $http_range; # Allows specific chunks of a file to be requested
proxy_set_header If-Range $http_if_range;

emby.conf

server {
	listen          80;
	server_name     emby.domain.com;
	return          301 https://$server_name$request_uri;
}

server {
	listen 443 ssl http2;
	server_name     emby.domain.com;

	root /config/www;
	index index.html index.htm index.php;

	include         /config/nginx/ssl.conf;

	client_max_body_size 0;

	proxy_buffering off; # Send data as fast as it can not buffering large chunks

	# Disable access to swagger
	location ^~ /swagger {
		return 404;
	}

	location / {
		include /config/nginx/proxy.conf;
		proxy_pass              http://10.0.3.6:8096;
		http2_push_preload      on;

		# Only match image files, case-insensitive
		location ~* /Items/.*/Images/ {
			# proxy_pass is a control directive and won't be inherited, add it again
			proxy_pass http://10.0.3.6:8096;

			# Add cache status header (HIT, MISS, etc)
			add_header X-Cache-Status $upstream_cache_status;

			# Proxy buffering is required for caching
			proxy_buffering                 on;
			# Cache config
			proxy_cache_key                 "$scheme$host$request_uri";
			proxy_cache                     unraid_cache;
			proxy_cache_valid               200 48h; # Cache is valid for 200 HTTP status codes for 48h. Any other statuses should not be cached
			proxy_cache_use_stale           error timeout updating http_500 http_502 http_503 http_504;
			proxy_cache_revalidate          on; # Uses If-Modified-Since when refreshing expired cache items
			proxy_cache_background_update   on; # Combined with use_stale "updating" will return stale content while a background task updates the item
			proxy_cache_lock                on; # If multiple clients request a file that isn't in the cache only send 1 request to origin to get it
			proxy_cache_min_uses            1; # Sets the number of times an item must be requested before it's cached
		}
	}
}

 

Edited by mwongjay
Link to comment
Share on other sites

  • 3 weeks later...
Ilarramendi

Helo! Currently large downloads are not working for me with this configuration, if i add the next line to the config  it works perfectly:

proxy_max_temp_file_size 0;

 

  • Thanks 1
Link to comment
Share on other sites

  • 4 weeks later...
iBoss

Hi @pir8radio

 

I have issue only happen with old device (Galaxy Note 5) .. if  connect to the server using https I can not play any video but with http it will play.

this happen only with GN5 ... other devices (iOS, new android mobile, etc ..) all work fine.

any idea?!

 

Many thanks

Link to comment
Share on other sites

Ilarramendi
56 minutes ago, iBoss said:

Hi @pir8radio

 

I have issue only happen with old device (Galaxy Note 5) .. if  connect to the server using https I can not play any video but with http it will play.

this happen only with GN5 ... other devices (iOS, new android mobile, etc ..) all work fine.

any idea?!

 

Many thanks

Can you open emby from the web browser in the gn5?

Link to comment
Share on other sites

iBoss

@Ilarramendi

I have tried from the web ... it strange it gives me "Your connection is not private" !! but on any other devices it is secured. (please see the attached screenshot)

if I proceed to it, it it will open and play the video without any issue ... but in the emby app will not open. (please see the attached screenshot)

 

and this is my nginx conf:

 


user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  8192;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

server_names_hash_bucket_size 64;
    server_tokens off;

    log_format  emby  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" $request_time $server_port "$http_x_emby_authorization"';


    log_format default '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" $request_time $server_port';

    sendfile        off;
    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;

    proxy_connect_timeout 1h;
    proxy_send_timeout 1h;
    proxy_read_timeout 1h;
    tcp_nodelay on;

    include /etc/nginx/conf.d/*.conf;


server {
    listen 80 default_server;
    server_name _;

    return 301 https://$host$request_uri;
}


server {

    listen 80;
    listen [::]:80;

    listen [::]:443 ssl http2;
    listen 443 ssl http2;   

    ssl_session_timeout 30m;
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_certificate      /etc/nginx/cer/fullchain4.pem;
    ssl_certificate_key  /etc/nginx/cer/privkey4.pem;
    ssl_session_cache shared:SSL:10m;

    proxy_buffering off;
    server_name subdomain.mydomain;
    access_log  /var/log/nginx/emby.log  emby;


    location / {
        proxy_pass http://172.18.0.9:8096;

        proxy_hide_header X-Powered-By;
        proxy_set_header Range $http_range;
        proxy_set_header If-Range $http_if_range;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        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;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;

    }   
}
}

 

 

 

from_emby.jpg

from_browser.jpg

Edited by iBoss
Link to comment
Share on other sites

pwhodges

Hmm; the error is saying the cert authority is bad, which shouldn't be so in that case.  But I'm not aware of anything going wrong with Lets Encrypt (I use them myself for many certificates).

Actually, I'm wondering whether that is actually the fundamental problem here.  If the playback error is only occurring in a browser (have you tried other browsers, BTW?), then maybe it's a video which requires transcoding in browsers (e.g. HEVC) and you have transcoding disabled - might that be your case?

Paul

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...