Skip to main content

Self-Hosted Deployment

AxonFlow Community is source-available under BSL 1.1 and runs locally with Docker Compose. This path is ideal for engineers trying the platform, building governed AI applications, and standing up an internal sandbox before moving to higher tiers.

It is also the fastest way to learn the real runtime shape of AxonFlow:

  • Agent on 8080
  • Orchestrator on 8081
  • PostgreSQL and Redis for state and coordination
  • Prometheus and Grafana for observability

That matters because a lot of teams first encounter AxonFlow through SDK snippets or policy docs. The self-hosted stack is where those abstractions become a concrete system you can inspect end to end.

What You Get

The default compose stack starts:

  • Agent for gateway, proxy, policy, and MCP APIs
  • Orchestrator for routing, workflows, and multi-agent execution
  • PostgreSQL and Redis
  • Prometheus and Grafana

In community mode, client auth checks are skipped for the local developer flow, which makes onboarding fast. That is convenient when trying it, but you should still treat the stack as an internal environment and add proper secrets before any serious shared deployment.

The current local compose path uses DEPLOYMENT_MODE=community. That is the supported local-development model and the right default mental model for community self-hosting.

Prerequisites

  • Docker Engine or Docker Desktop
  • Docker Compose v2
  • 4 GB RAM minimum
  • 10 GB free disk
  • At least one provider key if you want AxonFlow to route LLM calls itself

Quick Start

git clone https://github.com/getaxonflow/axonflow.git
cd axonflow

cp .env.example .env
# Add one or more provider credentials if needed:
# OPENAI_API_KEY=...
# ANTHROPIC_API_KEY=...

docker compose up -d
docker compose ps

Services and Ports

ServicePortNotes
Agent8080Main API entry point
Orchestrator8081Workflow, routing, WCP
PostgreSQL5432Local database
Redis6379Cache / coordination
Prometheus9090Native metrics scrape target
Grafana3000admin / grafana_localdev456

Verify the Stack

curl -s http://localhost:8080/health | jq .
curl -s http://localhost:8081/health | jq .
curl -s http://localhost:8080/prometheus | head
curl -s http://localhost:9090/-/healthy
curl -s http://localhost:3000/api/health

The agent and orchestrator health endpoints return capability-aware JSON. They do not expose every dependency as a hand-curated component table, so rely on both service health and container health when debugging.

Configuration That Matters First

The local stack already wires the core database and Redis settings. The variables most teams care about first are:

VariablePurpose
OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEYEnable routed LLM providers
AZURE_OPENAI_*Enable Azure OpenAI
OLLAMA_ENDPOINT, OLLAMA_MODELEnable local model routing
DEFAULT_LLM_PROVIDERSet the preferred provider
LLM_ROUTING_STRATEGY, PROVIDER_WEIGHTSMulti-provider routing behavior
PII_ACTION, SQLI_ACTIONGlobal security/detection behavior
MCP_PII_ACTION, MCP_SQLI_ACTIONMCP-specific overrides
GATEWAY_PII_ACTION, GATEWAY_SQLI_ACTIONGateway-specific overrides
MCP_DYNAMIC_POLICIES_ENABLEDOpt into orchestrator-backed MCP dynamic policies
AXONFLOW_INTERNAL_SERVICE_SECRETRecommended shared secret for agent-orchestrator service auth
AXONFLOW_MAP_MAX_TIMEOUT_SECONDSMAP (Multi-Agent Planning) plan execution budget on the orchestrator. Default 300s, clamped to 60..1800s. Platform v7.2.0+.

If you are assessing whether Community is enough for your workload, these settings are where that answer usually starts to emerge. Once teams need broader limits, richer governance workflows, or enterprise identity/compliance features, Evaluation and Enterprise become easier to justify.

MAP plan timeout and your ingress

MAP plans chain multiple LLM calls end-to-end, so a five-step plan can run 60-120s before the orchestrator returns. The plan budget is a three-link chain and the smallest link wins; if any of them is shorter than the plan itself the connection is killed mid-stream and the SDK caller sees HTTP 504 Gateway Time-out. Starting on platform v7.2.0 the two knobs you control on a self-hosted deployment are:

LayerKnobDefaultRange
SDK clientmapTimeout (TS), map_timeout (Python), MapTimeout (Go), mapTimeout (Java)120soperator choice
OrchestratorAXONFLOW_MAP_MAX_TIMEOUT_SECONDS env300s60..1800s (clamped)

If you front the orchestrator with a reverse proxy, load balancer, or service mesh (NGINX, Traefik, Envoy, an ALB, etc.), its idle / read timeout is the third link in the chain. The rule is: SDK mapTimeout must be less than or equal to the orchestrator cap, which must be less than or equal to the proxy idle timeout. Raise them together, never the SDK alone. The orchestrator logs the effective cap at startup when the env is set non-default, and clamp decisions are logged when input falls outside the 60..1800s range.

The Go / Python / TypeScript / Java SDK quickstarts have matching timeout sections (Go, Python, TypeScript, Java).

MCP Connector Configuration

The default compose stack mounts config/axonflow.yaml, which registers several local PostgreSQL-backed demo connectors. You do not need to invent an ENABLED_CONNECTORS list to get started.

If you want a different config file layout, point the agent at it with AXONFLOW_CONFIG_FILE.

Local LLMs

To use Ollama or another local endpoint:

# Example
export OLLAMA_ENDPOINT=http://host.docker.internal:11434
export OLLAMA_MODEL=llama3.2:latest

docker compose up -d

For provider-specific setup, see LLM Overview.

Hardening Before Shared Use

If this stack is going to be used by more than one developer or promoted beyond a laptop sandbox:

  • set AXONFLOW_INTERNAL_SERVICE_SECRET
  • persist PostgreSQL and Grafana volumes intentionally
  • put the stack behind controlled network access
  • centralize logs and metrics
  • review Security Best Practices

What Leaves The Environment

This is one of the first questions serious reviewers ask, and it should be answered explicitly.

  • the AxonFlow runtime itself is self-hosted in your environment
  • audit records, policy context, workflow state, and connector enforcement stay in your deployment boundary
  • prompts only leave your environment when you send them to the LLM provider you configured
  • SDK telemetry can be disabled completely with AXONFLOW_TELEMETRY=off (canonical); DO_NOT_TRACK=1 is also honored today but is deprecated and scheduled for removal after 2026-05-05 — see Telemetry

If you are assessing AxonFlow in a high-scrutiny environment, use Assessing AxonFlow in Regulated Environments and Telemetry alongside this page.

Troubleshooting

Container fails to start

docker compose logs axonflow-agent
docker compose logs axonflow-orchestrator

Common causes:

  • Port conflict: another service on 8080 or 8081
  • Missing .env file: copy from .env.example
  • Docker memory: allocate at least 4GB to Docker Desktop

Health check returns unhealthy

curl -s http://localhost:8080/health | jq .

If "orchestrator": "unreachable":

  • Check orchestrator container is running: docker compose ps
  • Check network: docker compose exec axonflow-agent curl http://axonflow-orchestrator:8081/health
  • Review orchestrator logs for startup errors

If "database": "disconnected":

  • Check postgres container: docker compose ps postgres
  • Verify the database exists: docker compose exec postgres psql -U axonflow -d axonflow -c '\l'

Authentication errors (401)

For community mode without AXONFLOW_INTERNAL_SERVICE_SECRET:

  • Requests don't require auth by default
  • If you set AXONFLOW_INTERNAL_SERVICE_SECRET, all requests need Basic auth

Cleanup

docker compose down          # Stop containers
docker compose down -v # Stop + remove volumes (resets database)

First Checks That Usually Save Time

When something feels "mostly up, but not actually usable," start with:

  • missing provider key: stack is healthy, but routed LLM features are limited
  • broken Docker networking: agent and orchestrator are up, but cross-service calls fail
  • wrong local model endpoint: Ollama or another local provider is configured but unreachable from containers
  • no observability signal: health works, but /prometheus or Grafana is empty because no traffic has flowed yet

Next Steps