mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-19 13:12:48 +03:00
Neither /ws nor the jsmpeg websockets checked Origin, and the internal port grants admin to everyone, so any page a LAN user visited could open ws://frigate:5000/ws and send commands or read streams. Both servers now reject a browser handshake whose Origin host matches neither Host nor X-Forwarded-Host, and allow handshakes without an Origin for non-browser clients. nginx now forwards an outer proxy's X-Forwarded-Host instead of overwriting it, so proxies that rewrite Host and the Home Assistant integration's proxy still match.
395 lines
12 KiB
Nginx Configuration File
395 lines
12 KiB
Nginx Configuration File
# Loaded with -c from the /tmp/nginx/conf copy: relative includes follow the -c
|
|
# file, all other path directives follow --prefix and must stay absolute.
|
|
|
|
daemon off;
|
|
# ignored by a non-root master; keeps workers root under FRIGATE_RUN_AS_ROOT
|
|
user root;
|
|
worker_processes auto;
|
|
|
|
error_log /dev/stdout warn;
|
|
pid /tmp/nginx/nginx.pid;
|
|
|
|
events {
|
|
worker_connections 1024;
|
|
}
|
|
|
|
http {
|
|
map_hash_bucket_size 256;
|
|
server_tokens off;
|
|
|
|
client_body_temp_path /tmp/nginx/client_body;
|
|
proxy_temp_path /tmp/nginx/proxy;
|
|
fastcgi_temp_path /tmp/nginx/fastcgi;
|
|
uwsgi_temp_path /tmp/nginx/uwsgi;
|
|
scgi_temp_path /tmp/nginx/scgi;
|
|
|
|
include mime.types;
|
|
default_type application/octet-stream;
|
|
|
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
|
'$status $body_bytes_sent "$http_referer" '
|
|
'"$http_user_agent" "$http_x_forwarded_for" '
|
|
'request_time="$request_time" upstream_response_time="$upstream_response_time"';
|
|
|
|
|
|
access_log /dev/stdout main;
|
|
|
|
# send headers in one piece, it is better than sending them one by one
|
|
tcp_nopush on;
|
|
|
|
sendfile on;
|
|
|
|
keepalive_timeout 65;
|
|
|
|
gzip on;
|
|
gzip_comp_level 6;
|
|
gzip_types text/plain text/css application/json application/x-javascript application/javascript text/javascript image/svg+xml image/x-icon image/bmp;
|
|
gzip_proxied no-cache no-store private expired auth;
|
|
gzip_vary on;
|
|
|
|
proxy_cache_path /dev/shm/nginx_cache levels=1:2 keys_zone=api_cache:10m max_size=10m inactive=1m use_temp_path=off;
|
|
|
|
map $sent_http_content_type $should_not_cache {
|
|
'application/json' 0;
|
|
default 1;
|
|
}
|
|
|
|
# keep an outer proxy's X-Forwarded-Host so the websocket servers can
|
|
# match a browser's Origin when that proxy rewrites Host
|
|
map $http_x_forwarded_host $forwarded_host {
|
|
"" $http_host;
|
|
default $http_x_forwarded_host;
|
|
}
|
|
|
|
upstream frigate_api {
|
|
server 127.0.0.1:5001;
|
|
keepalive 1024;
|
|
}
|
|
|
|
upstream mqtt_ws {
|
|
server 127.0.0.1:5002;
|
|
keepalive 1024;
|
|
}
|
|
|
|
upstream jsmpeg {
|
|
server 127.0.0.1:8082;
|
|
keepalive 1024;
|
|
}
|
|
|
|
include go2rtc_upstream.conf;
|
|
|
|
server {
|
|
include listen.conf;
|
|
include security_headers.conf;
|
|
|
|
# enable HTTP/2 for TLS connections to eliminate browser 6-connection limit
|
|
http2 on;
|
|
|
|
# vod settings
|
|
vod_base_url '';
|
|
vod_segments_base_url '';
|
|
vod_mode mapped;
|
|
vod_max_mapping_response_size 1m;
|
|
vod_upstream_location /api;
|
|
vod_align_segments_to_key_frames on;
|
|
vod_manifest_segment_durations_mode accurate;
|
|
vod_ignore_edit_list on;
|
|
# short leading segments at each playlist start; sources start at
|
|
# the seek target, so the ladder applies to every seek. Only
|
|
# effective when clips declare real keyFrameDurations
|
|
vod_bootstrap_segment_durations 1000;
|
|
vod_bootstrap_segment_durations 2000;
|
|
vod_bootstrap_segment_durations 4000;
|
|
vod_segment_duration 10000;
|
|
|
|
# MPEG-TS settings (not used when fMP4 is enabled, kept for reference)
|
|
vod_hls_mpegts_align_frames off;
|
|
vod_hls_mpegts_interleave_frames on;
|
|
|
|
# file handle caching / aio
|
|
open_file_cache max=1000 inactive=5m;
|
|
open_file_cache_valid 2m;
|
|
open_file_cache_min_uses 1;
|
|
open_file_cache_errors on;
|
|
aio on;
|
|
|
|
# file upload size
|
|
client_max_body_size 20M;
|
|
|
|
# https://github.com/kaltura/nginx-vod-module#vod_open_file_thread_pool
|
|
vod_open_file_thread_pool default;
|
|
|
|
# vod caches
|
|
vod_metadata_cache metadata_cache 512m;
|
|
vod_mapping_cache mapping_cache 5m 10m;
|
|
|
|
# gzip manifests
|
|
gzip on;
|
|
gzip_types application/vnd.apple.mpegurl;
|
|
|
|
include auth_location.conf;
|
|
include base_path.conf;
|
|
|
|
location /vod/ {
|
|
include auth_request.conf;
|
|
aio threads;
|
|
vod hls;
|
|
|
|
# Use fMP4 (fragmented MP4) instead of MPEG-TS for better performance
|
|
# Smaller segments, faster generation, better browser compatibility
|
|
vod_hls_container_format fmp4;
|
|
|
|
# fMP4 playlists use EXT-X-MAP, which requires HLS protocol
|
|
# version 6 (RFC 8216 section 7); the module default is 4
|
|
vod_hls_version 6;
|
|
|
|
secure_token $args;
|
|
secure_token_types application/vnd.apple.mpegurl;
|
|
|
|
include security_headers.conf;
|
|
add_header Cache-Control "no-store";
|
|
expires off;
|
|
|
|
keepalive_disable safari;
|
|
}
|
|
|
|
location /stream/ {
|
|
include auth_request.conf;
|
|
include security_headers.conf;
|
|
add_header Cache-Control "no-store";
|
|
expires off;
|
|
|
|
types {
|
|
application/dash+xml mpd;
|
|
application/vnd.apple.mpegurl m3u8;
|
|
video/mp2t ts;
|
|
image/jpeg jpg;
|
|
}
|
|
|
|
root /tmp;
|
|
}
|
|
|
|
location /clips/ {
|
|
include auth_request.conf;
|
|
types {
|
|
video/mp4 mp4;
|
|
image/jpeg jpg jpeg;
|
|
image/png png;
|
|
image/webp webp;
|
|
}
|
|
|
|
expires 7d;
|
|
include security_headers.conf;
|
|
add_header Cache-Control "public";
|
|
autoindex on;
|
|
root /media/frigate;
|
|
}
|
|
|
|
location /cache/ {
|
|
internal; # This tells nginx it's not accessible from the outside
|
|
alias /tmp/cache/;
|
|
}
|
|
|
|
location /recordings/ {
|
|
include auth_request.conf;
|
|
types {
|
|
video/mp4 mp4;
|
|
}
|
|
|
|
autoindex on;
|
|
autoindex_format json;
|
|
root /media/frigate;
|
|
}
|
|
|
|
location /exports/ {
|
|
include auth_request.conf;
|
|
types {
|
|
video/mp4 mp4;
|
|
}
|
|
|
|
autoindex on;
|
|
autoindex_format json;
|
|
root /media/frigate;
|
|
}
|
|
|
|
location /ws {
|
|
include auth_request.conf;
|
|
proxy_pass http://mqtt_ws/;
|
|
include proxy.conf;
|
|
}
|
|
|
|
location /live/jsmpeg/ {
|
|
include auth_request.conf;
|
|
proxy_pass http://jsmpeg/;
|
|
include proxy.conf;
|
|
}
|
|
|
|
# frigate lovelace card uses this path
|
|
location /live/mse/api/ws {
|
|
# tells /auth to apply the go2rtc stream checks
|
|
set $go2rtc_stream_proxy 1;
|
|
include auth_request.conf;
|
|
limit_except GET {
|
|
deny all;
|
|
}
|
|
proxy_pass http://go2rtc/api/ws;
|
|
include proxy.conf;
|
|
}
|
|
|
|
location /live/webrtc/api/ws {
|
|
# tells /auth to apply the go2rtc stream checks
|
|
set $go2rtc_stream_proxy 1;
|
|
include auth_request.conf;
|
|
limit_except GET {
|
|
deny all;
|
|
}
|
|
proxy_pass http://go2rtc/api/ws;
|
|
include proxy.conf;
|
|
}
|
|
|
|
# pass through go2rtc player
|
|
location /live/webrtc/webrtc.html {
|
|
include auth_request.conf;
|
|
limit_except GET {
|
|
deny all;
|
|
}
|
|
proxy_pass http://go2rtc/webrtc.html;
|
|
include proxy.conf;
|
|
}
|
|
|
|
# integration uses this to add webrtc candidate
|
|
location /api/go2rtc/webrtc {
|
|
# tells /auth to apply the go2rtc stream checks
|
|
set $go2rtc_stream_proxy 1;
|
|
include auth_request.conf;
|
|
limit_except POST {
|
|
deny all;
|
|
}
|
|
proxy_pass http://go2rtc/api/webrtc;
|
|
include proxy.conf;
|
|
}
|
|
|
|
location ~* /api/.*\.(jpg|jpeg|png|webp|gif)$ {
|
|
include auth_request.conf;
|
|
rewrite ^/api/(.*)$ /$1 break;
|
|
proxy_pass http://frigate_api;
|
|
include proxy.conf;
|
|
}
|
|
|
|
location /api/ {
|
|
include auth_request.conf;
|
|
include security_headers.conf;
|
|
add_header Cache-Control "no-store";
|
|
expires off;
|
|
proxy_pass http://frigate_api/;
|
|
include proxy.conf;
|
|
|
|
proxy_cache api_cache;
|
|
proxy_cache_key "$scheme$proxy_host$request_uri|$role|$groups|$user";
|
|
proxy_cache_lock on;
|
|
proxy_cache_use_stale updating;
|
|
proxy_cache_valid 200 5s;
|
|
proxy_cache_bypass $http_x_cache_bypass;
|
|
proxy_no_cache $should_not_cache;
|
|
add_header X-Cache-Status $upstream_cache_status;
|
|
|
|
location /api/vod/ {
|
|
include auth_request.conf;
|
|
proxy_pass http://frigate_api/vod/;
|
|
include proxy.conf;
|
|
proxy_cache off;
|
|
}
|
|
|
|
location /api/login {
|
|
auth_request off;
|
|
rewrite ^/api(/.*)$ $1 break;
|
|
proxy_pass http://frigate_api;
|
|
include proxy.conf;
|
|
}
|
|
|
|
location /api/logout {
|
|
auth_request off;
|
|
rewrite ^/api(/.*)$ $1 break;
|
|
proxy_pass http://frigate_api;
|
|
include proxy.conf;
|
|
}
|
|
|
|
# Allow unauthenticated access to the first_time_login endpoint
|
|
# so the login page can load help text before authentication.
|
|
location /api/auth/first_time_login {
|
|
auth_request off;
|
|
limit_except GET {
|
|
deny all;
|
|
}
|
|
rewrite ^/api(/.*)$ $1 break;
|
|
proxy_pass http://frigate_api;
|
|
include proxy.conf;
|
|
}
|
|
|
|
location /api/stats {
|
|
include auth_request.conf;
|
|
access_log off;
|
|
rewrite ^/api(/.*)$ $1 break;
|
|
proxy_pass http://frigate_api;
|
|
include proxy.conf;
|
|
}
|
|
|
|
location /api/version {
|
|
include auth_request.conf;
|
|
access_log off;
|
|
rewrite ^/api(/.*)$ $1 break;
|
|
proxy_pass http://frigate_api;
|
|
include proxy.conf;
|
|
}
|
|
}
|
|
|
|
location / {
|
|
# do not require auth for static assets
|
|
include security_headers.conf;
|
|
add_header Cache-Control "no-store";
|
|
expires off;
|
|
|
|
location /assets/ {
|
|
access_log off;
|
|
expires 1y;
|
|
include security_headers.conf;
|
|
add_header Cache-Control "public";
|
|
}
|
|
|
|
location /locales/ {
|
|
access_log off;
|
|
include security_headers.conf;
|
|
add_header Cache-Control "public";
|
|
}
|
|
|
|
location ~ ^/.*-([A-Za-z0-9]+)\.webmanifest$ {
|
|
access_log off;
|
|
expires 1y;
|
|
include security_headers.conf;
|
|
add_header Cache-Control "public";
|
|
default_type application/json;
|
|
proxy_set_header Accept-Encoding "";
|
|
sub_filter_once off;
|
|
sub_filter_types application/json;
|
|
sub_filter '"start_url": "/BASE_PATH/"' '"start_url" : "$http_x_ingress_path/"';
|
|
sub_filter '"src": "/BASE_PATH/' '"src": "$http_x_ingress_path/';
|
|
}
|
|
|
|
sub_filter 'href="/BASE_PATH/' 'href="$http_x_ingress_path/';
|
|
sub_filter 'url(/BASE_PATH/' 'url($http_x_ingress_path/';
|
|
sub_filter '"/BASE_PATH/dist/' '"$http_x_ingress_path/dist/';
|
|
sub_filter '"/BASE_PATH/js/' '"$http_x_ingress_path/js/';
|
|
sub_filter '"/BASE_PATH/assets/' '"$http_x_ingress_path/assets/';
|
|
sub_filter '"/BASE_PATH/locales/' '"$http_x_ingress_path/locales/';
|
|
sub_filter '"/BASE_PATH/monacoeditorwork/' '"$http_x_ingress_path/assets/';
|
|
sub_filter 'return`/BASE_PATH/`' 'return window.baseUrl';
|
|
sub_filter '<body>' '<body><script>window.baseUrl="$http_x_ingress_path/";</script>';
|
|
sub_filter_types text/css application/javascript;
|
|
sub_filter_once off;
|
|
|
|
root /opt/frigate/web;
|
|
try_files $uri $uri.html $uri/ /index.html;
|
|
}
|
|
}
|
|
}
|