The following Wiki article will take you through how to Set up a CDN for Plex with CloudFlare & NGINX.
Difficulty: Moderate
Requirements:
- A second IP (can be done with one, but not the scope of this guide)
- A domain
- A free CloudFlare account
Caveats: CloudFlare has the effect of forcing certain levels of TLS encryption on the client. Older clients (such as some SmartTVs) do not support the minimum level of TLS required by CloudFlare, and may prevent them from being able to connect to the server. You can bypass this by rolling your own proxy where you control the level of security.
I modified this a bit from the github entry posted here along with the corresponding post on Reddit. This may take a good amount of time to setup, so make sure your read through and understand the instructions before starting! Sure this might be a bit convoluted and setting up apache and nginx to work aside each other is a bit of a pain, but with QuickBox utilizing Apache and Plex not playing well with it, there are few options.
Once you understand what’s involved, grab a cup of coffee and let’s get to work!
Sign up for CloudFlare
The first step is to sign up with an account at CloudFlare and move the nameservers of your domain over to the one’s provided during CloudFlare’s setup. Once CloudFlare is setup, make sure you add your failover IP to a new subdomain, i.e. plex.yourdomain.com. Until we setup Let’s Encrypt for the subdomain, ensure server traffic is not being routed through CloudFlare just yet. (grey icon) Further, under the crypto tab, ensure SSL is set to either Full or Full (Strict)
Add a second IP to your server
As your new nameservers propagate throughout the network, take this time to bring up the second IP on your server. We need this second IP to bind an instance of NGINX to, so that there are no conflicts with our currently running Apache server. If you want to reverse proxy apache through nginx, you could run this all off a single IP, but that won’t be covered here.
The setup of an IP may vary from host to host; however for a dedicated machine running Ubuntu, this method should work for most. A failover ip can be brought online by editing the file /etc/network/interfaces to bring a new ip address online for your network interface.
sudo nano /etc/network/interfaces
Insert at the bottom of interface eth0 (before ipv6 if your server supports it). Replace IP.OF.FAIL.OVER with the IP you were given by your provider and replace eth0 with the name of your adapter if necessary (e.g. enp2s0):
up ip addr add IP.OF.FAIL.OVER/32 dev eth0
down ip addr del IP.OF.FAIL.OVER/32 dev eth0
Save and exit. Bring the new interface online with the command
ip addr add IP.OF.FAIL.OVER/32 dev eth0
You should now be able to ping your new IP. Confirm with a local test: ping IP.OF.FAIL.OVER If your new IP fails to respond to ping, consider consulting your host’s documentation for help.
Bind Apache to the main IP of your server
If you don’t know the IP address of your server you can attempt to be lazy and grab it with this one-liner:
sudo ifconfig | grep -m1 "inet addr" | cut -d: -f2 | cut -d" " -f1
If that doesn’t work, check the email that your host sent you :sweat_smile:
Now we need to edit two files in apache to prevent Apache2 from binding to all available interfaces:
sudo nano /etc/apache2/ports.conf
It should look something like this:
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf
Listen 80
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
Alter the file as such:
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf
Listen ORIG.IP.OF.SRV:80
<IfModule ssl_module>
Listen ORIG.IP.OF.SRV:443
</IfModule>
<IfModule mod_gnutls.c>
Listen ORIG.IP.OF.SRV:443
</IfModule>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
Save, exit and load up the next file:
sudo nano /etc/apache2/sites-enabled/default-ssl.conf
Find the sections where it says <VirtualHost *:80> and <VirtualHost *:443>. Replace the asterisks with the ORIG.IP.OF.SRV:
...
<VirtualHost ORIG.IP.OF.SRV:80>
...
<VirtualHost ORIG.IP.OF.SRV:443>
Now, stop Apache2.
sudo systemctl stop apache2
Install NGINX, Let’s Encrypt and bind to the failover IP
Start by installing nginx:
sudo apt update
sudo apt install nginx
Also, if you do not have Let’s Encrypt installed, now would be the time to do that
sudo apt install letsencrypt
Now, we need to alter nginx to bind to our new IP and also connect with the Let’s Encrypt servers so that they can issue you an SSL certificate.
sudo nano /etc/nginx/sites-enabled/default
Underneath the block you should see
server {
listen 80 default_server;
Insert your failover IP and the .well-known location for Let’s Encrypt:
server {
listen IP.OF.FAIL.OVER:80 default_server;
location ~ /.well-known {
allow all;
}
Save and exit. Run the command sudo nginx -t to ensure your configuration is valid. If yes, hooray! Let’s take this opportunity to restart nginx and bring our apache2 server back online.
sudo systemctl restart nginx
sudo systemctl restart apache2
Ensure there are no conflicts and both services are currently running (systemctl status apache2 & systemctl status nginx)
Now we can use Let’s Encrypt to grab an SSL certificate. Make sure your DNS is pointing at your failover (and not through cloudflare)
sudo letsencrypt certonly -a webroot --webroot-path=/var/www/html -d plex.yourdomain.com
If all goes well you now have shiny new SSL certs for plex.yourdomain.com.
Now we will beef up security just a bit more:
sudo bash
cd /etc/letsencrypt/live/plex.yourdomain.com/
Check the issuing authority of your certificate as per: source
sudo openssl x509 -noout -text -in fullchain.pem | grep Issuer:
You’ll see something like:
Issuer: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3
Download the corresponding pem:
wget -O chain.pem "https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem"
Change x3 if necessary to correlate to the authority who issued your certificate.
Now we will generate a dhparam for nginx
mkdir -p /etc/nginx/ssl
cd /etc/nginx/ssl
openssl dhparam -out dhparam.pem 2048
We now have everything we need to configure our Plex Reverse Proxy:
cd /etc/nginx/sites-enabled
wget -O plex.conf https://raw.githubusercontent.com/toomuchio/plex-nginx-reverseproxy/master/nginx.conf
Now we must alter the file to include our failover IP, ssl certificates and dhparam.
nano plex.conf
Find and insert your failover IP into the two listen parameters
listen 80;
listen 443 ssl http2;
becomes
listen IP.OF.FAIL.OVER:80;
listen IP.OF.FAIL.OVER:443 ssl http2;
Next find:
ssl_certificate
ssl_certificate_key
Insert your letsencrypt certificates here:
ssl_certificate /etc/letsencrypt/live/plex.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/plex.yourdomain.com/privkey.pem;
Now add our trusted certificate (chain.pem):
ssl_trusted_certificate /etc/letsencrypt/live/plex.yourdomain.com/chain.pem;
And the dhparam a bit further down:
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
That’s all the edits we need to make to this file so save and exit. Test your config and cross your fingers!
nginx -t
If all goes well, start your server
systemctl start nginx
Now your Plex should be accessible via https://plex.yourdomain.com
Alter your Plex Server settings
Make sure “Show Advanced Settings” is on. Under the Network tab add a custom access url:
https://plex.yourdomain.com:443
Under Remote Access, disable remote access
Update firewall to prevent external pinging of port 32400
iptables -A INPUT -p tcp -s localhost --dport 32400 -j ACCEPT
iptables -A INPUT -p tcp --dport 32400 -j DROP
The first rule ensures our localhost is still able to talk with Plex. This allows our proxy to communicate, with the internal server, but the second rule prevents all other access. As such, you should still be able to access your plex installation from both plex.tv/web/app and plex.yourdomain.com. Confirm you are able to, then once you have, ensure these rules stay persistent upon a reboot with iptables-persistent:
apt install iptables-persistent
Choose yes during installation to save your current iptables (note if you have any fail2ban rules, they may get included in here. Make sure you have no firewall rules you don’t want to save, though you can remove unintentional additions if needed.
At this point, no data should be served from your server via port 32400 and all traffic should flow exclusively through port 443 (you can verify this with tcptrack – your server will not establish connections via port 32400 during playback though it will try- SYN_CONNECT).
Enable CloudFlare CDN for plex.mydomain.com
Change over that grey cloud icon to the orange one!
Your data is now being proxied through CloudFlare’s servers. Congratulations!! Once the DNS switches over to your CloudFlare IP you should see a noticeable improvement in your speeds and jitter.
Please note this may not be perfect – I will do my best to answer questions and update and errors in the guide. Please let me know if you run into issues!
If you’re worried about sending all of your data through cloudflare, the same basic principle could apply to a VPS such as Linode, Vultr or other.
Difficulty: Moderate
Requirements:
Caveats:
CloudFlare has the effect of forcing certain levels of TLS encryption on the client. Older clients (such as some SmartTVs) do not support the minimum level of TLS required by CloudFlare, and may prevent them from being able to connect to the server. You can bypass this by rolling your own proxy where you control the level of security.
I modified this a bit from the github entry posted here along with the corresponding post on Reddit. This may take a good amount of time to setup, so make sure your read through and understand the instructions before starting! Sure this might be a bit convoluted and setting up apache and nginx to work aside each other is a bit of a pain, but with QuickBox utilizing Apache and Plex not playing well with it, there are few options.
Once you understand what’s involved, grab a cup of coffee and let’s get to work!
1. Sign up for CloudFlare
The first step is to sign up with an account at CloudFlare and move the nameservers of your domain over to the one’s provided during CloudFlare’s setup. Once CloudFlare is setup, make sure you add your failover IP to a new subdomain, i.e. plex.yourdomain.com. Until we setup Let’s Encrypt for the subdomain, ensure server traffic is not being routed through CloudFlare just yet. (grey icon) Further, under the crypto tab, ensure SSL is set to either Full or Full (Strict)
2. Add a second IP to your server
As your new nameservers propagate throughout the network, take this time to bring up the second IP on your server. We need this second IP to bind an instance of NGINX to, so that there are no conflicts with our currently running Apache server. If you want to reverse proxy apache through nginx, you could run this all off a single IP, but that won’t be covered here.
The setup of an IP may vary from host to host; however for a dedicated machine running Ubuntu, this method should work for most. A failover ip can be brought online by editing the file
/etc/network/interfacesto bring a new ip address online for your network interface.Insert at the bottom of interface eth0 (before ipv6 if your server supports it). Replace IP.OF.FAIL.OVER with the IP you were given by your provider and replace eth0 with the name of your adapter if necessary (e.g. enp2s0):
Save and exit. Bring the new interface online with the command
You should now be able to ping your new IP. Confirm with a local test:
ping IP.OF.FAIL.OVERIf your new IP fails to respond to ping, consider consulting your host’s documentation for help.
3. Bind Apache to the main IP of your server
If you don’t know the IP address of your server you can attempt to be lazy and grab it with this one-liner:
If that doesn’t work, check the email that your host sent you
Now we need to edit two files in apache to prevent Apache2 from binding to all available interfaces:
It should look something like this:
Alter the file as such:
Save, exit and load up the next file:
Find the sections where it says
<VirtualHost *:80>and<VirtualHost *:443>. Replace the asterisks with the ORIG.IP.OF.SRV:Now, stop Apache2.
4. Install NGINX, Let’s Encrypt and bind to the failover IP
Start by installing nginx:
Also, if you do not have Let’s Encrypt installed, now would be the time to do that
Now, we need to alter nginx to bind to our new IP and also connect with the Let’s Encrypt servers so that they can issue you an SSL certificate.
Underneath the block you should see
Insert your failover IP and the .well-known location for Let’s Encrypt:
Save and exit. Run the command
sudo nginx -tto ensure your configuration is valid. If yes, hooray! Let’s take this opportunity to restart nginx and bring our apache2 server back online.Ensure there are no conflicts and both services are currently running (
systemctl status apache2&systemctl status nginx)Now we can use Let’s Encrypt to grab an SSL certificate. Make sure your DNS is pointing at your failover (and not through cloudflare)
If all goes well you now have shiny new SSL certs for plex.yourdomain.com.
Now we will beef up security just a bit more:
Check the issuing authority of your certificate as per: source
You’ll see something like:
Download the corresponding pem:
Change x3 if necessary to correlate to the authority who issued your certificate.
Now we will generate a dhparam for nginx
We now have everything we need to configure our Plex Reverse Proxy:
Now we must alter the file to include our failover IP, ssl certificates and dhparam.
Find and insert your failover IP into the two listen parameters
becomes
Next find:
Insert your letsencrypt certificates here:
Now add our trusted certificate (chain.pem):
And the dhparam a bit further down:
That’s all the edits we need to make to this file so save and exit. Test your config and cross your fingers!
If all goes well, start your server
Now your Plex should be accessible via https://plex.yourdomain.com
5. Alter your Plex Server settings
Make sure “Show Advanced Settings” is on. Under the Network tab add a custom access url:
Under Remote Access, disable remote access
6. Update firewall to prevent external pinging of port 32400
The first rule ensures our localhost is still able to talk with Plex. This allows our proxy to communicate, with the internal server, but the second rule prevents all other access. As such, you should still be able to access your plex installation from both plex.tv/web/app and plex.yourdomain.com. Confirm you are able to, then once you have, ensure these rules stay persistent upon a reboot with iptables-persistent:
Choose yes during installation to save your current iptables (note if you have any fail2ban rules, they may get included in here. Make sure you have no firewall rules you don’t want to save, though you can remove unintentional additions if needed.
At this point, no data should be served from your server via port 32400 and all traffic should flow exclusively through port 443 (you can verify this with tcptrack – your server will not establish connections via port 32400 during playback though it will try- SYN_CONNECT).
7. Enable CloudFlare CDN for plex.mydomain.com
Change over that grey cloud icon to the orange one!
Your data is now being proxied through CloudFlare’s servers. Congratulations!! Once the DNS switches over to your CloudFlare IP you should see a noticeable improvement in your speeds and jitter.
Please note this may not be perfect – I will do my best to answer questions and update and errors in the guide. Please let me know if you run into issues!
If you’re worried about sending all of your data through cloudflare, the same basic principle could apply to a VPS such as Linode, Vultr or other.
Why is it bad for sharing?
If you look at the reddit comments you see people using it for media players and not just web:
https://www.reddit.com/r/PleX/comments/5ni728/plex_with_nginx_better_performance_and_everything/dchh8y9
Perhaps you have that CF setting set wrong?
I have QB in a lxc container now as I work my way out of QB and into a full docker config. I use nginx as the reverse proxy for the Dockers so I’ll try to give this a go in that config shortly.
I use an OVH server in France. Without the CDN enabled, I usually pull down speeds between 400-1800kb/s from my server. When routed through CloudFlare, Plex rockets to 8MB/s-15MB/s. This translates to insanely faster buffering (most lower bitrate files start within a second) as well as reduced jitter (no random dropouts during streaming).
For me the difference is night and day. Higher bitrate files (eg 20mbps) were not doable (or only under optimal circimstances, but the network would typically change before I was done watching an hour long file). I have no issues now.
Some may see improvements simply with the reverse proxy and not routing their data through CF, though the benefits of CF are very clear in my case – I simply don’t see saturated links at any hour of the day at my location from an OVH France server.
Edit: And you are completely right – it is convoluted. This would be significantly less so if QB ran off nginx (which is a thought kicking around somewhere in the back of my head)
you forgot an n, im setting up now and got to that step and noticed
on a side note, if i just activated my 2nd ip minutes before doing this guide will it take a little bit before https://plex.mydomain.com works? i followed step by step and both nginx -t tests showed settings working but i am unable to load the url. im not too technical with domain stuff.
This is related to DNS propagation. It may take a bit of time to get it going. I prefer to use a shorter TTL (time to live) in these circumstances (5 minutes or so) as it helps propagate the change throughout the DNS servers faster. As long as ping is up on the IP, it should propagate through the network eventually.
thanks everything is working here, will have to test out some devices now!
I look forward to your results!
CloudFlare is the CDN – they are the one responsible for routing your data over a faster network and making the server appear much closer to you geographically speaking. Ping to server without CloudFlare: 160ms. With CloudFlare: 15ms. Using them as a proxy server will change the routing of your data to one that hopefully is much better connected than the one provided solely by your DC/ISP.
It would be the same idea as using a VPN (or reverse proxy) to improve speeds.
Ah! I forgot I have a Samsung SmartTV too (far prefer the Roku myself). I can’t even communicate with the plex website to login to my account right now. Do you have any other servers (shares or otherwise) on your account to verify it is localized to the proxied server? I have a feeling something fishy is going on with the login portal at the moment.
local server and a remote server setup regular work, but the CF setup is not working on a 2015 JS model. my friend is having no issues playing on his KS (2016) model samsung which uses a different app (new style like roku/xbox). I am thinking there are limitations on this outdated app?
the roku is nice, but I prefer to be a 1 remote kind of guy especially when I am laying in bed.
im thinking i will probably just roll back the changes all together, i have a hetzner box and dont have any issues streaming just have 5-6 second load time loading some files was hoping this would alleviate it but seems to cause more issues than its worth to figure them out! did not notice any decrease when pinging the server with cf enabled and disabled, its always 135ms average.
but it was nice to run through it and have it actually working for the most part
Another quick question. What settings are needed to make Plexpy work again with this setup? I can’t figure that out just yet.
I have finally gotten this to work. I can immediately tell a difference in speed from what I’ve been dealing with! Loading is significantly faster and the constant buffering issues I was dealing with seem non-existent. Thanks for the help and thanks for the wiki!
thanks a bunch for this guide Liza, worked perfectly my first attempt and my peering is SO SO much better/quicker
Could be a potentially incorrectly setup plex.conf but it could also be an issue through CloudFlare – did you make sure to change the SSL type in your CF panel to at least full or full (strict)?
Nothing should be affected at all in the apache configuration, all we do is change the IP we bind to nothing else. The “Connection is not Private” error is in relation to a self-signed certificate or a certificate for a domain that is assigned to another domain than the one in use.
That warning message is just a warning and wouldn’t affect anything in your setup.
The Samsung TV is a known issue with CloudFlare proxy (see the note in the top paragraphs), in order to remove the rule permanently edit the file /etc/iptables/rule.v4 to prevent the rule from being applied at start up.
The first thing to do is check whether or not your plex.conf contains a forward block so that all traffic to port 80 is redirected to port 443.
The old version of the conf has this block:
If your file has this, we want to move the listen parameter in this block to the next (main) server block then remove this server block.
Cut
And paste it right above the line
Then remove the old server block entirely:
Save the changes and exit.
Remove the file /etc/nginx/sites-enabled/default.
Restart nginx
Finally in plex, add a second custom access url
Make sure in network connections in Plex that SSL connetections are not set to required.
This should allow clients to access plex via http rather than https and will let clients such as Samsung SmartTVs and PS4s connect to the proxy (albeit insecurely)
I’m hesitant to add this to the main tutorial because I’m unsure of how this will affect future renewals of letsencrypt because we are effectively removing the webroot by deleting the default conf.
If this is too confusing, feel free to PM me and we can discuss options.
so i got this working but didnt do letsencrypt for my original domain. i have the ip forwarded and can access quickbox from other subdomain and plex from plex subdomain but can’t get a certificate for quickbox sub domain now following other guides instructions?
i ended up getting it to work by using acme.sh and using the cloudflare dns option then editing the default-ssl.conf for apache to point to these certs. Now im certified for both my quickbox subdomain and plex subdomain
I was succesful with all the steps until this:
“Now your Plex should be accessible via https://plex.yourdomain.com”
I can connect to my site https://plex.mysite.com and 443 but not 80. None of this is going to the plex manage page though.
I’ve continued through the rest of the steps but plex.tv not able to find my server.
I’ve gone back to the steps about installing nginx and installing letsencrypt.
I saw that @cackai2 encountered a similar issue but he was able to fix it by creating the proper SSL cert, because he forgot to put his domain name. I had done this step correctly in the first place.
I’d appreciate some help.
Update: (Fixed) *resolved:
Fixed it by doing the ssl cert properly.
My plex.yourwebsite.com was activated on cloudflare already prior to me initiating those steps. I had turned the cloud to grey (DNS mode only) and redid this step.
Update/Problem 2:
Now I am able to go to http:// plex.yourdomain.com and get to plex. When I try plex.tv, able to find my server sporadically.
When I turn on cloudflare, it doesn’t find it anymore within plex. Any idea?
Update 3: Figured it out. It was because for some reason cloudflare SSL type not set to FULL. On PC Chrome – I can see it as FULL from the moment I signed up for an account, but i decided to check on my phone’s browser and saw it was set to “flexible”. Changed it on the phone to “FULL” and now it’s working.
I have the same connection issue as @dtech (Chrome or FF) and also have issues playing back media from firestick,chrome and android client from time to time. I get a lost connection to plex media server … Retry or cancel and have to hit retry anywhere from 1 – 4 times before my media will play. I’m guessing this is somehow a timeout problem, just hoping someone can shed some light on this.