Jump to content

How I host via Cloudflare Tunnels, but don't stream video through it


HorsePDF

Recommended Posts

HorsePDF

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:

image.png.c7759ce48a3ddb4827c1171fd5da1e27.png

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 

image.png.ef8e678af6489f76eb5efed5e835b750.png

Now redirect that traffic to a new location

image.png.acbaa43f8d769535e2f9e0c9cf8afcc4.png

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

image.thumb.png.5278b9c69b988454e26c4809e0c4d8b8.png

Why would I go to this trouble?

Here is why I think this makes sense

  1. 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)
  2. 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*
    1. 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.
    2. In my CF redirect, I change the port to a random port number that I then open on my router*
    3. 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)
    4. 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.*
    5. 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.

  • Thanks 2
Link to comment
Share on other sites

Gilgamesh_48

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. :( 

  • Disagree 1
Link to comment
Share on other sites

HorsePDF

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).

Link to comment
Share on other sites

vaise

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.

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...