- deploy.sh: one-command deploy script (--init for first time, bare for updates) - docker-compose.prod.yml: production stack with nginx, multi-worker uvicorn, no volume mounts for code - nginx/nginx.conf: reverse proxy with rate limiting, WebSocket support, static asset caching - Fix login to use real backend API instead of mock localStorage tokens - Add auth guard to AppShell (prevents flash-of-content on unauthenticated routes) - JWT claims decoded client-side for user info (no extra /me call needed) - Switch logo from missing .jpeg to .svg - Frontend API URL defaults to same-origin (works behind nginx without CORS) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
132 lines
4 KiB
Nginx Configuration File
132 lines
4 KiB
Nginx Configuration File
worker_processes auto;
|
|
|
|
events {
|
|
worker_connections 1024;
|
|
}
|
|
|
|
http {
|
|
include /etc/nginx/mime.types;
|
|
default_type application/octet-stream;
|
|
|
|
sendfile on;
|
|
tcp_nopush on;
|
|
tcp_nodelay on;
|
|
|
|
keepalive_timeout 65;
|
|
client_max_body_size 50M;
|
|
|
|
# Gzip
|
|
gzip on;
|
|
gzip_types text/plain text/css application/json application/javascript text/xml;
|
|
gzip_min_length 256;
|
|
|
|
# Rate limiting
|
|
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
|
|
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
|
|
|
|
# Upstream servers
|
|
upstream frontend {
|
|
server frontend:3000;
|
|
}
|
|
|
|
upstream backend {
|
|
server backend:8000;
|
|
}
|
|
|
|
server {
|
|
listen 80;
|
|
server_name _;
|
|
|
|
# ---------------------------------------------------------------
|
|
# API + Auth routes → FastAPI backend
|
|
# ---------------------------------------------------------------
|
|
location /api/ {
|
|
limit_req zone=api burst=20 nodelay;
|
|
|
|
proxy_pass http://backend;
|
|
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;
|
|
|
|
# Timeouts for long-running agent calls
|
|
proxy_read_timeout 300s;
|
|
proxy_send_timeout 300s;
|
|
}
|
|
|
|
# Stricter rate limit on login
|
|
location /api/v1/auth/login {
|
|
limit_req zone=login burst=3 nodelay;
|
|
|
|
proxy_pass http://backend;
|
|
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;
|
|
}
|
|
|
|
# Health check (no rate limit)
|
|
location /health {
|
|
proxy_pass http://backend;
|
|
}
|
|
|
|
# OpenAPI docs
|
|
location /docs {
|
|
proxy_pass http://backend;
|
|
}
|
|
location /openapi.json {
|
|
proxy_pass http://backend;
|
|
}
|
|
|
|
# ---------------------------------------------------------------
|
|
# WebSocket → FastAPI backend
|
|
# ---------------------------------------------------------------
|
|
location /ws/ {
|
|
proxy_pass http://backend;
|
|
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_read_timeout 86400s;
|
|
}
|
|
|
|
# ---------------------------------------------------------------
|
|
# Everything else → Next.js frontend
|
|
# ---------------------------------------------------------------
|
|
location / {
|
|
proxy_pass http://frontend;
|
|
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;
|
|
}
|
|
|
|
# Next.js static assets (long cache)
|
|
location /_next/static/ {
|
|
proxy_pass http://frontend;
|
|
proxy_cache_valid 200 365d;
|
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
}
|
|
}
|
|
|
|
# ---------------------------------------------------------------
|
|
# Optional: HTTPS server (uncomment when you have certs)
|
|
# ---------------------------------------------------------------
|
|
# server {
|
|
# listen 443 ssl http2;
|
|
# server_name your-domain.com;
|
|
#
|
|
# ssl_certificate /etc/nginx/ssl/cert.pem;
|
|
# ssl_certificate_key /etc/nginx/ssl/key.pem;
|
|
# ssl_protocols TLSv1.2 TLSv1.3;
|
|
#
|
|
# # ... same location blocks as above ...
|
|
# }
|
|
#
|
|
# server {
|
|
# listen 80;
|
|
# server_name your-domain.com;
|
|
# return 301 https://$host$request_uri;
|
|
# }
|
|
}
|