Jump to content

Cloudflare + nginx + Emby (Windows)


Go to solution Solved by Luke,

Recommended Posts

JasonNalley
Posted (edited)

So, lots of people get confused or don't understand how to set this up on your own domain.  I will try my best to provide "how to" information in here where necessary, but to be fair, a lot of this I adapted from various online posts about nginx and also used ChatGPT for help (you should totally use it for Q&A issues, it's very helpful and can give you a huge leg-up when trying to set this up).  I will also assume you understand the basic principals of what is going on.  This combination provides you with piece of mind, end-to-end encryption for you and your users, faster load times, etc.

Cloudflare’s free tier offers significant benefits. Cloudflare provides DDoS protection, reducing the risk of service outages due to attacks, and includes a Web Application Firewall (WAF) to block malicious traffic. Additionally, it improves site load speeds through caching and content delivery network (CDN) services, which distribute content across global servers, enhancing response times. Using Cloudflare with Nginx also allows for easy SSL/TLS encryption management, adding a critical layer of security without manual certificate renewal. This combo optimizes performance, security, and scalability.

Using Nginx together with Cloudflare provides a more robust and secure setup by leveraging the strengths of both. Cloudflare’s CDN and DDoS protection shield your network from malicious traffic and improve loading times, but it doesn’t handle every aspect of server management. Nginx provides fine-grained control over caching, authentication, and local load balancing, allowing you to customize how requests are processed and resources are served. Together, they offer enhanced performance, security, and reliability, with Cloudflare filtering threats and Nginx managing local configurations and fine-tuned responses.

Setting up cloudflare is pretty easy and mostly self-explanatory for initial setup.  You may want to take the time to go through all of the different settings for your domain within the cloudflare panel, read each one to understand what it does, and ask ChatGPT for anything you're unsure of.  The user-interface is very intuitive, and there's even a video on how to use your gmail account with cloudflare to provide a user@yourdomain.com experience completely free, so you can send and receive e-mail from your domain without any extra charges.  It's super easy to setup, and only requires that your gmail account has 2FA enabled.  Here's the video in question (The guy is a bit wordy, and takes his time, repeating himself several times, so I apologize ahead of time, but, it works like a dream).  This is especially handy for services like Ombi where you can communicate with your users through e-mail with password reset links and the like.


Cloudflare offers so many options for security that a write-up would take me ages, so I'm going to skip that, the key things you'll need going forward are SSL/TLS certificates from Cloudflare which you can find in the SSL/TLS section of your domain dashboard.  Save the certificate as a .crt file, and the key as a .key file (.pem works for both, just make sure you label which is which).  Save them to your nginx installation, I have mine in C:\nginx\conf\ssl  (you must create the ssl folder). 

If you've made it this far, I will assume you've setup cloudflare with your domain, enabled the security the way you want it setup, grabbed your certificates, and are now looking for how to integrate that with your nginx/emby setup.  The nginx walkthrough in these forums is pretty good, but it was also written 7 years ago, and there are some new technologies and new best practices that you should implement in your .conf files.  Go ahead and use that walkthrough to setup nginx and get it up and running (I still use nssm to have it run as a service).

Here's an example of a robust and secure nginx.conf file:
 

worker_processes auto; #lets nginx decide how many cores/threads to use on your processor

events {
    worker_connections 2048; #change as needed for your traffic,  2048 us a good starting point for low traffic environments, moving it up will devote more resources
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile      on;
    keepalive_timeout 65;

    # Extended gzip settings
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml application/font-woff application/font-woff2 font/ttf font/otf font/eot;
    gzip_min_length 1000;
    gzip_vary on;
    gzip_comp_level 6;
    gzip_proxied any;
    gzip_buffers 16 8k;

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; #enables a request limit, so each IP address accessing your server can only make 1 request per second, it's useful for preventing request floods
	    
	# Redirect HTTP to HTTPS for Emby subdomain
    server {
        listen 80;
        server_name your.domain.here;	#Update with your domain
        return 301 https://$host$request_uri;
    }

    # HTTPS server block for Emby subdomain
    server {
        listen 443 ssl;
        server_name your.domain.here;  #Update with your domain

        ssl_certificate      /your/ssl/certificate/file.pem/crt;	#Update with your ssl certificate file
        ssl_certificate_key  /your/ssl/key/file.key/pem;	#Update with your ssl certificate file
        ssl_session_timeout 30m;
        ssl_protocols TLSv1.2 TLSv1.3;	#Force TLS v1.2 and higher
        ssl_session_cache    shared:SSL:1m;
        ssl_ciphers 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
        ssl_prefer_server_ciphers  on;

        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8 8.8.4.4;

        # Security headers for Emby
        add_header X-Xss-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header 'Referrer-Policy' 'no-referrer';
        add_header Content-Security-Policy "frame-ancestors your-root.domain your.sub.domain;";  #replace with your root domain (ie google.com) and your subdomain (ie emby.google.com)
        proxy_hide_header X-Powered-By;
        add_header Content-Security-Policy "upgrade-insecure-requests";

        location / {
            proxy_pass http://192.168.x.x:8096; # Adjust as per your Emby server IP and port

            proxy_set_header Range $http_range;
            proxy_set_header If-Range $http_if_range;
            proxy_set_header X-Real-IP $http_CF_Connecting_IP;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            # WebSocket support
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
}

This example nginx.conf is a robust way for your server to communicate with Cloudflare, it also corrects some of the mistakes that Cloudflare makes (like allowing CBC ciphers on the free tier which are insecure).  The key features of this .conf are:

 

  • Performance Optimization: Gzip compression significantly reduces the size of transmitted data, improving loading times for users.

  • Security Enhancements: SSL/TLS support ensures secure data transmission, protecting user information and enhancing trust.

  • Traffic Management: Rate limiting helps prevent abuse by restricting the number of requests from a single IP, reducing the risk of denial-of-service attacks.

  • Automatic Redirects: The HTTP to HTTPS redirect ensures users access the secure version of your site.

  • WebSocket Support: Configuring WebSocket headers enables real-time communication features for applications like Emby.

  • Security Headers: Implementing various security headers helps mitigate common vulnerabilities, such as XSS and clickjacking.

  • Session Management: SSL session caching optimizes performance for returning users by reusing session data.

  • Customizable MIME Types: Inclusion of various MIME types ensures proper content delivery for different file types, including fonts.

  • Error Handling: The configuration supports error logging and management, which aids in troubleshooting and maintaining service quality.

  • Resource Management: The worker_processes and worker_connections directives ensure efficient use of server resources according to the system’s capabilities.

Please read the #comments next to the directives so you know what to put where.  The ssl_ciphers section forces communication with cloudflare to work on one of those ciphers, as a result, it forces your users to work off one of those ciphers, and they are currently the highest rated ciphers recommended by probely.


Emby requires a PKCS #12 formatted Certificate, and nginx doesn't really use that, so here's a python script that will take your certificate and key files and convert them into a single PKCS #12 formatted certificate.  You do not need to reference this file in nginx and only need to put the path in your emby server for this to work.

 

import subprocess

def convert_pem_to_pfx(cert_file, key_file, output_file, password):
    # Use OpenSSL to create a PKCS#12 file from the certificate and key
    command = [
        "openssl", "pkcs12", "-export",
        "-out", output_file,
        "-inkey", key_file,
        "-in", cert_file,
        "-password", f"pass:{password}"
    ]

    subprocess.run(command, check=True)

# Usage
certificate_file = 'certificate.pem'  # Path to your certificate
key_file = 'key.pem'                   # Path to your key
output_file = 'output.pfx'             # Desired output filename
password = 'your_password'              # Password for the .pfx file

convert_pem_to_pfx(certificate_file, key_file, output_file, password)


You only need to run this script once, you can set a password, or hit enter twice to bypass the password, the choice is yours.  Emby does provide a field for the password, so using a password is probably better than leaving it blank. 

Please note, that this was all made within the last week, and reflect the current best practices for security and balancing security/optimization/resource management, however, in the near future, things could change again and render some of this obsolete.  It's best practice to continually search and seek out new directives and test them out, as well as randomly browse cloudflare for any updated security features they may offer or takeaway from the free service tier.


Edited for spelling and clarity

Edited by JasonNalley
  • Like 1
  • Thanks 2
  • Solution
Posted

Thanks so much for this !

  • Thanks 1
Posted
21 hours ago, JasonNalley said:
gzip on;

Why aren't you using Brotli?

brotli on;
        brotli_comp_level 6;
        brotli_types *;
        gunzip on;

 

JasonNalley
Posted (edited)
50 minutes ago, TMCsw said:

Why aren't you using Brotli?

brotli on;
        brotli_comp_level 6;
        brotli_types *;
        gunzip on;

 

I figure most people are running emby on resource limited servers (CPU + Mem) rather than fully dedicated servers.  I use Brotli on mine for text and java, while using gzip for everything else.  I just switched this conf for gzip; I supposed could have kept both in and commented out the brotli and given an either or scenario, or even a mixed scenario like I use.  But brotli requires more CPU for compression due to the more complex algorithm, and takes up more memory during compression compared to gzip.  Brotli is also not as good at compressing images as gzip ime, and since most of the compression done will be to image files (thumbnails, posters, etc) it's probably a better usecase for gzip with an emby server.  Though, using it mixed has its benefits...

Edit: This is my normal .conf section for brotli and gzip

# Enable Brotli compression for text-based content
brotli on;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
brotli_min_length 1000; # Minimum length for Brotli compression
brotli_comp_level 6;    # Compression level for Brotli (1-11)
brotli_vary on;         # Enable Vary header for Brotli

# Enable Gzip compression for all types, including images and fallback for Brotli
gzip on;
gzip_types image/jpeg image/png image/gif image/webp image/svg+xml text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_buffers 16 8k;

In this case, nginx will use brotli for all text-based information (where it excels) and use gzip only for images, unless the client-side doesn't support brotli, then it will fall back to gzip for all types...  It's like having the best of both worlds... 

Edited by JasonNalley
  • 1 year later...
skooogis
Posted

How do you get Brotli-module? From what I can see, it's not in the precompiled downloads for Windows?

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