Remove Docker Compose configuration files and update deployment documentation for Coolify with Nixpacks
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -58,6 +58,22 @@ flask --app app.main run --port 12016
|
|||||||
pytest
|
pytest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Default admin user
|
||||||
|
|
||||||
|
On first startup a default admin account is created:
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| -------- | ------------------- |
|
||||||
|
| Email | `ai@allucanget.biz` |
|
||||||
|
| Password | `admin123` |
|
||||||
|
| Role | `admin` |
|
||||||
|
|
||||||
|
Override via environment variables `ADMIN_EMAIL` and `ADMIN_PASSWORD` before first run.
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
Deployed on [Coolify](https://coolify.io) using Nixpacks. See [docs/deployment/coolify.md](docs/deployment/coolify.md) for full instructions.
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
services:
|
|
||||||
backend:
|
|
||||||
build:
|
|
||||||
context: ./backend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
environment:
|
|
||||||
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
|
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
|
||||||
- APP_URL=${APP_URL:-https://ai.allucanget.biz}
|
|
||||||
- APP_NAME=${APP_NAME:-All You Can GET AI}
|
|
||||||
- CORS_ORIGINS=${CORS_ORIGINS:-https://ai.allucanget.biz}
|
|
||||||
volumes:
|
|
||||||
- app-data:/app/data
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
healthcheck:
|
|
||||||
test: [ "CMD", "curl", "-f", "http://localhost:12015/health" ]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 5s
|
|
||||||
expose:
|
|
||||||
- "12015"
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
build:
|
|
||||||
context: ./frontend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
environment:
|
|
||||||
- FLASK_SECRET_KEY=${FLASK_SECRET_KEY}
|
|
||||||
- BACKEND_URL=${BACKEND_URL:-http://backend:12015}
|
|
||||||
depends_on:
|
|
||||||
backend:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
expose:
|
|
||||||
- "12016"
|
|
||||||
|
|
||||||
networks:
|
|
||||||
app-network:
|
|
||||||
driver: bridge
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
app-data:
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
services:
|
|
||||||
backend:
|
|
||||||
build:
|
|
||||||
context: ./backend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: ai-backend
|
|
||||||
ports:
|
|
||||||
- "12015:12015"
|
|
||||||
environment:
|
|
||||||
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
|
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
|
||||||
- APP_URL=${APP_URL:-http://localhost}
|
|
||||||
- APP_NAME=${APP_NAME:-All You Can GET AI}
|
|
||||||
- CORS_ORIGINS=${CORS_ORIGINS:-http://localhost:12016}
|
|
||||||
volumes:
|
|
||||||
- ./data:/app/data
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
healthcheck:
|
|
||||||
test: [ "CMD", "curl", "-f", "http://localhost:12015/health" ]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 5s
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
build:
|
|
||||||
context: ./frontend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: ai-frontend
|
|
||||||
ports:
|
|
||||||
- "12016:12016"
|
|
||||||
environment:
|
|
||||||
- FLASK_SECRET_KEY=${FLASK_SECRET_KEY}
|
|
||||||
- BACKEND_URL=${BACKEND_URL:-http://backend:12015}
|
|
||||||
depends_on:
|
|
||||||
backend:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
|
|
||||||
nginx:
|
|
||||||
image: nginx:alpine
|
|
||||||
container_name: ai-nginx
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
volumes:
|
|
||||||
- ./nginx/docker-compose.conf:/etc/nginx/conf.d/default.conf:ro
|
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
- frontend
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
|
|
||||||
networks:
|
|
||||||
app-network:
|
|
||||||
driver: bridge
|
|
||||||
+22
-53
@@ -39,68 +39,37 @@ Describes:
|
|||||||
|
|
||||||
## Infrastructure Level 2
|
## Infrastructure Level 2
|
||||||
|
|
||||||
### Docker Compose (Recommended for Development & Production)
|
### Coolify with Nixpacks (Production)
|
||||||
|
|
||||||
All services are containerized and orchestrated with `docker compose`:
|
Both services are deployed as separate Nixpacks resources in Coolify:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────┐
|
||||||
│ Docker Host / VM │
|
│ Coolify Server │
|
||||||
│ ┌──────────────────────────────────────────────────────┐ │
|
│ ┌────────────────────────────┐ │
|
||||||
│ │ Docker Network: app-network (bridge) │ │
|
│ │ Backend Service (FastAPI) │ │
|
||||||
│ │ ┌──────────────────────────────────────────────┐ │ │
|
│ │ - Base Dir: /backend │ │
|
||||||
│ │ │ Backend Container (FastAPI) │ │ │
|
│ │ - Port: 12015 │ │
|
||||||
│ │ │ - Port: 12015 │ │ │
|
│ │ - Volume: /app/data │ │
|
||||||
│ │ │ - Service Name: backend │ │ │
|
│ ├────────────────────────────┤ │
|
||||||
│ │ │ - Volume Mount: /app/data ← host/data/ │ │ │
|
│ │ Frontend Service (Flask) │ │
|
||||||
│ │ ├──────────────────────────────────────────────┤ │ │
|
│ │ - Base Dir: /frontend │ │
|
||||||
│ │ │ Frontend Container (Flask) │ │ │
|
│ │ - Port: 12016 (public) │ │
|
||||||
│ │ │ - Port: 12016 │ │ │
|
│ │ - BACKEND_URL: :12015 │ │
|
||||||
│ │ │ - Service Name: frontend │ │ │
|
│ └────────────────────────────┘ │
|
||||||
│ │ │ - Depends on: backend (health check) │ │ │
|
|
||||||
│ │ ├──────────────────────────────────────────────┤ │ │
|
|
||||||
│ │ │ Nginx Container (Reverse Proxy) │ │ │
|
|
||||||
│ │ │ - Port: 80 (HTTP), 443 (HTTPS) │ │ │
|
|
||||||
│ │ │ - Config: nginx/docker-compose.conf │ │ │
|
|
||||||
│ │ │ - Routes: /api/* → backend:12015 │ │ │
|
|
||||||
│ │ │ / → frontend:12016 │ │ │
|
|
||||||
│ │ └──────────────────────────────────────────────┘ │ │
|
|
||||||
│ └──────────────────────────────────────────────────────┘ │
|
|
||||||
│ ▲ │
|
│ ▲ │
|
||||||
│ Host Port Bindings │
|
│ Coolify reverse proxy (TLS termination) │
|
||||||
│ 80:80, 443:443, 12015:12015, 12016:12016 │
|
└──────────────────────────────────────────────────────────┘
|
||||||
└─────────────────────────────────────────────────────────────┘
|
|
||||||
│
|
│
|
||||||
Users / Internet
|
Users / Internet
|
||||||
```
|
```
|
||||||
|
|
||||||
**Deployment Steps:**
|
**Deployment Steps:**
|
||||||
|
|
||||||
1. Ensure Docker and Docker Compose are installed
|
1. Create backend Nixpacks service in Coolify with Base Directory `/backend`
|
||||||
2. Create `.env` with required environment variables
|
2. Create frontend Nixpacks service with Base Directory `/frontend`
|
||||||
3. Run: `docker compose up --build`
|
3. Set environment variables per service
|
||||||
4. Access via browser at `http://localhost:12016` or through Nginx at `http://localhost:80`
|
4. Attach domain to frontend on port `12016`
|
||||||
|
5. Enable Auto HTTPS in Coolify
|
||||||
**Benefits:**
|
|
||||||
|
|
||||||
- **Consistency**: Same containerized environment across development, testing, and production
|
|
||||||
- **Simplicity**: Single command to start entire stack
|
|
||||||
- **Portability**: Run on any system with Docker installed
|
|
||||||
- **Persistence**: DuckDB data survives container restarts via volume mounts
|
|
||||||
- **Networking**: Service names enable automatic DNS resolution (backend:12015, frontend:12016)
|
|
||||||
- **Observability**: Easy logging with `docker compose logs`
|
|
||||||
|
|
||||||
**See**: [Docker Compose Deployment Guide](./deployment/docker-compose.md) for detailed instructions.
|
|
||||||
|
|
||||||
### Coolify (Alternative for Existing Deployments)
|
|
||||||
|
|
||||||
If using Coolify instead of Docker Compose:
|
|
||||||
|
|
||||||
1. **Recommended Path**: Deploy `docker-compose.coolify.yml` as one Coolify Docker Compose resource
|
|
||||||
2. **Public Entry Point**: Route domain to `nginx` service on port 80; backend and frontend stay internal
|
|
||||||
3. **Data Persistence**: Named volume keeps DuckDB data at `/app/data`
|
|
||||||
4. **Fallback Path**: Use separate Nixpacks services only when one-stack Compose deploy is not suitable
|
|
||||||
|
|
||||||
**Note**: In Compose-based Coolify deployment, frontend reaches backend through Docker DNS at `http://backend:12015`. In Nixpacks-based deployment, use Coolify internal networking or colocate both services.
|
|
||||||
|
|
||||||
**See**: [Coolify Deployment Guide](./deployment/coolify.md) for detailed instructions.
|
**See**: [Coolify Deployment Guide](./deployment/coolify.md) for detailed instructions.
|
||||||
|
|||||||
+151
-74
@@ -1,30 +1,6 @@
|
|||||||
# Coolify Deployment Guide
|
# Coolify Deployment Guide
|
||||||
|
|
||||||
This guide covers deploying `ai.allucanget.biz` using [Coolify](https://coolify.io) from the repository `https://git.allucanget.biz/allucanget/ai.allucanget.biz.git`.
|
This guide covers deploying `ai.allucanget.biz` using [Coolify](https://coolify.io) with Nixpacks from the repository `https://git.allucanget.biz/allucanget/ai.allucanget.biz.git`.
|
||||||
|
|
||||||
## Deployment Options
|
|
||||||
|
|
||||||
The application supports two deployment approaches:
|
|
||||||
|
|
||||||
### Option 1: Docker Compose (Recommended)
|
|
||||||
|
|
||||||
- **Best for**: Coolify deployments, local development, consistent environments
|
|
||||||
- **Compose file**: `docker-compose.coolify.yml` in Coolify, `docker-compose.yml` locally
|
|
||||||
- **Key benefits**:
|
|
||||||
- Same containerized services locally and in production
|
|
||||||
- Built-in service orchestration and networking
|
|
||||||
- Easy volume management for data persistence
|
|
||||||
- Better debugging and log viewing
|
|
||||||
|
|
||||||
### Option 2: Coolify with Nixpacks (Alternative)
|
|
||||||
|
|
||||||
- **Best for**: Existing Coolify installations, serverless deployments
|
|
||||||
- **Key differences**:
|
|
||||||
- Uses Coolify's Nixpacks build system instead of Docker
|
|
||||||
- Requires separate services setup in Coolify UI
|
|
||||||
- Manual environment variable configuration per service
|
|
||||||
|
|
||||||
This guide covers both Coolify paths. Use **Option 1 (Docker Compose)** for new deployments. Use **Option 2 (Nixpacks)** only if you need separate Coolify services instead of one stack.
|
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
@@ -46,55 +22,6 @@ Coolify's built-in reverse proxy routes traffic:
|
|||||||
- Git repository pushed to `https://git.allucanget.biz/allucanget/ai.allucanget.biz.git`
|
- Git repository pushed to `https://git.allucanget.biz/allucanget/ai.allucanget.biz.git`
|
||||||
- Domain configured to point to your Coolify server
|
- Domain configured to point to your Coolify server
|
||||||
|
|
||||||
## Option 1: Deploy with Docker Compose in Coolify
|
|
||||||
|
|
||||||
Use Coolify's **Docker Compose** resource with the dedicated compose file `docker-compose.coolify.yml`.
|
|
||||||
|
|
||||||
### Step 1: Create Docker Compose Resource
|
|
||||||
|
|
||||||
1. In Coolify, click **Add Resource** → **Deploy a new resource** → **Docker Compose**
|
|
||||||
2. Connect your Git repository (`git.allucanget.biz`)
|
|
||||||
3. Select the `ai.allucanget.biz` repository and `main` branch
|
|
||||||
4. Set **Compose File** to `docker-compose.coolify.yml`
|
|
||||||
5. Set **Base Directory** to `/`
|
|
||||||
6. Select the `frontend` service as the public-facing service on port `12016`
|
|
||||||
7. Click **Create Resource**
|
|
||||||
|
|
||||||
### Step 2: Configure Environment Variables
|
|
||||||
|
|
||||||
Add these in Coolify before first deploy:
|
|
||||||
|
|
||||||
| Variable | Service | Example |
|
|
||||||
| -------------------- | ---------- | --------------------------- |
|
|
||||||
| `OPENROUTER_API_KEY` | `backend` | `sk-or-v1-...` |
|
|
||||||
| `JWT_SECRET` | `backend` | `openssl rand -hex 32` |
|
|
||||||
| `APP_URL` | `backend` | `https://ai.allucanget.biz` |
|
|
||||||
| `APP_NAME` | `backend` | `All You Can GET AI` |
|
|
||||||
| `CORS_ORIGINS` | `backend` | `https://ai.allucanget.biz` |
|
|
||||||
| `FLASK_SECRET_KEY` | `frontend` | `openssl rand -hex 32` |
|
|
||||||
| `BACKEND_URL` | `frontend` | `http://backend:12015` |
|
|
||||||
|
|
||||||
### Step 3: Configure Domain and Proxy
|
|
||||||
|
|
||||||
1. Attach domain `ai.allucanget.biz` to the `frontend` service on port `12016`
|
|
||||||
2. Enable **Auto HTTPS** in Coolify
|
|
||||||
3. Coolify terminates TLS and forwards traffic directly to `frontend:12016`
|
|
||||||
|
|
||||||
No nginx service is needed in the Coolify stack. The frontend Flask app proxies `/api/*` calls to `http://backend:12015` internally. Coolify's own reverse proxy handles external TLS termination.
|
|
||||||
|
|
||||||
### Step 4: Persistent Storage
|
|
||||||
|
|
||||||
`docker-compose.coolify.yml` uses named volume `app-data` for DuckDB persistence at `/app/data`. No extra host bind mount needed for default setup.
|
|
||||||
|
|
||||||
### Step 5: Deploy and Verify
|
|
||||||
|
|
||||||
1. Start deployment in Coolify
|
|
||||||
2. Confirm `backend` becomes healthy
|
|
||||||
3. Open `https://ai.allucanget.biz/health` or proxied health route configured in Coolify
|
|
||||||
4. Open main domain and verify frontend loads
|
|
||||||
|
|
||||||
## Option 2: Deploy with Nixpacks in Coolify
|
|
||||||
|
|
||||||
## Step 1: Create Backend Service
|
## Step 1: Create Backend Service
|
||||||
|
|
||||||
1. In Coolify, click **Add Resource** → **Deploy a new resource** → **Git**
|
1. In Coolify, click **Add Resource** → **Deploy a new resource** → **Git**
|
||||||
@@ -142,6 +69,156 @@ Add these as **Runtime** environment variables in Coolify:
|
|||||||
|
|
||||||
8. Click **Create Resource**
|
8. Click **Create Resource**
|
||||||
|
|
||||||
|
> **Note:** Nixpacks will automatically detect and install only the production dependencies from `requirements.txt`.
|
||||||
|
> **Important:** Nixpacks copies the **contents** of the Base Directory to `/app/` in the container. When Base Directory is `/frontend`, the `frontend/` folder wrapper is removed — only `app/`, `tests/`, and `requirements.txt` are copied. Therefore the start command uses `app.main:app` (not `frontend.app.main:app`).
|
||||||
|
|
||||||
|
### Frontend Environment Variables
|
||||||
|
|
||||||
|
Add these as **Runtime** environment variables in Coolify:
|
||||||
|
|
||||||
|
| Variable | Description | Example |
|
||||||
|
| ------------------ | ----------------------------------------- | --------------------------------------------------------------- |
|
||||||
|
| `FLASK_SECRET_KEY` | Flask session cookie signing key | Generate with `openssl rand -hex 32` |
|
||||||
|
| `BACKEND_URL` | Internal URL to reach the backend service | `http://localhost:12015` (or use Coolify's internal networking) |
|
||||||
|
|
||||||
|
## Step 3: Configure Reverse Proxy
|
||||||
|
|
||||||
|
Coolify provides a built-in reverse proxy. Configure routing rules:
|
||||||
|
|
||||||
|
### Backend Proxy Rules
|
||||||
|
|
||||||
|
- **Domain**: `api.ai.allucanget.biz` (or subdomain of your choice)
|
||||||
|
- **Port**: `12015`
|
||||||
|
- **Path**: `/api/*` → forward to backend
|
||||||
|
|
||||||
|
### Frontend Proxy Rules
|
||||||
|
|
||||||
|
- **Domain**: `ai.allucanget.biz`
|
||||||
|
- **Port**: `12016`
|
||||||
|
- **Path**: `/` → forward to frontend
|
||||||
|
|
||||||
|
## Step 4: SSL/TLS
|
||||||
|
|
||||||
|
Enable HTTPS in Coolify for both services:
|
||||||
|
|
||||||
|
1. Go to each service's settings
|
||||||
|
2. Enable **Auto HTTPS** (Let's Encrypt)
|
||||||
|
3. Configure domain names
|
||||||
|
4. Coolify automatically handles certificate renewal
|
||||||
|
|
||||||
|
## Step 5: Persistent Storage (Optional)
|
||||||
|
|
||||||
|
If you want to persist DuckDB data:
|
||||||
|
|
||||||
|
1. In Coolify, go to the **Backend** service
|
||||||
|
2. Navigate to **Persistent Storage**
|
||||||
|
3. Add a volume mount:
|
||||||
|
- **Host Path**: `/data` (or any path on the host)
|
||||||
|
- **Container Path**: `/app/data`
|
||||||
|
- **Type**: `Bind Mount` or `Volume`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Backend healthcheck stays unhealthy
|
||||||
|
|
||||||
|
- Check backend logs in Coolify
|
||||||
|
- Verify `OPENROUTER_API_KEY` and `JWT_SECRET` are set
|
||||||
|
- Verify volume mount at `/app/data` is writable
|
||||||
|
|
||||||
|
### Backend won't start
|
||||||
|
|
||||||
|
- Check that `OPENROUTER_API_KEY` is set
|
||||||
|
- Verify `JWT_SECRET` is a sufficiently long random string
|
||||||
|
- Check logs in Coolify's **Logs** tab
|
||||||
|
|
||||||
|
### Frontend can't reach backend
|
||||||
|
|
||||||
|
- Ensure `BACKEND_URL` points to the correct internal URL
|
||||||
|
- If both services are on the same Coolify server, use `http://localhost:12015`
|
||||||
|
- Check that the backend service is running and healthy
|
||||||
|
|
||||||
|
### CORS errors
|
||||||
|
|
||||||
|
- Set `CORS_ORIGINS` to include your frontend domain
|
||||||
|
- Example: `https://ai.allucanget.biz`
|
||||||
|
|
||||||
|
### Nixpacks build fails
|
||||||
|
|
||||||
|
- Verify the base directory is correct (`/backend` or `/frontend`)
|
||||||
|
- Check that `requirements.txt` exists in the base directory
|
||||||
|
- Review build logs in Coolify
|
||||||
|
|
||||||
|
## Environment Variable Summary
|
||||||
|
|
||||||
|
All required environment variables:
|
||||||
|
|
||||||
|
| Variable | Service | Required |
|
||||||
|
| -------------------- | -------- | ------------------------------------- |
|
||||||
|
| `OPENROUTER_API_KEY` | Backend | Yes |
|
||||||
|
| `JWT_SECRET` | Backend | Yes |
|
||||||
|
| `APP_URL` | Backend | Yes |
|
||||||
|
| `APP_NAME` | Backend | No (defaults to "All You Can GET AI") |
|
||||||
|
| `CORS_ORIGINS` | Backend | Yes |
|
||||||
|
| `FLASK_SECRET_KEY` | Frontend | Yes |
|
||||||
|
| `BACKEND_URL` | Frontend | Yes |
|
||||||
|
|
||||||
|
## Deployment Checklist
|
||||||
|
|
||||||
|
- [ ] Repository pushed to Git
|
||||||
|
- [ ] Backend service created with correct base directory (`/backend`)
|
||||||
|
- [ ] Backend environment variables configured
|
||||||
|
- [ ] Frontend service created with correct base directory (`/frontend`)
|
||||||
|
- [ ] Frontend environment variables configured
|
||||||
|
- [ ] SSL certificates enabled
|
||||||
|
- [ ] Domain names configured
|
||||||
|
- [ ] Health checks passing
|
||||||
|
- [ ] Logs reviewed for errors
|
||||||
|
|
||||||
|
1. In Coolify, click **Add Resource** → **Deploy a new resource** → **Git**
|
||||||
|
2. Connect your Git repository (`git.allucanget.biz`)
|
||||||
|
3. Select the `ai.allucanget.biz` repository
|
||||||
|
4. Choose the `main` branch
|
||||||
|
5. Set **Build Pack** to `nixpacks`
|
||||||
|
6. **CRITICAL: Set Base Directory to `/backend`** — this tells Nixpacks to look in the `backend/` subdirectory for `requirements.txt` and the Python application
|
||||||
|
7. Set **Ports Exposed** to `12015`
|
||||||
|
8. Set **Start Command** to:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
uvicorn app.main:app --host 0.0.0.0 --port 12015
|
||||||
|
```
|
||||||
|
|
||||||
|
9. Click **Create Resource**
|
||||||
|
|
||||||
|
> **Important:** Nixpacks copies the **contents** of the Base Directory to `/app/` in the container. When Base Directory is `/backend`, the `backend/` folder wrapper is removed — only `app/`, `tests/`, and `requirements.txt` are copied. Therefore the start command uses `app.main:app` (not `backend.app.main:app`).
|
||||||
|
|
||||||
|
### Backend Environment Variables
|
||||||
|
|
||||||
|
Add these as **Runtime** environment variables in Coolify:
|
||||||
|
|
||||||
|
| Variable | Description | Example |
|
||||||
|
| -------------------- | ------------------------------------ | ------------------------------------ |
|
||||||
|
| `OPENROUTER_API_KEY` | OpenRouter API key for AI generation | `sk-or-v1-...` |
|
||||||
|
| `JWT_SECRET` | Secret key for JWT token signing | Generate with `openssl rand -hex 32` |
|
||||||
|
| `APP_URL` | Public URL of the backend | `https://api.ai.allucanget.biz` |
|
||||||
|
| `APP_NAME` | Application name | `All You Can GET AI` |
|
||||||
|
| `CORS_ORIGINS` | Comma-separated allowed origins | `https://ai.allucanget.biz` |
|
||||||
|
|
||||||
|
## Step 2: Create Frontend Service
|
||||||
|
|
||||||
|
1. In Coolify, click **Add Resource** → **Deploy a new resource** → **Git**
|
||||||
|
2. Select the same repository
|
||||||
|
3. Choose the `main` branch
|
||||||
|
4. Set **Build Pack** to `nixpacks`
|
||||||
|
5. **CRITICAL: Set Base Directory to `/frontend`** — this tells Nixpacks to look in the `frontend/` subdirectory for `requirements.txt` and the Python application
|
||||||
|
6. Set **Ports Exposed** to `12016`
|
||||||
|
7. Set **Start Command** to:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
gunicorn app.main:app --bind 0.0.0.0:12016 --workers 2 --timeout 120
|
||||||
|
```
|
||||||
|
|
||||||
|
8. Click **Create Resource**
|
||||||
|
|
||||||
> **Note:** The frontend uses `requirements.txt` for production dependencies and `requirements-dev.txt` for development dependencies (like pytest). Nixpacks will automatically detect and install only the production dependencies.
|
> **Note:** The frontend uses `requirements.txt` for production dependencies and `requirements-dev.txt` for development dependencies (like pytest). Nixpacks will automatically detect and install only the production dependencies.
|
||||||
> **Important:** Nixpacks copies the **contents** of the Base Directory to `/app/` in the container. When Base Directory is `/frontend`, the `frontend/` folder wrapper is removed — only `app/`, `tests/`, and `requirements.txt` are copied. Therefore the start command uses `app.main:app` (not `frontend.app.main:app`).
|
> **Important:** Nixpacks copies the **contents** of the Base Directory to `/app/` in the container. When Base Directory is `/frontend`, the `frontend/` folder wrapper is removed — only `app/`, `tests/`, and `requirements.txt` are copied. Therefore the start command uses `app.main:app` (not `frontend.app.main:app`).
|
||||||
|
|
||||||
|
|||||||
@@ -1,243 +0,0 @@
|
|||||||
# Docker Compose Deployment Guide
|
|
||||||
|
|
||||||
This guide explains how to deploy the AI application locally using Docker Compose.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Docker Compose provides a convenient way to:
|
|
||||||
|
|
||||||
- **Develop locally** with the same containerized environment used in production
|
|
||||||
- **Manage services** as a single stack (backend, frontend, and Nginx)
|
|
||||||
- **Persist data** using volume mounts
|
|
||||||
- **Enable service-to-service communication** using Docker's internal networking
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- Docker Desktop installed and running
|
|
||||||
- Docker Compose v2.0+ (included with Docker Desktop)
|
|
||||||
- A `.env` file with required environment variables (see [Configuration](#configuration))
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
1. **Clone the repository** and navigate to the project root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ai.allucanget.biz
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Configure environment variables** in `.env`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Copy the example if you don't have a .env file
|
|
||||||
cp .env.example .env
|
|
||||||
|
|
||||||
# Edit .env and fill in required values
|
|
||||||
# - OPENROUTER_API_KEY: Your openrouter.ai API key
|
|
||||||
# - JWT_SECRET: A random secret for signing JWT tokens
|
|
||||||
# - FLASK_SECRET_KEY: A random secret for Flask session cookies
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Build and start the services**:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up --build
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Access the application**:
|
|
||||||
- Frontend UI: http://localhost:12016
|
|
||||||
- Backend API: http://localhost:12015
|
|
||||||
- API Health: http://localhost:12015/health
|
|
||||||
- Nginx Proxy: http://localhost:80 (routes to frontend) or http://localhost:80/api (routes to backend)
|
|
||||||
|
|
||||||
5. **View logs**:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# All services
|
|
||||||
docker compose logs -f
|
|
||||||
|
|
||||||
# Specific service
|
|
||||||
docker compose logs -f backend
|
|
||||||
docker compose logs -f frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
6. **Stop the services**:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
The `.env` file in the project root is automatically loaded by Docker Compose. Required variables:
|
|
||||||
|
|
||||||
| Variable | Purpose | Example |
|
|
||||||
| -------------------- | ------------------------------------------ | ---------------------------------------------------------------------------- |
|
|
||||||
| `OPENROUTER_API_KEY` | API key for AI generation | `sk-or-v1-...` |
|
|
||||||
| `JWT_SECRET` | Secret for JWT token signing | (random hex string) |
|
|
||||||
| `FLASK_SECRET_KEY` | Secret for Flask session cookies | (random hex string) |
|
|
||||||
| `BACKEND_URL` | Internal URL for frontend to reach backend | `http://backend:12015` (Docker) or `http://localhost:12015` (local dev) |
|
|
||||||
| `CORS_ORIGINS` | Allowed CORS origins for backend | `http://localhost:12016` (local) or `https://ai.allucanget.biz` (production) |
|
|
||||||
| `APP_URL` | Public URL of the backend | `http://localhost` or `https://ai.allucanget.biz` |
|
|
||||||
| `APP_NAME` | Application name | `All You Can GET AI` |
|
|
||||||
|
|
||||||
### Volume Mounts
|
|
||||||
|
|
||||||
The `docker-compose.yml` defines the following volume:
|
|
||||||
|
|
||||||
- `./data:/app/data` — Persists the DuckDB database (`app.db`) between container restarts
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Docker Network: app-network (internal bridge) │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────┐ ┌──────────────────────────┐ │
|
|
||||||
│ │ Frontend │ │ Backend │ │
|
|
||||||
│ │ Port 12016 │ │ Port 12015 │ │
|
|
||||||
│ │ Flask + Gunicorn│◄──►│ FastAPI + Uvicorn │ │
|
|
||||||
│ │ (Service name: │ │ (Service name: backend) │ │
|
|
||||||
│ │ frontend) │ │ │ │
|
|
||||||
│ └──────────────────┘ │ ┌────────────────────┐ │ │
|
|
||||||
│ ▲ │ │ DuckDB Database │ │ │
|
|
||||||
│ │ │ │ /app/data/app.db │ │ │
|
|
||||||
│ ┌────▼──────────────┐ │ └────────────────────┘ │ │
|
|
||||||
│ │ Nginx (Port 80) │ └──────────────────────────┘ │
|
|
||||||
│ │ Reverse Proxy │ │
|
|
||||||
│ └───────────────────┘ │
|
|
||||||
│ ▲ │
|
|
||||||
│ │ (bind mount) │
|
|
||||||
│ Host:80, 443 │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
│
|
|
||||||
Host OS
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Tasks
|
|
||||||
|
|
||||||
### View service status
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose ps
|
|
||||||
```
|
|
||||||
|
|
||||||
Output example:
|
|
||||||
|
|
||||||
```
|
|
||||||
NAME COMMAND SERVICE STATUS PORTS
|
|
||||||
ai-backend "uvicorn app.main:a…" backend Up 2m 0.0.0.0:12015->12015/tcp
|
|
||||||
ai-frontend "gunicorn app.main:…" frontend Up 2m 0.0.0.0:12016->12016/tcp
|
|
||||||
ai-nginx "nginx -g daemon of…" nginx Up 2m 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
|
|
||||||
```
|
|
||||||
|
|
||||||
### Rebuild images
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Rebuild all services
|
|
||||||
docker compose build
|
|
||||||
|
|
||||||
# Rebuild a specific service
|
|
||||||
docker compose build backend
|
|
||||||
docker compose build frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
### Access container shell
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Backend shell
|
|
||||||
docker compose exec backend bash
|
|
||||||
|
|
||||||
# Frontend shell
|
|
||||||
docker compose exec frontend bash
|
|
||||||
```
|
|
||||||
|
|
||||||
### View service logs
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Tail all logs
|
|
||||||
docker compose logs -f
|
|
||||||
|
|
||||||
# Follow only backend logs
|
|
||||||
docker compose logs -f backend
|
|
||||||
|
|
||||||
# Last 100 lines of frontend logs
|
|
||||||
docker compose logs --tail 100 frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clean up
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Stop containers but keep volumes and images
|
|
||||||
docker compose stop
|
|
||||||
|
|
||||||
# Stop and remove containers
|
|
||||||
docker compose down
|
|
||||||
|
|
||||||
# Stop containers and remove volumes (WARNING: deletes database!)
|
|
||||||
docker compose down -v
|
|
||||||
|
|
||||||
# Remove images as well
|
|
||||||
docker compose down --rmi all
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### "Docker daemon is not running"
|
|
||||||
|
|
||||||
**Error**: `error during connect: This error may indicate the client is not properly configured`
|
|
||||||
|
|
||||||
**Solution**: Start Docker Desktop (Windows/Mac) or start the Docker daemon (Linux).
|
|
||||||
|
|
||||||
### "Port 12015 or 12016 already in use"
|
|
||||||
|
|
||||||
**Error**: `Error response from daemon: bind: address already in use`
|
|
||||||
|
|
||||||
**Solution**: Either stop the other application using that port, or modify the ports in `docker-compose.yml`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
ports:
|
|
||||||
- "13000:12015" # Maps host:13000 to container:12015
|
|
||||||
- "13001:12016" # Maps host:13001 to container:12016
|
|
||||||
```
|
|
||||||
|
|
||||||
### Frontend cannot reach backend
|
|
||||||
|
|
||||||
**Error**: Connection refused or 502 Bad Gateway
|
|
||||||
|
|
||||||
**Ensure**:
|
|
||||||
|
|
||||||
1. Backend service is running: `docker compose ps`
|
|
||||||
2. `BACKEND_URL` in `.env` is set to `http://backend:12015` (not `localhost`)
|
|
||||||
3. Services are on the same Docker network: `docker compose ps` shows them in the same `docker-compose.yml`
|
|
||||||
|
|
||||||
### Database file not persisting
|
|
||||||
|
|
||||||
**Issue**: Data is lost after `docker compose down`
|
|
||||||
|
|
||||||
**Solution**: The volume mount `./data:/app/data` should persist data automatically. Check that:
|
|
||||||
|
|
||||||
1. The `data/` directory exists on your host
|
|
||||||
2. The volume is mounted correctly in `docker-compose.yml`
|
|
||||||
3. DuckDB has write permissions to the `data/` directory
|
|
||||||
|
|
||||||
## Performance Tips
|
|
||||||
|
|
||||||
- **Development**: Use `docker compose up` for real-time logs and quick iterations
|
|
||||||
- **Background**: Use `docker compose up -d` to run services detached
|
|
||||||
- **Rebuilds**: Use `docker compose up --build` only when dependencies or Dockerfiles change
|
|
||||||
- **Caching**: Docker caches layers; unchanged steps build faster
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
- **Deployment**: See [Coolify Deployment](./coolify.md) for production deployment
|
|
||||||
- **Testing**: See [Testing Guide](../TESTING.md) for running tests
|
|
||||||
- **Architecture**: See [Deployment View](../7-deployment-view.md) for system architecture
|
|
||||||
|
|
||||||
## Additional Resources
|
|
||||||
|
|
||||||
- [Docker Compose Documentation](https://docs.docker.com/compose/)
|
|
||||||
- [Docker Networking Guide](https://docs.docker.com/network/)
|
|
||||||
- [Best Practices for Writing Dockerfiles](https://docs.docker.com/develop/dev-best-practices/dockerfile_best-practices/)
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# Nginx reverse proxy configuration for Docker Compose deployment
|
|
||||||
# Place this in docker-compose.yml volume mount to /etc/nginx/conf.d/default.conf
|
|
||||||
|
|
||||||
# Backend API proxy - use Docker service name instead of localhost
|
|
||||||
upstream backend {
|
|
||||||
server backend:12015;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Frontend proxy - use Docker service name instead of localhost
|
|
||||||
upstream frontend {
|
|
||||||
server frontend:12016;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
# Backend API proxy
|
|
||||||
location /api/ {
|
|
||||||
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;
|
|
||||||
|
|
||||||
# WebSocket support (if needed in future)
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Frontend proxy
|
|
||||||
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;
|
|
||||||
|
|
||||||
# Static files caching
|
|
||||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
||||||
proxy_pass http://frontend;
|
|
||||||
expires 30d;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Health check endpoint
|
|
||||||
location /health {
|
|
||||||
proxy_pass http://backend;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user