Files
ai.allucanget.biz/docs/deployment/docker-compose.md
T

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 .env file with required environment variables (see Configuration)

Quick Start

  1. Clone the repository and navigate to the project root:
cd ai.allucanget.biz
  1. 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
  1. Build and start the services:
docker compose up --build
  1. Access the application:

  2. View logs:

# All services
docker compose logs -f

# Specific service
docker compose logs -f backend
docker compose logs -f frontend
  1. 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:

  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

Additional Resources