8.7 KiB
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
.envfile with required environment variables (see Configuration)
Quick Start
- Clone the repository and navigate to the project root:
cd ai.allucanget.biz
- Configure environment variables in
.env:
# 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
- Build and start the services:
docker compose up --build
-
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)
-
View logs:
# All services
docker compose logs -f
# Specific service
docker compose logs -f backend
docker compose logs -f frontend
- Stop the services:
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 | AI Allucanget |
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
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
# Rebuild all services
docker compose build
# Rebuild a specific service
docker compose build backend
docker compose build frontend
Access container shell
# Backend shell
docker compose exec backend bash
# Frontend shell
docker compose exec frontend bash
View service logs
# 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
# 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:
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:
- Backend service is running:
docker compose ps BACKEND_URLin.envis set tohttp://backend:12015(notlocalhost)- Services are on the same Docker network:
docker compose psshows them in the samedocker-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:
- The
data/directory exists on your host - The volume is mounted correctly in
docker-compose.yml - DuckDB has write permissions to the
data/directory
Performance Tips
- Development: Use
docker compose upfor real-time logs and quick iterations - Background: Use
docker compose up -dto run services detached - Rebuilds: Use
docker compose up --buildonly when dependencies or Dockerfiles change - Caching: Docker caches layers; unchanged steps build faster
Next Steps
- Deployment: See Coolify Deployment for production deployment
- Testing: See Testing Guide for running tests
- Architecture: See Deployment View for system architecture