nexus-5/nginx.conf
2026-01-26 11:09:40 -05:00

109 lines
4.0 KiB
Nginx Configuration File

map $http_origin $cors_origin {
default "";
"https://local.example.com:5173" $http_origin;
"https://app.example.com" $http_origin;
}
# Garage S3 web endpoint (port 3902 for public reads via website mode)
upstream garage_web {
server 10.10.10.39:3902;
server 10.10.10.40:3902 backup;
server 10.10.10.41:3902 backup;
}
server {
listen 5500;
server_name _;
# Use Docker's embedded DNS for dynamic container resolution
# Prevents stale IPs when containers restart and get new addresses
resolver 127.0.0.11 valid=10s;
set $upstream_web web:8000;
# 🔒 SECURITY: Remote Oathkeeper proxies here with auth headers already added
# Flow: Internet → Oathkeeper → This Nginx → Django/S3
# Internal auth check endpoint for S3 media
# Forwards all Oathkeeper headers so Django middleware can authenticate
location = /internal-auth-check {
internal;
proxy_pass http://$upstream_web/api/media-auth/;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
# Forward standard headers
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 🔒 Forward all Oathkeeper auth headers for middleware validation
proxy_set_header X-Oathkeeper-Secret $http_x_oathkeeper_secret;
proxy_set_header X-User-Id $http_x_user_id;
proxy_set_header X-User-Email $http_x_user_email;
proxy_set_header X-User-First-Name $http_x_user_first_name;
proxy_set_header X-User-Last-Name $http_x_user_last_name;
proxy_set_header X-User-Phone $http_x_user_phone;
proxy_set_header X-User-Profile-Type $http_x_user_profile_type;
proxy_set_header X-Django-Profile-Id $http_x_django_profile_id;
}
# S3-backed media serving with auth_request
# Flow: auth_request → Django validates → proxy to Garage S3
location /api/media/ {
# Auth check before proxying to S3
auth_request /internal-auth-check;
# Strip /api/media/ prefix and proxy to Garage web endpoint
# Website mode serves bucket content at root path
rewrite ^/api/media/(.*)$ /$1 break;
proxy_pass http://garage_web/;
proxy_http_version 1.1;
# Set Host header to bucket name for Garage website mode
proxy_set_header Host nexus-media.web.garage.nebula;
# Video streaming support - forward range requests
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
add_header Accept-Ranges bytes;
# Cache headers for static content (private = browser only, not CDN)
add_header Cache-Control "private, max-age=3600";
}
# Legacy internal location (kept for backwards compatibility during migration)
# Can be removed once S3 migration is verified
location /media-internal/ {
internal;
alias /app/media/;
add_header Accept-Ranges bytes;
sendfile on;
sendfile_max_chunk 1m;
tcp_nopush on;
tcp_nodelay on;
}
# All other requests proxy to Django
# Oathkeeper has already validated session and added headers before reaching here
location / {
proxy_pass http://$upstream_web;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
# WebSocket support (for GraphQL subscriptions)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Large file uploads (videos) - increased from 50m
client_max_body_size 250m;
proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}