Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correcting and adjusting Nginx docs #1098

Merged
merged 21 commits into from
Sep 11, 2024
Merged
Changes from 13 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 150 additions & 75 deletions docs/general/networking/nginx.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,56 +21,51 @@ The default X-Frame-Options header may cause issues with the webOS app, causing

:::

Create the file `/etc/nginx/conf.d/jellyfin.conf` which will forward requests to Jellyfin.
Create the file `/etc/nginx/sites-available/jellyfin` which will forward requests to Jellyfin. After you've finished, you will need to symlink this file to /etc/nginx/sites-enabled and then reload nginx. This example assumes you've already acquired certifications as documented in our [Let's Encrypt](https://jellyfin.org/docs/general/networking/letsencrypt#nginx) guide.

Note that a server listening on http port 80 is required for the Certbot / Let's Encrypt certificate renewal process.

### HTTPS config example

```config
# Uncomment the commented sections after you have acquired a SSL Certificate
server {
listen 80;
listen [::]:80;
# server_name DOMAIN_NAME;
server_name DOMAIN_NAME;

# Uncomment to redirect HTTP to HTTPS
# return 301 https://$host$request_uri;
#}
return 301 https://$host$request_uri;
}

#server {
# listen 443 ssl;
# listen [::]:443 ssl;
http2 on;
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name DOMAIN_NAME;

## The default `client_max_body_size` is 1M, this might not be enough for some posters, etc.
client_max_body_size 20M;

# Uncomment next line to Disable TLS 1.0 and 1.1 (Might break older devices)
# ssl_protocols TLSv1.3 TLSv1.2;
ssl_protocols TLSv1.3 TLSv1.2;

# use a variable to store the upstream proxy
# in this example we are using a hostname which is resolved via DNS
# (if you aren't using DNS remove the resolver line and change the variable to point to an IP address e.g `set $jellyfin 127.0.0.1`)
set $jellyfin jellyfin;
resolver 127.0.0.1 valid=30s;

#ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem;
#include /etc/letsencrypt/options-ssl-nginx.conf;
#ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
#add_header Strict-Transport-Security "max-age=31536000" always;
#ssl_trusted_certificate /etc/letsencrypt/live/DOMAIN_NAME/chain.pem;
#ssl_stapling on;
#ssl_stapling_verify on;
ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
ssl_trusted_certificate /etc/letsencrypt/live/DOMAIN_NAME/chain.pem;

# Security / XSS Mitigation Headers
# NOTE: X-Frame-Options may cause issues with the webOS app
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "0"; # Do NOT enable. This is obsolete/dangerous
add_header X-Content-Type-Options "nosniff";

# COOP/COEP. Disable if you use external plugins/images/assets
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;

# Permissions policy. May cause issues on some clients
add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), battery=(), bluetooth=(), camera=(), clipboard-read=(), display-capture=(), document-domain=(), encrypted-media=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), interest-cohort=(), keyboard-map=(), local-fonts=(), magnetometer=(), microphone=(), payment=(), publickey-credentials-get=(), serial=(), sync-xhr=(), usb=(), xr-spatial-tracking=()" always;

Expand All @@ -82,10 +77,71 @@ server {
# NOTE: The default CSP headers may cause issues with the webOS app
#add_header Content-Security-Policy "default-src https: data: blob: http://image.tmdb.org; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.gstatic.com https://www.youtube.com blob:; worker-src 'self' blob:; connect-src 'self'; object-src 'none'; frame-ancestors 'self'";

location = / {
return 302 http://$host/web/;
#return 302 https://$host/web/;
location / {
# Proxy main Jellyfin traffic
proxy_pass http://$jellyfin:8096;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;

# Disable buffering when the nginx proxy gets very resource heavy upon streaming
felix920506 marked this conversation as resolved.
Show resolved Hide resolved
proxy_buffering off;
}

location /socket {
# Proxy Jellyfin Websockets traffic
proxy_pass http://$jellyfin:8096;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
}
```

### HTTP config example

<details>
<summary>Expand HTTP Example</summary>

```config
server {
listen 80;
listen [::]:80;
server_name DOMAIN_NAME;

## The default `client_max_body_size` is 1M, this might not be enough for some posters, etc.
client_max_body_size 20M;

# use a variable to store the upstream proxy
# in this example we are using a hostname which is resolved via DNS
# (if you aren't using DNS remove the resolver line and change the variable to point to an IP address e.g `set $jellyfin 127.0.0.1`)
solidsnake1298 marked this conversation as resolved.
Show resolved Hide resolved
set $jellyfin jellyfin;
resolver 127.0.0.1 valid=30s;

# Security / XSS Mitigation Headers
# NOTE: X-Frame-Options may cause issues with the webOS app
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "0"; # Do NOT enable. This is obsolete/dangerous
add_header X-Content-Type-Options "nosniff";

# Permissions policy. May cause issues on some clients
solidsnake1298 marked this conversation as resolved.
Show resolved Hide resolved
add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), battery=(), bluetooth=(), camera=(), clipboard-read=(), display-capture=(), document-domain=(), encrypted-media=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), interest-cohort=(), keyboard-map=(), local-fonts=(), magnetometer=(), microphone=(), payment=(), publickey-credentials-get=(), serial=(), sync-xhr=(), usb=(), xr-spatial-tracking=()" always;

# Content Security Policy
# See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
# Enforces https content and restricts JS/CSS to origin
# External Javascript (such as cast_sender.js for Chromecast) must be whitelisted.
# NOTE: The default CSP headers may cause issues with the webOS app
#add_header Content-Security-Policy "default-src https: data: blob: http://image.tmdb.org; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.gstatic.com https://www.youtube.com blob:; worker-src 'self' blob:; connect-src 'self'; object-src 'none'; frame-ancestors 'self'";

location / {
# Proxy main Jellyfin traffic
Expand Down Expand Up @@ -115,47 +171,52 @@ server {
proxy_set_header X-Forwarded-Host $http_host;
}
}

```

</details>

## Nginx with Subpath (example.org/jellyfin)

When connecting to server from a client application, enter `http(s)://DOMAIN_NAME/jellyfin` in the address field.

Set the [base URL](/docs/general/networking#base-url) field in the Jellyfin server. This can be done by navigating to the Admin Dashboard -> Networking -> Base URL in the web client. Fill in this box with `/jellyfin` and click Save. The server will need to be restarted before this change takes effect.

### HTTP config example

:::caution

HTTP is insecure. The following configuration is provided for ease of use only. If you are planning on exposing your server over the Internet you should setup HTTPS (see below for HTTPS configuration example). [Let's Encrypt](https://letsencrypt.org/getting-started/) can provide free TLS certificates which can be installed easily via [certbot](https://certbot.eff.org/).

:::
### HTTPS subpath example

```conf
# Jellyfin hosted on http://DOMAIN_NAME/jellyfin
# Jellyfin hosted on https://DOMAIN_NAME/jellyfin

server {
listen 80;
listen [::]:80;
server_name DOMAIN_NAME;

# Uncomment to redirect HTTP to HTTPS
return 301 https://$host$request_uri;
}

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

server_name DOMAIN_NAME;
# You can specify multiple domain names if you want
#server_name jellyfin.local;

ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
ssl_trusted_certificate /etc/letsencrypt/live/DOMAIN_NAME/chain.pem;

# use a variable to store the upstream proxy
# in this example we are using a hostname which is resolved via DNS
# (if you aren't using DNS remove the resolver line and change the variable to point to an IP address e.g `set $jellyfin 127.0.0.1`)
set $jellyfin jellyfin;
resolver 127.0.0.1 valid=30s;

# Uncomment and create directory to also host static content
#root /srv/http/media;
index index.html;

location / {
try_files $uri $uri/ =404;
}
# Uncomment next line to disable TLS 1.0 and 1.1 (Might break older devices)
ssl_protocols TLSv1.3 TLSv1.2;

# Jellyfin
location /jellyfin {
Expand All @@ -166,66 +227,71 @@ server {
# https://www.acunetix.com/blog/articles/a-fresh-look-on-reverse-proxy-related-attacks/
location /jellyfin/ {
# Proxy main Jellyfin traffic

proxy_pass http://$jellyfin:8096;

proxy_pass_request_headers on;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;

# Disable buffering when the nginx proxy gets very resource heavy upon streaming
proxy_buffering off;
}

location /jellyfin/socket {
# Proxy Jellyfin Websockets traffic
proxy_pass http://$jellyfin:8096;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
}
```

### HTTPS config example
### HTTP subpath example

:::caution

HTTP is insecure. The following configuration is provided for ease of use only. If you are planning on exposing your server over the Internet you should setup HTTPS (see below for HTTPS configuration example). [Let's Encrypt](https://letsencrypt.org/getting-started/) can provide free TLS certificates which can be installed easily via [certbot](https://certbot.eff.org/).

:::

The following config is meant to work with Certbot / Let's Encrypt.
<details>
<summary>Expand HTTP Example</summary>

```conf
# Jellyfin hosted on https://DOMAIN_NAME/jellyfin
# Jellyfin hosted on http://DOMAIN_NAME/jellyfin

server {
listen 80;
listen [::]:80;
server_name DOMAIN_NAME;

# Uncomment to redirect HTTP to HTTPS
return 301 https://$host$request_uri;
}

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

server_name DOMAIN_NAME;
# You can specify multiple domain names if you want
#server_name jellyfin.local;
ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
add_header Strict-Transport-Security "max-age=31536000" always;
ssl_trusted_certificate /etc/letsencrypt/live/DOMAIN_NAME/chain.pem;
ssl_stapling on;
ssl_stapling_verify on;

# use a variable to store the upstream proxy
# in this example we are using a hostname which is resolved via DNS
# (if you aren't using DNS remove the resolver line and change the variable to point to an IP address e.g `set $jellyfin 127.0.0.1`)
set $jellyfin jellyfin;
resolver 127.0.0.1 valid=30s;

# Uncomment next line to disable TLS 1.0 and 1.1 (Might break older devices)
# ssl_protocols TLSv1.3 TLSv1.2;
# Uncomment and create directory to also host static content
solidsnake1298 marked this conversation as resolved.
Show resolved Hide resolved
#root /srv/http/media;
index index.html;

location / {
try_files $uri $uri/ =404;
}

# Jellyfin
location /jellyfin {
Expand All @@ -236,28 +302,38 @@ server {
# https://www.acunetix.com/blog/articles/a-fresh-look-on-reverse-proxy-related-attacks/
location /jellyfin/ {
# Proxy main Jellyfin traffic

proxy_pass http://$jellyfin:8096;

proxy_pass_request_headers on;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;

# Disable buffering when the nginx proxy gets very resource heavy upon streaming
proxy_buffering off;
}

location /jellyfin/socket {
# Proxy Jellyfin Websockets traffic
proxy_pass http://$jellyfin:8096;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
}
```

</details>

## Extra Nginx Configurations

### Censor sensitive information in logs
Expand Down Expand Up @@ -367,7 +443,6 @@ In the "Advanced" tab, enter the following in "Custom Nginx Configuration". Thi
# External Javascript (such as cast_sender.js for Chromecast) must be whitelisted.
# NOTE: The default CSP headers may cause issues with the webOS app
#add_header Content-Security-Policy "default-src https: data: blob: http://image.tmdb.org; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.gstatic.com/cv/js/sender/v1/cast_sender.js https://www.gstatic.com/eureka/clank/95/cast_sender.js https://www.gstatic.com/eureka/clank/96/cast_sender.js https://www.gstatic.com/eureka/clank/97/cast_sender.js https://www.youtube.com blob:; worker-src 'self' blob:; connect-src 'self'; object-src 'none'; frame-ancestors 'self'";

```

In the "SSL" tab, use the jellyfin.example.org certificate that you created with Nginx Proxy Manager and enable "Force SSL", "HTTP/2 Support", "HSTS Enabled", "HSTS Subdomains".