HorsePDF 11 Posted April 15, 2024 Posted April 15, 2024 Hello, A few months ago I was in the process of moving away from directly exposing Emby via my home router to using Cloudflare Tunnels, but as it turns out, Cloudflare don't like you paying nothing and yet streaming GB/TB of data through their network. This was frustrating as I really wanted to put Emby away behind something I trust but I also didn't want to get my account banned for streaming media through it. I've read through many posts here about avoiding caching but it seems it's not necessarily the caching that will trigger your account being in trouble, it's the bandwidth usage as well of just piping all that data through their servers. Since I now had some time, I thought I would try to work out a long term stable option using Cloudflare. So what to do? When talking about security with self-hosting anything, I'm not going to go crazy but I like to take away easy wins for bad people. When it comes to running something like Emby, I'll assert that the biggest risk you face is automated attacks at scale. By this I mean that when it comes to hosting Emby at home, I am not really worried about some clever kid that I beat in an online game spending a weekend taking revenge on me or a state-backed hacking groups spending 6 months breaking in - I'm mainly worried about the type of flaws that are easy for people to automatically discover and exploit - e.g. recent examples with Emby and HomeAssistant. Both of these flaws allowed attackers to bypass the authentication layers of the application - no matter how complex your password is or whether you have MFA enabled (in the HA case), it's a trivial exploit once an attacker detects a vulnerable version of your software running. Both of these flaws were exploitable at scale, provided you could find Emby servers online. Given my determination to run things through Cloudflare for several reasons, security included, I wanted to come up with a system that gave me some confidence without being too complicated and without risking my Cloudflare account being banned for streaming through their service. I have not written this for everyone to be able to follow - if you are not familiar with nginx, Cloudflare, HTTP semantics, then this may not be all that helpful. Split Service Where I've landed is a split hosting setup - far from ideal but I think it's better than going all Cloudflare or all direct access. To begin Expose Emby through Cloudflare tunnels as per other guides (I won't go into the details here right now) Expose Emby via reverse proxy for external traffic (and internal too, makes sense to keep things consistent in my view) Setup port forwarding on your router to direct a port from the internet to your nginx service Nginx will have two Emby configurations to start with - one for external and one for internal Once you are able to hit Emby both internally as well as externally, then it's time to split the external. I'm going to imagine that you now have emby.acme.com setup via Cloudflare Tunnels, and you also have streaming.acme.com setup with direct access to your service via your home internet router. What's the difference? emby.acme.com is going to be your main address you use for everything, and that will go via Cloudflare Tunnels. You can use Cloudflare's many, many security options to come up with a setup that is secure but easy for your situation. streaming.acme.com is going to be a DNS only record in Cloudflare, it will point to your home IP and you will port forward this port (can be any random port number) to your nginx server. If we were to leave this setup in place, you would be able to access your Emby service via Cloudflare (with media streaming through Cloudflare), AND you can access Emby via the streaming address, completely outside Cloudflare. So what we can do next is use some clever redirection stuff. Nginx Configuration Now that you have two URLs working with Emby, let's look at Nginx again. In my configuration I have two different `server` blocks in my nginx configuration - one for my internal network and one for external. I don't know if this is strictly necessary but when I started I was an nginx novice and it made sense to be able to apply different rules depending on the origin of the traffic. To complete our nginx configuration, I am actually going to clone my external configuration, giving me a third `server` block. For my third block, I will use the domain streaming.acme.com - this separates it from emby.acme.com which is my tunneled traffic via Cloudflare. Now in my streaming block, I am going to update the rule as follows: This tells nginx to proxy traffic that is destined for streaming.acme.com/something/emby/videos/xxx to your emby server. What it also does (as long as you don't have other `location` sections) is tell nginx to not redirect any other requests that fall outside of this location to your Emby server. Cloudflare Redirect Since we want traffic to go through Cloudflare *except* when it's the actual media stream, we want your main Emby URL to be setup with a DNS address in CF that is proxied through their infrastructure and accesses your local Emby via CF tunnels. To handle the actual stream, we will create a redirect like this Now redirect that traffic to a new location What happens now? Well hopefully it comes together and something like this: if you visit https://streaming.acme.com:port/, then nothing is returned (where previously you could access Emby outside of Cloudflare and directly via your router) - nginx returns a 404 (or if you prefer, set it to return code 444 which drops the connection without explanation). If you visit https://emby.acme.com/ then you will hit the Emby login screen and can log in, and move around the application (this traffic is all via Cloudflare, with caching etc.) If you start to play a video from https://emby.acme.com, Cloudflare will intercept that request and return a redirect to your client, telling it to go and fetch the video chunk/stream from https://streaming.acme.com:port/something/emby/videos/xxx It should hopefully look something like this Why would I go to this trouble? Here is why I think this makes sense 99% of requests will go through Cloudflare, where you can layer on world class security options - you don't need to rely solely on Emby and the development team for security, put a fantastic authentication system & WAF in-front of it. This includes your authentication, requests to delete media and admin operations (These requests benefit from caching) You don't stream the video through Cloudflare - this was our compromise with this design. You are now exposing your nginx service directly to the world, however you may have to do that anyway if you don't want to stream through Cloudflare. Plus you can further protect yourself from autonomous/widespread attacks* You can use all of the Cloudflare security and other features to protect your Emby instance - I am assuming you want to have an easily recognizable URL & use port 443 for ease of use, so now you can do this and then have the Cloudflare firewall and other security features between the client and your service. In my CF redirect, I change the port to a random port number that I then open on my router* In my Nginx service, I drop any request immediately that is not a request to stream an Emby video file (e.g. the login page or any other API/page) If you look in my configuration, I lifted /emby/video off the root location and inserted a `something` - I was exploring injecting a Cloudflare access token as a query string but for now I just added a random base64 encoded string so that streaming.acme.com/emby is not a valid path.* I'm pretty new at Cloudflare, but I'm positive there are a couple of other clever things you cand do, e.g. you could block connections from certain countries, put your friends on an allow-list and block everyone else, or find other creative things to do. * Some people may look at using a random port number or having a random string injected into the path as not that secure, which may be right in some context, however since we don't have complete control over the Emby clients (to setup client certificates or integrate with a real IDP), and since I am focused on being safe from widespread flaws affecting Emby, or the webstack that they build on, or the logging framework they use, or some flaw in some other library, all I need to do for now is make this a pain for anyone to try and exploit. It may not stand up against some state sponsored hackers, but I'd be surprised if you fall victim to a widespread malware dropping activity as part of a critical flaw. Would this have saved me from the two earlier attacks I honestly couldn't answer this right now, it's possible the answer is no, but I am in my infancy with my Cloudflare setup and confident that with a few tweaks (limiting countries, suspicious request blocking) then I will be more confident in the future. Most of all, I would love a way from the Emby client to authenticate securely with a service like Cloudflare - a username and password being sent to the Emby service is nice but as we see flaws that negate this type of authentication, I'd rather try and put Cloudflare or another industry leading provider as my 1st line of defense rather than rely solely on the small teams building the software I enjoy running at home (no offense Emby Team) My goal initially was to move away from hosting Emby directly via my router/home connection, and onto Cloudflare which I believe I have accomplished with a compromise I can live with for now - as I actually get time to spend with Cloudflare I hope to be able to come back and say that I have more confidence that Cloudflare would help avoid attacks in the future. 8
Gilgamesh_48 1130 Posted April 15, 2024 Posted April 15, 2024 While Emby is mentioned this is NOT about Emby. It should be moved to the general discussion area. It also seem totally unnecessary but that is just my judgement and others might disagree. 1
HorsePDF 11 Posted April 15, 2024 Author Posted April 15, 2024 Hi @Gilgamesh_48 How is this not about Emby? I've posted this in the same place as numerous other posts about setting up Emby with Cloudflare, Nginx, or other hosting layers, that are pinned to this very forum. Re: second point, it's possible that you are not the target audience for this (I'm not sure that's worth vocalizing though).
vaise 331 Posted April 15, 2024 Posted April 15, 2024 That's a cool way of getting around the video streaming 'issue'. I personally have not been banned yet - I have no idea why - 400-600GB/month - been using for many years on the free plan. I have my nginx waiting there to take over with a quick dns change and port opening - if I ever get banned. Your solution does mean re-opening a port on my firewall/router - which is the main benefit of tunnels IMHO. But apart from that, I think this is really good - albeit a bit complicated for many emby users. I will add it to my task list to implement later - once I get my new router that will have more advanced security - my exiting one cant do IPS/IDS for more than 100Mbps - and I have a GB connection now, so turned that off.
Wane2506 1 Posted May 25, 2024 Posted May 25, 2024 Hi @HorsePDF How do I find out that it's working? i run emby without nginx. are my settings correct?
vaise 331 Posted June 10, 2024 Posted June 10, 2024 (edited) On 25/05/2024 at 17:01, Wane2506 said: Hi @HorsePDF How do I find out that it's working? i run emby without nginx. are my settings correct? I think you have ld instead of Id in that URI Query String - @HorsePDFmay need to clarify that a bit - it is a CAPITAL I (as in eye) in the Id, not L as in elle. As to you NOT using nginx, I thing you are stuffed as you cant do the nginx rewite which is half the config here - you cant sdo this process if you just use CF to direct directly to emby. Edited June 10, 2024 by vaise
rbjtech 4996 Posted June 13, 2024 Posted June 13, 2024 Thanks @HorsePDFfor taking the time to write that up. I use my own direct connection, with my own perimeter defences (fw,ips/ids,nginx rp,dmz etc)and to be fair, see very little 'probing' on the NMS but I'm thinking like you, and ideally want the extra mature layer of protection CF gives - and the split traffic approach seems a good way to do this. I'm going to experiment when I get some time - thanks for the ideas !
rbjtech 4996 Posted June 13, 2024 Posted June 13, 2024 (edited) On 16/04/2024 at 00:56, vaise said: I will add it to my task list to implement later - once I get my new router that will have more advanced security - my exiting one cant do IPS/IDS for more than 100Mbps - and I have a GB connection now, so turned that off. I would suggest maybe building your own using a hardened OS + the NGFW of your choice. That way you are in control of how much cpu you can give it and how many/how fast you want the interfaces.. IPS/IDS are notorious for needing fast single pipeline processing - I'm running 1Gig internet using IPS/IDS using an old Gen 3 - 3.0Ghz Intel i3 I had spare - it runs at ~10% cpu at max throughput - so well over spec'd - I could probably get away with a slower celeron in there, it's not power hungry as it's barely in use for day to day ops. Edited June 13, 2024 by rbjtech
horstepipe 377 Posted July 12, 2024 Posted July 12, 2024 thanks for sharing! I am wondering... why is a second server block being needed, shouldn't a second location block inside one server block be okay, too? what are the advantages/disadvantages of these setups?
atropa 10 Posted July 14, 2024 Posted July 14, 2024 Could someone share the full ngix.conf file with this working setup? Anonymized, of course. Then you just have to change the domain. That would be helpful
HorsePDF 11 Posted July 14, 2024 Author Posted July 14, 2024 On 7/12/2024 at 10:59 AM, horstepipe said: I am wondering... why is a second server block being needed, shouldn't a second location block inside one server block be okay, too? what are the advantages/disadvantages of these setups? I am not entirely sure what you mean by second server block, but perhaps the reason I had it setup like this is because I have two different URLs coming through nginx with different settings, one is for streaming the media, and the other is for delivering everything else (APIs, web traffic, thumbnails etc.). They listen on two different ports, so this may be why I have it configured this way, this is more to do with my internal network setup I think than a requirement. If you know nginx better than I do then see what works for you :) 1
HorsePDF 11 Posted July 14, 2024 Author Posted July 14, 2024 Here is most of my emby config. I also have more that is not relevant to the external access - these two blocks are the two that are described in my post. I used a standard recommended config I found on the forum a long time ago as my base which is what I have modified. ##This is the main entrance to Emby externally. server { listen 12345 ssl; ## Listens on port XYZ IPv4 with http2 and ssl enabled proxy_buffering off; ## Sends data as fast as it can not buffering large chunks. server_name media.yoursite.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 /run/secrets/FULLCHAIN; ssl_certificate_key /run/secrets/PRIVKEY; ssl_session_cache shared:SSL:10m; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location ^~ /swagger { return 404; } location / { ## Setting the URL of the backend server via a variable like this means nginx will not crash if the backend server is down at startup set $emby_url http://emby:8096; ## Enter the IP and port of the backend emby server here. proxy_pass $emby_url; proxy_hide_header X-Powered-By; 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; } } ## PUBLIC STREAM ENDPOINT ## ## This is the public endpoint that will be used to stream media from the emby server, all other requests will go through the private endpoint. server { listen 23456 ssl; proxy_buffering off; ## Sends data as fast as it can not buffering large chunks. server_name media-stream.yoursite.com; ## SSL SETTINGS ## ssl_session_timeout 30m; ssl_protocols TLSv1.2 TLSv1.1 TLSv1; ssl_certificate /run/secrets/FULLCHAIN; ssl_certificate_key /run/secrets/PRIVKEY; ssl_session_cache shared:SSL:10m; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; ## Since this endpoint is accessible without protections from Cloudflare, I shifted the location so that ## it is not in a default location if there is ever a vulnerability with Emby that people scan for ## we will reject any requests to other locations in Emby, so that the login screen and pretty much everything else is not accessible. location ~* ^/RANDOM_LOCATION_HERE/emby/videos/(.*)$ { set $emby_url http://emby:8096; ## Enter the IP and port of the backend emby server here. rewrite ^/RANDOM_LOCATION_HERE/emby/videos/(.*)$ /emby/videos/$1 break; proxy_pass $emby_url; proxy_hide_header X-Powered-By; 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 emby.buddycloud.net; ## 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; } location / { return 444; # Close connection immediately } } 1
HorsePDF 11 Posted July 14, 2024 Author Posted July 14, 2024 (edited) Coming back to this post I had a realization, I was away recently and downloaded converted media to my phone over the internet. I had not considered this, so there is another rule you would need to get downloads going through this mechanism, probably something under /emby/Sync/JobItems/# From my CloudFlare Dashboard: Edited July 14, 2024 by HorsePDF
Wane2506 1 Posted July 14, 2024 Posted July 14, 2024 I have successfully configured it, thank you for sharing the nginx configuration. how do I know that this has successfully redirected traffic from Cloudflare to nginx???
vaise 331 Posted July 26, 2024 Posted July 26, 2024 On 15/07/2024 at 02:46, Wane2506 said: I have successfully configured it, thank you for sharing the nginx configuration. how do I know that this has successfully redirected traffic from Cloudflare to nginx??? Look at your hourly/daily/monthly CF usage. I was 600-800GB, now a fraction of that.
vaise 331 Posted July 26, 2024 Posted July 26, 2024 On 14/07/2024 at 23:22, HorsePDF said: Coming back to this post I had a realization, I was away recently and downloaded converted media to my phone over the internet. I had not considered this, so there is another rule you would need to get downloads going through this mechanism, probably something under /emby/Sync/JobItems/# From my CloudFlare Dashboard: Hi @HorsePDF- I was wondering what these random 'jumps' were on the CF usage I was seeing. I suspected it was my sone doing downloads to his iphone as he lives away now. Can I ask how you got that list in the CF dashboard ? I thought the free plan did not give me such insight.
vaise 331 Posted July 26, 2024 Posted July 26, 2024 (edited) On 14/07/2024 at 23:22, HorsePDF said: Coming back to this post I had a realization, I was away recently and downloaded converted media to my phone over the internet. I had not considered this, so there is another rule you would need to get downloads going through this mechanism, probably something under /emby/Sync/JobItems/# From my CloudFlare Dashboard: Hi @HorsePDF, in addition to my question on where you found this list on cloudflare dash, I implemented anyway with a CF redirect on /emby/Sync/JobItems/ and the corresponding nginx listen on /emby/sync/jobitems/ - but the downloads never start - they are stuck at ready to transfer (I have unticked for only wifi). Further to this, I tried just /emby/Sync and that was even worse - as it breaks the download button on the iphone - it does nothing. I will keep working on this, but I look forward to your response. May have something to do with this in the log that happens after clicking download : 2024-07-26 14:52:42.430 Warn Server: AUTH-ERROR: 120.22.125.234 - Access token is invalid or expired. 2024-07-26 14:52:42.430 Error Server: Access token is invalid or expired. Edited July 26, 2024 by vaise
HorsePDF 11 Posted July 26, 2024 Author Posted July 26, 2024 @vaisethe dashboard I showed is part of the paid plan I think. I bought it for this dashboard plus a few other things like better WAF features. I'll try have a look at it soon. It may be more complicated, the streaming seems to be pretty stateless so it's easy to redirect. If the download jobs are using a sync framework, it may be much harder. One thing to note, Cloudflare may care less about you downloading vs streaming, I don't know. There may not be a difference fundamentally for them, but they may target streaming users because that's not what they want to be hosting. Not sure on that
vaise 331 Posted July 28, 2024 Posted July 28, 2024 @HorsePDF- only free plan for me. unfortunate. I would love to know what these bumps are : I have disabled downloads for all users, so thats not it. So strange - a few megas an hour, then 977MB at 7PM last night, then 334MB at 10PM. Trawled emby logs but nothing I can see. I am thinking there is something other that /emby/video going on here and still going through CF.
vaise 331 Posted July 28, 2024 Posted July 28, 2024 Found something in log : 2024-07-28 19:02:09.752 Info Server: http/1.1 Response 206 to 122.199.13.186. Time: 271764ms. GET http://emby.mydomain.com/videos/70782/original.mkv?DeviceId=E14F65CC-04F2-4400-BEDD-D53829056BAA&MediaSourceId=bf29aaaf9e47d4a61bb471f288fe30a4&PlaySessionId=50c83dbc92c146b0b379074ca90b1d78&api_key=f4148b72273343549ec867bc4451a456 That's like 5 minutes on a URL that would still go through CF as its not being redirected. A search through the logs for emby.mydomain.com/videos finds a few others also - around this time. @Lukeany idea what here is NOT following the normal /emby/ part of the url path ? Is it transcoded content or something special ? I
vaise 331 Posted July 29, 2024 Posted July 29, 2024 2 hours ago, Luke said: Everything from emby apps should be. Are you saying some devices could use /Video instead of /emby/Video ?
Luke 40082 Posted July 29, 2024 Posted July 29, 2024 1 minute ago, vaise said: Are you saying some devices could use /Video instead of /emby/Video ? I don' think so, not from an emby app at least.
vaise 331 Posted July 29, 2024 Posted July 29, 2024 As per my log above, something out there is using just /Video. Some type of playback method or some type of device. I will try and narrow it down.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now