Local Testing (Docker Compose)
This guide runs both layers locally:
backend: FastAPI onhttp://localhost:8001frontend: Next.js onhttp://localhost:3000
No VPS web server (nginx) or TLS is used locally.
Prerequisites
- Docker installed.
- Docker Compose plugin available (or
docker-compose). - If you want the AI endpoints to work fully, you need an Ollama server reachable from the backend container.
Step 1: Create environment files
From the repo root (/home/paul/Apps/LNA/AI/lna-ai-api):
cp backend/docker/.env.backend.example backend/docker/.env.backend
cp frontend/docker/.env.frontend.example frontend/docker/.env.frontend
Step 2: Configure backend env (backend/docker/.env.backend)
At minimum, the backend must be able to start. Set:
SUPABASE_URLSUPABASE_KEY
Then decide how you want the model provider to work:
Option A (recommended for local): LNA_LLM_PROVIDER=ollama
The code uses Ollama for:
- chat generation (via the OpenAI-compatible streaming client)
- embeddings (via Ollama
embeddings)
If Ollama is running on your host machine, DO NOT use localhost inside the container. Use your host LAN IP:
- Set:
LNA_LLM_PROVIDER=ollamaOLLAMA_HOST=http://<YOUR_LAN_IP>:11434OLLAMA_EMBEDDING_HOST=http://<YOUR_LAN_IP>:11434
If Ollama is not reachable, the backend may still start, but /answer/stream will fail when called.
Option B: LNA_LLM_PROVIDER=deepseek
If you use DeepSeek, set:
LNA_LLM_PROVIDER=deepseekDEEPSEEK_API_KEYDEEPSEEK_BASE_URL(optional, defaults tohttps://api.deepseek.com)DEEPSEEK_MODEL(optional, defaults todeepseek-chat)
Note: embeddings still use Ollama. You still need Ollama running somewhere reachable and set OLLAMA_EMBEDDING_HOST.
Step 3: Configure frontend env (frontend/docker/.env.frontend)
Set for local development:
NEXT_PUBLIC_APP_URL=http://localhost:3000NEXT_PUBLIC_API_URL=http://localhost:8001NEXT_PUBLIC_AI_API_URL=http://localhost:8001
Step 4: Start everything
From the repo root:
First build can take a few minutes.
Understanding docker-compose.yml (what gets built/run)
This repoβs docker-compose.yml defines two services: backend and frontend.
- Paths are relative: paths like
env_file: backend/docker/.env.backendanddockerfile: backend/docker/Dockerfileare resolved relative to the folder that containsdocker-compose.yml(the repo root).
backend service
- Build:
context: .means the Docker build context is the repo root (so the Dockerfile can copy bothbackend/andlna_ai_agent.pyfrom the root).dockerfile: backend/docker/Dockerfileselects the backend Dockerfile.- Environment:
env_file: backend/docker/.env.backendloads variables into the container (Supabase/LLM config, etc).- Ports:
8001:8001exposes the API on your machine athttp://localhost:8001.- Restart policy:
unless-stoppedrestarts the container automatically if it crashes.
frontend service
- Build:
context: .uses the repo root as build context.dockerfile: frontend/docker/Dockerfileselects the frontend Dockerfile.- Environment:
env_file: frontend/docker/.env.frontendloads public Next.js env vars.- Dependency:
depends_on: [backend]startsbackendbeforefrontend(it does not wait for backend to be βreadyβ, only started).- Ports:
3000:3000exposes the app onhttp://localhost:3000.
What docker compose up --build does
docker compose: reads./docker-compose.ymlin the current directory.up: creates a private network for the project, then creates & starts the containers defined in the compose file.--build: if an image is missing (or the Dockerfile/context changed), it builds the images first, then starts containers from those images.- Ports: because
docker-compose.ymlmaps ports, you can reach services on your host: backend:localhost:8001frontend:localhost:3000
Useful compose commands (local testing)
- Start (build if needed):
- Start in background:
- Stop containers (keeps images):
- Rebuild everything from scratch (no cache):
Step 4A: Build images individually (without starting containers)
This is useful when you want to confirm Docker builds before running.
From the repo root:
- Build only backend image:
- Build only frontend image:
- Build both images:
Step 4B: Start containers individually (after building)
From the repo root:
- Start only backend:
- Start only frontend (will also start backend because it is a dependency):
Tip: add -d to run detached:
Step 4C: Build Dockerfiles directly (without compose)
This is the βraw Dockerβ way. Itβs helpful to understand what compose is doing.
From the repo root:
- Build backend image (uses
backend/docker/Dockerfile):
- Build frontend image (uses
frontend/docker/Dockerfile):
If you build this way, you must also docker run ... with ports and env yourself (compose normally handles that wiring for you).
Step 5: Verify backend
Open a new terminal and run:
You should receive a JSON response with status: "healthy".
Step 6: Verify frontend
Open in your browser:
http://localhost:3000
Step 7: View logs / troubleshoot
Backend logs:
Frontend logs:
Common failures:
- Backend container exits immediately:
- Check
SUPABASE_URL/SUPABASE_KEYare set correctly. /answer/streamfails:- Check
OLLAMA_HOST/OLLAMA_EMBEDDING_HOSTare reachable from inside the container.
Next step (optional)
If you want, I can modify docker-compose.yml to also run an Ollama container on the same Docker network so you donβt need LAN IPs.