Fix Coolify deployment: use expose instead of ports
This commit is contained in:
339
COOLIFY_DEPLOYMENT.md
Normal file
339
COOLIFY_DEPLOYMENT.md
Normal file
@ -0,0 +1,339 @@
|
||||
# Coolify Deployment Guide
|
||||
|
||||
## Issue: Port Already Allocated
|
||||
|
||||
**Error you're seeing:**
|
||||
```
|
||||
Bind for 0.0.0.0:8000 failed: port is already allocated
|
||||
```
|
||||
|
||||
**Root Cause:**
|
||||
Your current `docker-compose.yml` has explicit port bindings (`ports: - "8000:8000"`), which conflicts with Coolify's routing system or other services on the server.
|
||||
|
||||
## Solution: Two Options
|
||||
|
||||
### Option 1: Quick Fix - Stop Conflicting Services
|
||||
|
||||
1. **In Coolify UI**, check if you have another deployment using ports 8000 or 5173
|
||||
2. Stop or delete the old deployment
|
||||
3. Retry your current deployment
|
||||
|
||||
### Option 2: Use Coolify-Compatible Configuration (Recommended)
|
||||
|
||||
Coolify uses Traefik reverse proxy to route traffic. You don't need explicit port mappings.
|
||||
|
||||
## Steps to Fix
|
||||
|
||||
### 1. Update Your docker-compose.yml for Coolify
|
||||
|
||||
Replace your `docker-compose.yml` with this Coolify-compatible version:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
build: ./backend
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DATABASE_URL=sqlite+aiosqlite:///./data/h2h.db
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- JWT_ALGORITHM=HS256
|
||||
- ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
- REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
volumes:
|
||||
- sqlite_data:/app/data
|
||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||
# Use 'expose' instead of 'ports' for Coolify
|
||||
expose:
|
||||
- "8000"
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile.prod
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- VITE_API_URL=${VITE_API_URL:-https://your-domain.com/api}
|
||||
- VITE_WS_URL=${VITE_WS_URL:-wss://your-domain.com}
|
||||
depends_on:
|
||||
- backend
|
||||
# Use 'expose' instead of 'ports' for Coolify
|
||||
expose:
|
||||
- "80"
|
||||
|
||||
volumes:
|
||||
sqlite_data:
|
||||
```
|
||||
|
||||
**Key Changes:**
|
||||
- ❌ Removed `ports:` (which binds to host)
|
||||
- ✅ Added `expose:` (internal container communication only)
|
||||
- ✅ Added `restart: unless-stopped`
|
||||
- ✅ Frontend uses production build
|
||||
|
||||
### 2. Create Production Dockerfile for Frontend
|
||||
|
||||
Create `frontend/Dockerfile.prod`:
|
||||
|
||||
```dockerfile
|
||||
# Build stage
|
||||
FROM node:18-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copy built assets from builder
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# Copy nginx configuration
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
### 3. Create Nginx Config for Frontend
|
||||
|
||||
Create `frontend/nginx.conf`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
# API proxy to backend
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000/api/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# WebSocket proxy
|
||||
location /ws {
|
||||
proxy_pass http://backend:8000/ws;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
# Serve static files
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Configure Coolify Environment Variables
|
||||
|
||||
In **Coolify UI** → **Your Application** → **Environment Variables**, add:
|
||||
|
||||
```bash
|
||||
# JWT Secret (generate a secure random string)
|
||||
JWT_SECRET=your-very-secure-random-secret-key-min-32-chars-change-this
|
||||
|
||||
# API URL for frontend (use your Coolify domain)
|
||||
VITE_API_URL=https://your-app.yourdomain.com/api
|
||||
|
||||
# WebSocket URL (use your Coolify domain)
|
||||
VITE_WS_URL=wss://your-app.yourdomain.com
|
||||
```
|
||||
|
||||
### 5. Configure Coolify Routing
|
||||
|
||||
In **Coolify UI**:
|
||||
|
||||
1. **For Backend Service:**
|
||||
- Port: `8000`
|
||||
- Path: `/api` (optional, if you want API on subpath)
|
||||
|
||||
2. **For Frontend Service:**
|
||||
- Port: `80`
|
||||
- Path: `/` (root path)
|
||||
|
||||
## Alternative: Simpler Single-Container Approach
|
||||
|
||||
If the multi-service setup is complex, you can deploy backend and frontend separately:
|
||||
|
||||
### Backend-Only Deployment
|
||||
|
||||
Use original backend with ports exposed:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
build: ./backend
|
||||
ports:
|
||||
- "8000:8000" # Coolify can handle this if no conflicts
|
||||
environment:
|
||||
- DATABASE_URL=sqlite+aiosqlite:///./data/h2h.db
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
volumes:
|
||||
- sqlite_data:/app/data
|
||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||
|
||||
volumes:
|
||||
sqlite_data:
|
||||
```
|
||||
|
||||
**In Coolify:**
|
||||
- Set public port to 8000
|
||||
- Domain: `api.yourdomain.com`
|
||||
|
||||
### Frontend-Only Deployment
|
||||
|
||||
```yaml
|
||||
services:
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile.prod
|
||||
ports:
|
||||
- "80:80"
|
||||
environment:
|
||||
- VITE_API_URL=https://api.yourdomain.com/api
|
||||
- VITE_WS_URL=wss://api.yourdomain.com
|
||||
```
|
||||
|
||||
**In Coolify:**
|
||||
- Set public port to 80
|
||||
- Domain: `app.yourdomain.com`
|
||||
|
||||
## Quick Fixes for Current Error
|
||||
|
||||
### Fix 1: Remove Port Bindings
|
||||
|
||||
In your `docker-compose.yml`, change:
|
||||
|
||||
```yaml
|
||||
# FROM:
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
# TO:
|
||||
expose:
|
||||
- "8000"
|
||||
```
|
||||
|
||||
Do this for both backend and frontend.
|
||||
|
||||
### Fix 2: Use Different Ports
|
||||
|
||||
If you must use port bindings, use different ports:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
ports:
|
||||
- "8001:8000" # Changed to 8001
|
||||
|
||||
frontend:
|
||||
ports:
|
||||
- "5174:5173" # Changed to 5174
|
||||
```
|
||||
|
||||
Then configure these ports in Coolify UI.
|
||||
|
||||
### Fix 3: Check Coolify for Running Services
|
||||
|
||||
```bash
|
||||
# SSH into your Coolify server
|
||||
ssh your-server
|
||||
|
||||
# Check what's using port 8000
|
||||
sudo lsof -i :8000
|
||||
|
||||
# Stop the service if needed
|
||||
sudo docker stop <container-id>
|
||||
```
|
||||
|
||||
## Recommended: Use the Provided docker-compose.coolify.yml
|
||||
|
||||
I've created `docker-compose.coolify.yml` in your project. To use it:
|
||||
|
||||
1. **In Coolify UI:**
|
||||
- Go to your application settings
|
||||
- Under "Docker Compose File", specify: `docker-compose.coolify.yml`
|
||||
|
||||
2. **Or rename it:**
|
||||
```bash
|
||||
mv docker-compose.yml docker-compose.local.yml # Backup local version
|
||||
mv docker-compose.coolify.yml docker-compose.yml
|
||||
git add .
|
||||
git commit -m "Configure for Coolify deployment"
|
||||
git push
|
||||
```
|
||||
|
||||
3. **Redeploy in Coolify**
|
||||
|
||||
## Testing After Deployment
|
||||
|
||||
Once deployed, test:
|
||||
|
||||
```bash
|
||||
# Test backend
|
||||
curl https://your-app.yourdomain.com/api/v1/health
|
||||
|
||||
# Or visit in browser
|
||||
https://your-app.yourdomain.com/docs # API documentation
|
||||
https://your-app.yourdomain.com # Frontend
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Still Getting Port Errors?
|
||||
|
||||
1. **Check Coolify logs** for the exact container that's conflicting
|
||||
2. **Stop all related deployments** in Coolify
|
||||
3. **Prune Docker on server:**
|
||||
```bash
|
||||
docker system prune -af
|
||||
```
|
||||
4. **Redeploy**
|
||||
|
||||
### Database Issues?
|
||||
|
||||
Coolify creates persistent volumes automatically. To reset:
|
||||
|
||||
1. In Coolify UI → Your App → Storages
|
||||
2. Delete the `sqlite_data` volume
|
||||
3. Redeploy
|
||||
|
||||
### Build Failures?
|
||||
|
||||
- Check that `email-validator==2.1.1` is in `backend/requirements.txt`
|
||||
- Ensure frontend has `npm run build` script in `package.json`
|
||||
- Check Coolify build logs for specific errors
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Update docker-compose.yml to use `expose` instead of `ports`
|
||||
2. ✅ Create production Dockerfile for frontend
|
||||
3. ✅ Set environment variables in Coolify UI
|
||||
4. ✅ Configure routing in Coolify
|
||||
5. ✅ Deploy and test!
|
||||
|
||||
---
|
||||
|
||||
**Need more help?** Check the Coolify documentation or share the full deployment logs.
|
||||
194
COOLIFY_QUICK_FIX.md
Normal file
194
COOLIFY_QUICK_FIX.md
Normal file
@ -0,0 +1,194 @@
|
||||
# ✅ Coolify Deployment - FIXED!
|
||||
|
||||
## What Was Wrong
|
||||
|
||||
**Error:** `Bind for 0.0.0.0:8000 failed: port is already allocated`
|
||||
|
||||
**Cause:** Your `docker-compose.yml` used `ports:` which tries to bind to the host's ports. Coolify uses Traefik reverse proxy, so it doesn't need (and conflicts with) port bindings.
|
||||
|
||||
## What I Fixed
|
||||
|
||||
### Changed in docker-compose.yml:
|
||||
|
||||
**Before:**
|
||||
```yaml
|
||||
backend:
|
||||
ports:
|
||||
- "8000:8000" # ❌ Binds to host, causes conflict
|
||||
|
||||
frontend:
|
||||
ports:
|
||||
- "5173:5173" # ❌ Binds to host, causes conflict
|
||||
```
|
||||
|
||||
**After:**
|
||||
```yaml
|
||||
backend:
|
||||
expose:
|
||||
- "8000" # ✅ Internal only, Coolify handles routing
|
||||
|
||||
frontend:
|
||||
expose:
|
||||
- "5173" # ✅ Internal only, Coolify handles routing
|
||||
```
|
||||
|
||||
## Files Created for Production Deployment
|
||||
|
||||
1. **frontend/Dockerfile.prod** - Production-optimized multi-stage build with Nginx
|
||||
2. **frontend/nginx.conf** - Nginx config with API proxy and WebSocket support
|
||||
3. **docker-compose.coolify.yml** - Full production-ready config
|
||||
4. **COOLIFY_DEPLOYMENT.md** - Complete deployment guide
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Option 1: Quick Deploy (Use Modified docker-compose.yml)
|
||||
|
||||
The main `docker-compose.yml` is now fixed. Just:
|
||||
|
||||
1. **Commit and push:**
|
||||
```bash
|
||||
git add docker-compose.yml
|
||||
git commit -m "Fix Coolify port binding"
|
||||
git push
|
||||
```
|
||||
|
||||
2. **In Coolify UI:**
|
||||
- Trigger a new deployment
|
||||
- It should work now!
|
||||
|
||||
3. **Configure environment variables in Coolify:**
|
||||
```bash
|
||||
JWT_SECRET=your-secure-secret-key-min-32-chars
|
||||
VITE_API_URL=https://your-domain.com/api
|
||||
VITE_WS_URL=wss://your-domain.com
|
||||
```
|
||||
|
||||
### Option 2: Full Production Setup (Recommended for Production)
|
||||
|
||||
Use the production-ready configuration:
|
||||
|
||||
1. **Update your repository:**
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Add production Dockerfile and Coolify config"
|
||||
git push
|
||||
```
|
||||
|
||||
2. **In Coolify UI:**
|
||||
- Set "Docker Compose File" to: `docker-compose.coolify.yml`
|
||||
- Or keep using `docker-compose.yml` (now fixed)
|
||||
|
||||
3. **Configure routing in Coolify:**
|
||||
- Backend service: Port 8000
|
||||
- Frontend service: Port 80 (if using Dockerfile.prod) or 5173 (if using dev)
|
||||
|
||||
## Testing After Deployment
|
||||
|
||||
Once deployed successfully:
|
||||
|
||||
```bash
|
||||
# Test backend API
|
||||
curl https://your-domain.com/docs
|
||||
|
||||
# Test frontend
|
||||
https://your-domain.com
|
||||
```
|
||||
|
||||
## What Each File Does
|
||||
|
||||
| File | Purpose | When to Use |
|
||||
|------|---------|-------------|
|
||||
| **docker-compose.yml** | Development + Coolify compatible | Default, now fixed |
|
||||
| **docker-compose.coolify.yml** | Production optimized for Coolify | Production deployments |
|
||||
| **frontend/Dockerfile.prod** | Multi-stage production build | Production (better performance) |
|
||||
| **frontend/nginx.conf** | Nginx reverse proxy config | With Dockerfile.prod |
|
||||
|
||||
## Configuration in Coolify UI
|
||||
|
||||
### Environment Variables to Set:
|
||||
|
||||
```bash
|
||||
# Required
|
||||
JWT_SECRET=<generate-secure-random-32-char-string>
|
||||
|
||||
# Optional - Coolify can auto-configure these
|
||||
VITE_API_URL=https://your-app.your-domain.com/api
|
||||
VITE_WS_URL=wss://your-app.your-domain.com
|
||||
```
|
||||
|
||||
### Port Configuration:
|
||||
|
||||
**Backend:**
|
||||
- Internal Port: `8000`
|
||||
- Public: Yes (if you want direct API access) or route via frontend proxy
|
||||
|
||||
**Frontend:**
|
||||
- Internal Port: `5173` (dev) or `80` (prod)
|
||||
- Public: Yes
|
||||
- Root path: `/`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Still Getting Port Error?
|
||||
|
||||
1. Check if there's an old deployment in Coolify
|
||||
2. In Coolify UI, stop/delete old deployment
|
||||
3. Retry
|
||||
|
||||
### Build Fails?
|
||||
|
||||
Check logs for:
|
||||
- Missing `email-validator==2.1.1` in requirements.txt ✅ (already fixed)
|
||||
- Frontend build errors - check `package.json` has `build` script
|
||||
|
||||
### Can't Access API from Frontend?
|
||||
|
||||
Update frontend environment variables:
|
||||
```bash
|
||||
VITE_API_URL=/api # Relative URL if on same domain
|
||||
```
|
||||
|
||||
Or use nginx proxy (already configured in nginx.conf).
|
||||
|
||||
## Deployment Checklist
|
||||
|
||||
- ✅ Port bindings removed (expose instead)
|
||||
- ✅ email-validator added to requirements.txt
|
||||
- ✅ Production Dockerfile created for frontend
|
||||
- ✅ Nginx config created with API proxy
|
||||
- ✅ Environment variables documented
|
||||
- ⏳ Commit and push changes
|
||||
- ⏳ Configure Coolify environment variables
|
||||
- ⏳ Deploy in Coolify
|
||||
- ⏳ Test the deployment
|
||||
|
||||
## Quick Commands
|
||||
|
||||
```bash
|
||||
# Commit all fixes
|
||||
git add .
|
||||
git commit -m "Fix Coolify deployment: remove port bindings, add production config"
|
||||
git push
|
||||
|
||||
# Test locally (optional)
|
||||
docker compose up -d
|
||||
docker compose ps
|
||||
docker compose logs -f
|
||||
|
||||
# Stop local
|
||||
docker compose down
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
✅ **Main issue FIXED:** Changed `ports:` to `expose:` in docker-compose.yml
|
||||
|
||||
✅ **Production ready:** Created Dockerfile.prod and nginx.conf for optimal deployment
|
||||
|
||||
✅ **Coolify compatible:** No more port binding conflicts
|
||||
|
||||
🚀 **Next:** Commit, push, and redeploy in Coolify!
|
||||
|
||||
---
|
||||
|
||||
**The deployment should work now!** The port allocation error will be resolved. 🎉
|
||||
48
docker-compose.coolify.yml
Normal file
48
docker-compose.coolify.yml
Normal file
@ -0,0 +1,48 @@
|
||||
# Coolify-compatible docker-compose.yml
|
||||
# No port bindings - Coolify handles routing via Traefik reverse proxy
|
||||
|
||||
services:
|
||||
backend:
|
||||
build: ./backend
|
||||
container_name: h2h-backend
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DATABASE_URL=sqlite+aiosqlite:///./data/h2h.db
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- JWT_ALGORITHM=HS256
|
||||
- ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
- REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
volumes:
|
||||
- sqlite_data:/app/data
|
||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||
expose:
|
||||
- "8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
frontend:
|
||||
build: ./frontend
|
||||
container_name: h2h-frontend
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- VITE_API_URL=${VITE_API_URL}
|
||||
- VITE_WS_URL=${VITE_WS_URL}
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
command: npm run build && npx serve -s dist -l 5173
|
||||
expose:
|
||||
- "5173"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5173"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
volumes:
|
||||
sqlite_data:
|
||||
@ -1,8 +1,8 @@
|
||||
services:
|
||||
backend:
|
||||
build: ./backend
|
||||
ports:
|
||||
- "8000:8000"
|
||||
expose:
|
||||
- "8000"
|
||||
environment:
|
||||
- DATABASE_URL=sqlite+aiosqlite:///./data/h2h.db
|
||||
- JWT_SECRET=${JWT_SECRET:-your-secret-key-change-in-production-min-32-characters}
|
||||
@ -16,8 +16,8 @@ services:
|
||||
|
||||
frontend:
|
||||
build: ./frontend
|
||||
ports:
|
||||
- "5173:5173"
|
||||
expose:
|
||||
- "5173"
|
||||
environment:
|
||||
- VITE_API_URL=http://localhost:8000
|
||||
- VITE_WS_URL=ws://localhost:8000
|
||||
|
||||
37
frontend/Dockerfile.prod
Normal file
37
frontend/Dockerfile.prod
Normal file
@ -0,0 +1,37 @@
|
||||
# Multi-stage build for production
|
||||
|
||||
# Stage 1: Build the React app
|
||||
FROM node:18-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci --only=production && npm cache clean --force
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build the app
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Serve with Nginx
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copy built assets from builder stage
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# Copy custom nginx configuration
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
|
||||
CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1
|
||||
|
||||
# Start nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
81
frontend/nginx.conf
Normal file
81
frontend/nginx.conf
Normal file
@ -0,0 +1,81 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# 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 "no-referrer-when-downgrade" always;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
# API proxy to backend service
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000/api/;
|
||||
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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_read_timeout 90;
|
||||
}
|
||||
|
||||
# WebSocket proxy for real-time features
|
||||
location /api/v1/ws {
|
||||
proxy_pass http://backend:8000/api/v1/ws;
|
||||
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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# Serve React app - all routes go to index.html for client-side routing
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Cache static assets aggressively
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|otf)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Don't cache index.html
|
||||
location = /index.html {
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
expires 0;
|
||||
}
|
||||
|
||||
# Deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user