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.
|
||||
Reference in New Issue
Block a user