diff --git a/NGINX.md b/NGINX.md new file mode 100644 index 0000000..2642363 --- /dev/null +++ b/NGINX.md @@ -0,0 +1,130 @@ + + +# Nginx Integration + +This document explains how nginx is integrated into the frontend to serve the React SPA and proxy API requests to the FastAPI backend. + +## Overview + +The frontend uses a multi-stage Docker build: + +1. **Build stage**: Bun compiles the React app with Vite → static files in `dist/` +2. **Runtime stage**: nginx serves those static files and proxies `/api` to the backend + +``` +┌─────────────┐ ┌──────────────────────────────────────┐ ┌──────────┐ +│ Browser │────▶│ nginx (frontend container :80) │────▶│ Backend │ +│ │ │ • / → static files (SPA) │ │ :8000 │ +│ │ │ • /api/* → proxy to backend │ │ │ +└─────────────┘ └──────────────────────────────────────┘ └──────────┘ +``` + +## Files Involved + +| File | Purpose | +|------|---------| +| `frontend/nginx.conf` | nginx server block (static + proxy rules) | +| `frontend/Dockerfile` | Multi-stage build: Bun → nginx | + +## nginx Configuration + +### Static file serving + +```nginx +root /usr/share/nginx/html; +index index.html; + +location / { + try_files $uri $uri/ /index.html; +} +``` + +- **root**: Vite build output is copied to `/usr/share/nginx/html` in the container +- **try_files**: For client-side routing (React Router), any non-file path falls back to `index.html` so the SPA handles the route + +### API proxy + +```nginx +location /api { + rewrite ^/api/?(.*) /$1 break; + proxy_pass http://backend:8000; + proxy_http_version 1.1; + 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; +} +``` + +| Directive | Purpose | +|-----------|---------| +| `rewrite ^/api/?(.*) /$1 break` | Strips `/api` prefix. `/api/health` → `/health`, `/api` → `/` | +| `proxy_pass http://backend:8000` | Forwards to the backend service on the Docker network | +| `proxy_set_header Host` | Preserves the original Host header | +| `proxy_set_header X-Real-IP` | Passes client IP for logging/rate-limiting | +| `proxy_set_header X-Forwarded-For` | Chain of proxies for debugging | +| `proxy_set_header X-Forwarded-Proto` | Original scheme (http/https) for redirects | + +### Gzip + +```nginx +gzip on; +gzip_types text/plain text/css application/json application/javascript text/xml application/xml; +``` + +Compresses responses to reduce transfer size. + +## Docker Integration + +### Dockerfile + +```dockerfile +FROM nginx:alpine AS runtime + +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] +``` + +- Static files from the build stage go to `/usr/share/nginx/html` +- `nginx.conf` replaces the default server config in `/etc/nginx/conf.d/` +- `daemon off` keeps nginx in the foreground for Docker + +### Service discovery + +The backend is reached as `http://backend:8000` via Docker Compose service name. Both services share `dokploy-network`, so nginx can resolve and connect to the backend. + +## Frontend API usage + +The React app uses relative URLs so it works in dev and production: + +```typescript +const API_BASE = '/api' + +fetch(`${API_BASE}/health`) // → /api/health → nginx → backend:8000/health +``` + +- **Development**: Vite dev server proxies `/api` to `localhost:8000` +- **Production**: nginx proxies `/api` to `backend:8000` + +Same code path, different proxy layer. + +## Request flow examples + +| Browser request | nginx action | Backend receives | +|----------------|---------------|------------------| +| `GET /` | Serve `index.html` | — | +| `GET /assets/index-xxx.js` | Serve static file | — | +| `GET /dashboard` | Serve `index.html` (SPA route) | — | +| `GET /api/health` | Proxy to backend | `GET /health` | +| `GET /api` | Proxy to backend | `GET /` | + +## Customization + +- **Backend host/port**: Change `proxy_pass http://backend:8000` if the backend service name or port changes +- **API prefix**: To use a different prefix (e.g. `/v1`), update both `nginx.conf` and `src/lib/api.ts` +- **Static caching**: Add `expires` or `add_header Cache-Control` in the `location /` block for stronger caching +