Self-Hosted Docker Compose

Clone the Future AGI repo and run the self-hosted stack locally with Docker Compose.

📝
TL;DR

Clone the repo, run docker compose up -d, create a user, and send your first trace to a self-hosted Future AGI stack running entirely on your machine.

TimeDifficultyPackage
15 min (10 to 15 min more for the first image pull)Beginnerfi-instrumentation-otel + traceai-openai
Prerequisites
  • Docker Engine 24.0+ and Docker Compose v2.24+ (docker --version, docker compose version)
  • 8+ GB RAM and 64+ GB disk allocated to Docker (Docker Desktop defaults of 2 to 4 GB will OOM-kill ClickHouse)
  • Linux, macOS, or Windows with WSL 2. ECS Fargate and Cloud Run are not supported because the code-executor service needs privileged: true
  • Python 3.11
  • An OpenAI API key

Install

pip install fi-instrumentation-otel traceai-openai openai
export FI_API_KEY="your-fi-api-key"
export FI_SECRET_KEY="your-fi-secret-key"
export FI_BASE_URL="http://localhost:8000"
export OPENAI_API_KEY="sk-..."

Tutorial

Clone the repo

git clone https://github.com/future-agi/future-agi.git
cd future-agi

Every service pulls a published image (futureagi/future-agi, futureagi/frontend, futureagi/fi-collector, and so on); there’s no source build. The first docker compose up downloads several GB of image layers; later boots reuse the cache.

You should see a future-agi/ directory with docker-compose.yml and .env.example at the root.

Configure .env

cp .env.example .env

.env.example documents itself: every value in it is optional, and an empty .env runs the whole stack on safe local-only defaults (a dev SECRET_KEY, PG_PASSWORD=futureagi, and so on). You don’t need to edit anything to bring the stack up.

Two things worth setting before you go further:

  • Drop your provider keys in so the gateway can route model requests:
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
  • If you want signup confirmations and password-reset emails to actually deliver, add Mailgun credentials:
MAILGUN_API_KEY=key-...
MAILGUN_SENDER_DOMAIN=mg.your-domain.com

If you skip Mailgun, you can still set a password via the Django shell in Step 4.

You should see a .env file sitting next to .env.example in future-agi/.

See Environment Variables for the full list of knobs.

Start the stack

docker compose up -d
docker compose ps --format "{{.Names}} {{.Status}}"

-d runs detached. The --format flag prints one line per service so you can scan health without horizontal-scrolling the default table.

docker compose up -d alone starts the light stack:

  • Frontend and backend
  • A Temporal worker and Temporal itself
  • The LLM gateway, serving, and the code executor
  • Postgres, ClickHouse, Redis, RabbitMQ, and MinIO
  • The trace collector

It does not start the PeerDB CDC stack, the extra queue workers, or the Temporal UI. Those sit behind Compose profiles and need COMPOSE_PROFILES=full (or workers, or observability) set before you run up.

The stack is ready when the backend logs Application startup complete:

docker compose logs -f backend

If ClickHouse keeps restarting in docker compose ps instead of settling, Docker Desktop’s default memory limit (2 to 4 GB) is too low. Raise it to 8+ GB in Docker Desktop’s settings and run docker compose up -d again.

Tip

First boot pulls the published images from scratch. Later docker compose up calls reuse the cached images and start in under 30 seconds.

Open the dashboard and create your first user

Two URLs are now live on your machine:

ServiceURLNotes
Frontendhttp://localhost:3000Sign up here
Backend APIhttp://localhost:8000Health check at /health/

A third, the PeerDB UI at http://localhost:3001, is only reachable if you started with COMPOSE_PROFILES=full.

Open the frontend, sign up with any email (the local stack doesn’t enforce verification by default), and grab an API key from Settings → API Keys.

You should see a new project and an API key pair in the dashboard. Update the FI_API_KEY and FI_SECRET_KEY values you exported in Install with these real keys.

Tip

No Mailgun? Set the password directly via the Django shell instead of waiting for a reset email:

docker compose exec backend python manage.py shell -c "
from django.contrib.auth import get_user_model
u = get_user_model().objects.get(email='you@example.com')
u.set_password('your-new-password')
u.save()
"

Send your first trace to the local stack

Point the instrumentation SDK at your local backend with FI_BASE_URL. Everything else is identical to the cloud setup.

import os
from fi_instrumentation import register, FITracer
from fi_instrumentation.fi_types import ProjectType
from traceai_openai import OpenAIInstrumentor
from openai import OpenAI

client = OpenAI()

# FI_BASE_URL (exported in Install) points the exporter at the local
# backend instead of the Future AGI cloud endpoint.
trace_provider = register(
    project_type=ProjectType.OBSERVE,
    project_name="local-stack-smoke-test",
)
OpenAIInstrumentor().instrument(tracer_provider=trace_provider)
tracer = FITracer(trace_provider.get_tracer("local-stack-smoke-test"))

@tracer.agent(name="smoke_test_agent")
def smoke_test_agent(question: str) -> str:
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": question}],
    )
    return response.choices[0].message.content

print(smoke_test_agent("What's our policy on refunds after 30 days?"))
trace_provider.force_flush()

Open Observe → Traces → local-stack-smoke-test in the dashboard. You should see one parent span (smoke_test_agent) with the OpenAI call nested underneath. If the trace shows up, backend ingestion, ClickHouse, frontend rendering, and gateway routing are all wired correctly.

Troubleshooting

SymptomCauseFix
PeerDB UI at :3001 won’t loadYou ran docker compose up -d without a profileSet COMPOSE_PROFILES=full in .env (or export it) before docker compose up -d, then re-run
ClickHouse container keeps restartingDocker Desktop’s default memory limit (2 to 4 GB) is too lowRaise Docker’s memory allocation to 8+ GB in Docker Desktop settings, then docker compose up -d again
Traces never appear after force_flush()FI_BASE_URL wasn’t set before register() ran, so the SDK sent spans to the cloud endpoint instead of localhostSet export FI_BASE_URL="http://localhost:8000" before running the script
Every trace 503s from the collectorfi-collector fell back to its baked-in Postgres default instead of the compose postgres serviceConfirm PG_USER / PG_PASSWORD / PG_DB in .env match what postgres was started with, then docker compose restart fi-collector
Backend never logs Application startup completeFirst-run image pull is still in progress, or it failed silentlyRun docker compose logs -f backend and watch for a pull error; a clean first pull takes 10 to 15 minutes
code-executor fails to start on a managed container platformThe service requires privileged: true, which ECS Fargate and Cloud Run blockRun the stack on a host with a real Docker daemon (a VM, bare metal, or WSL 2), not a Fargate/Cloud Run task
Signup works but no confirmation email arrivesNo Mailgun credentials in .envAdd MAILGUN_API_KEY and MAILGUN_SENDER_DOMAIN, or set the password directly via the Django shell (Step 4)

Continue to Self-Hosting with Docker Compose for every deployment mode, profile, and override.

Was this page helpful?

Questions & Discussion