275 lines
8.5 KiB
Nginx Configuration File

worker_processes auto;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# CORS origin validation - only allow configured origins
# Validates Origin header against whitelist; returns empty string for disallowed origins
# Production domain injected via envsubst from APP_BASE_URL env var
map $http_origin $cors_origin {
default "";
# Localhost development (various ports)
"~^http://localhost(:[0-9]+)?$" $http_origin;
# Docker internal network
"~^http://host\.docker\.internal(:[0-9]+)?$" $http_origin;
# Production domain (injected from APP_BASE_URL)
"${APP_BASE_URL}" $http_origin;
}
# Enable UTF-8 charset for proper handling of special characters in URLs
charset utf-8;
charset_types application/json text/plain text/css text/javascript;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Optimizations for video streaming
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# Gzip compression for API responses (reduces JSON payload size by 60-80%)
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_types
application/json
application/javascript
application/xml
text/plain
text/css
text/javascript
text/xml;
# Increase buffer sizes for large video files
client_max_body_size 0;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
server {
listen 80;
server_name _;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Hide nginx version
server_tokens off;
# Curated public videos
location /videos/public/ {
alias /media/public/curated/;
# Enable byte-range requests (essential for video seeking)
add_header Accept-Ranges bytes;
# CORS headers for cross-origin video playback (validated origin only)
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Range";
# Cache control
expires 1d;
add_header Cache-Control "public, max-age=86400";
# Proper MIME types for video
types {
video/mp4 mp4;
video/webm webm;
image/jpeg jpg jpeg;
image/png png;
}
}
# Compilation videos from playback directory
location /videos/playback/ {
alias /media/playback/;
add_header Accept-Ranges bytes;
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Range";
expires 1d;
add_header Cache-Control "public, max-age=86400";
types {
video/mp4 mp4;
video/webm webm;
}
}
# Compilation symlinks
location /videos/compilations/ {
alias /media/compilations/;
add_header Accept-Ranges bytes;
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Range";
expires 1d;
add_header Cache-Control "public, max-age=86400";
types {
video/mp4 mp4;
video/webm webm;
}
}
# Public videos directory
location /videos/videos/ {
alias /media/videos/;
add_header Accept-Ranges bytes;
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Range";
expires 1d;
add_header Cache-Control "public, max-age=86400";
types {
video/mp4 mp4;
video/webm webm;
}
}
# Quickies short-form videos - optimized for fast loading
location /videos/quickies/ {
alias /media/quickies/;
# Enable byte-range requests (essential for video seeking)
add_header Accept-Ranges bytes;
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, OPTIONS, HEAD";
add_header Access-Control-Allow-Headers "Range, If-Range";
add_header Access-Control-Expose-Headers "Content-Range, Accept-Ranges, Content-Length";
# Extended cache for immutable video content (7 days)
expires 7d;
add_header Cache-Control "public, max-age=604800, immutable";
# Optimize output buffers for video streaming
output_buffers 2 512k;
types {
video/mp4 mp4;
video/webm webm;
}
}
# Also serve quickies at /media/quickies/ path for direct URL access
location /media/quickies/ {
alias /media/quickies/;
# Enable byte-range requests (essential for video seeking)
add_header Accept-Ranges bytes;
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, OPTIONS, HEAD";
add_header Access-Control-Allow-Headers "Range, If-Range";
add_header Access-Control-Expose-Headers "Content-Range, Accept-Ranges, Content-Length";
# Extended cache for immutable video content (7 days)
expires 7d;
add_header Cache-Control "public, max-age=604800, immutable";
# Optimize output buffers for video streaming
output_buffers 2 512k;
types {
video/mp4 mp4;
video/webm webm;
}
}
# Library videos (studios, OnlyFans, gifs, etc.)
location /videos/library/ {
alias /media/local/;
add_header Accept-Ranges bytes;
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Range";
expires 1d;
add_header Cache-Control "public, max-age=86400";
types {
video/mp4 mp4;
video/webm webm;
}
}
# Thumbnails location
location /thumbnails/ {
alias /media/thumbnails/;
expires 7d;
add_header Cache-Control "public, max-age=604800";
add_header Access-Control-Allow-Origin $cors_origin always;
}
# Ad images location
location /ads/ {
alias /media/ads/;
expires 1d;
add_header Cache-Control "public, max-age=86400";
add_header Access-Control-Allow-Origin $cors_origin always;
types {
image/jpeg jpg jpeg;
image/png png;
image/gif gif;
image/webp webp;
}
}
# User gallery images location
location /gallery/ {
alias /media/gallery/;
expires 7d;
add_header Cache-Control "public, max-age=604800";
add_header Access-Control-Allow-Origin $cors_origin always;
types {
image/jpeg jpg jpeg;
image/png png;
image/gif gif;
image/webp webp;
}
}
# Digest frames location (extracted video frames for AI analysis)
location /digest-frames/ {
alias /media/digest_frames/;
expires 7d;
add_header Cache-Control "public, max-age=604800";
add_header Access-Control-Allow-Origin $cors_origin always;
types {
image/jpeg jpg jpeg;
image/png png;
}
}
# Health check
location /health {
return 200 'OK';
add_header Content-Type text/plain;
}
}
}