4.4 KiB
4.4 KiB
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:
- Build stage: Bun compiles the React app with Vite → static files in
dist/ - Runtime stage: nginx serves those static files and proxies
/apito 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
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/htmlin the container - try_files: For client-side routing (React Router), any non-file path falls back to
index.htmlso the SPA handles the route
API proxy
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
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
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.confreplaces the default server config in/etc/nginx/conf.d/daemon offkeeps 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:
const API_BASE = '/api'
fetch(`${API_BASE}/health`) // → /api/health → nginx → backend:8000/health
- Development: Vite dev server proxies
/apitolocalhost:8000 - Production: nginx proxies
/apitobackend: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:8000if the backend service name or port changes - API prefix: To use a different prefix (e.g.
/v1), update bothnginx.confandsrc/lib/api.ts - Static caching: Add
expiresoradd_header Cache-Controlin thelocation /block for stronger caching