First-run setup

What the first-run setup screen checks on a new self-hosted install, how Production and Test flight report each result, and how to fix a failed check.

In this page

The first time you open a new self-hosted install in a browser, it sends you to /setup. The screen asks how you plan to run the instance, which is the launch mode, then runs pre-flight checks against every service the app depends on. It names the setup it runs in (Standalone, Distributed or Helm) and shows that setup’s fix for anything that is down. Continue then takes you to sign-in, or to sign-up when the instance has no account yet.

📝
TL;DR

Production, the default, requires all 13 checks and holds you on the screen while one fails. Test flight requires seven and lets the rest through as Caution or Optional. The launch mode changes how results are reported, never which services run, and nothing stores it. A service your install does not run reads Optional in both modes.

%%{init: {"flowchart": {"curve": "linear"}}}%%
flowchart TD
  accTitle: The first-run setup flow
  accDescr: A first visit opens the setup screen. You pick a launch mode, the pre-flight checks run, and Continue leads to sign-in when an account exists or to sign-up when none does.
  A["First visit to the UI"] --> B["Pick a launch mode"]
  B --> C["Pre-flight checks"]
  C -->|"Continue"| D{"Account exists?"}
  D -->|"Yes"| E["Sign in"]
  D -->|"No"| F["Sign up"]

When the screen appears

Opening the UI (http://localhost:3000 on a default install) sends a browser to /setup until you click Continue on it. The browser remembers that in its local storage, so each new browser or private window sees the screen once. Open /setup again at any time to re-run the checks.

The screen and its checks exist only on an open-source install. On an install with an Enterprise Edition license, the UI skips the screen and the checks endpoint answers 404.

The two launch modes

You pick one on the first screen, and Production is selected by default. The choice lives only in that browser tab: it is not written to .env and nothing reads it later.

ModeForRequired checksA down service that is not required
ProductionAn instance that will carry real trafficAll 13None: every down service reads Failed and blocks Continue
Test flightTrying Future AGI out locallyCore application database, Tracing data warehouse, LLM request gateway, Async task engine, Trace ingestion, Django backend, React frontendReads Caution. SSL/TLS certificate reads Optional

Results never block Continue in Test flight, even a Failed row, so read them before you go on. When Production is blocked, the screen offers Continue with Test flight; in Test flight, Switch to Production runs the stricter mode.

What each status means

StatusMeaning
ReadyThe service answered. A Ready row can carry a note, such as Standalone’s built-in code sandbox running Python but not JavaScript
CautionThe service is down, and this mode does not require it
FailedThe service is down, and this mode requires it. In Production it blocks Continue
OptionalYour install does not run the service, a local install needs no certificate, or Test flight skips the certificate check
Checking…The result is still being revealed: after the first response, the rows flip one by one

Whether a service is up never depends on the mode. Only the label on a down service changes.

The pre-flight checks

The screen shows 13 rows. Eleven probe a service, all at the same time. Django backend and React frontend are not probed: the page loading at all shows they are up, so they always read Ready.

CheckWhat breaks when it is downProductionTest flight
Core application databaseNothing loadsFailedFailed
Tracing data warehouseTraces, spans and dashboards will not loadFailedFailed
Cache and session storeSessions, caching and rate limits will not workFailedCaution
Websocket connectionLive updates will not reach the browserFailedCaution
Object storage serviceDataset uploads, exports and media will failFailedCaution
LLM request gatewayEvery LLM call fails: evaluations, playground and agentsFailedFailed
Async task engineEvaluations, optimizations and scheduled jobs will not runFailedFailed
Trace ingestionSpans sent by the SDK will not arriveFailedFailed
Django backendNot probed, always Readyn/an/a
React frontendNot probed, always Readyn/an/a
Agent fixer (evals)Embedding-based evals, ground truth and Vector DB columns will not runFailedCaution
Code execution sandboxCustom code evaluations will not runFailedCaution
SSL/TLS certificateBrowser and SDK traffic travels unencryptedFailedOptional

Websocket connection checks the channel layer that carries live updates to the browser, which is Redis in both Compose setups, and the WEBSOCKET_ENDPOINT that workers send those updates to.

Checks that can read Optional

  • Agent fixer (evals) reads Optional when model serving is not deployed: Standalone without the ml profile, or Helm with serving.enabled=false, the default. The row then reads “Embedding-based evals, ground truth and Vector DB columns are off; everything else works”. Distributed always runs serving, so there the row reads Failed or Caution while it is down, never Optional.
  • Code execution sandbox reads Optional on Helm with codeExecutor.enabled=false, the default. Custom code evals are refused until you set codeExecutor.enabled=true (the nodes must allow privileged pods), or run them in the worker pods with codeExecutor.localFallback=true when everyone who can write evals is trusted. In Standalone without the sandbox profile the row reads Ready, with a note that JavaScript evals need the sandbox profile.
  • SSL/TLS certificate reads Optional on a local install, in both modes. An install is local when every configured URL (FRONTEND_URL, and VITE_HOST_API or else BASE_URL; on Helm, urls.app and urls.api) names localhost, a private or CGNAT (Tailscale) address, a single-label host name, or a .local, .internal or .lan name, and the browser reached the API on such a host. While every configured URL is local, as on a default Helm install, a browser that came in on a public host name or address fails the check.

Fix a failed check

The Details panel under the checks gives one fix per Failed or Caution row, for the setup the screen runs in. Each row’s name links to the matching “Pre-flight says …” section of INSTALLATION.md on GitHub. Most fixes start or restart a container:

CheckStandaloneDistributed
Core application databasedocker compose up -d postgresdocker compose up -d postgres
Tracing data warehousedocker compose up -d clickhousedocker compose up -d clickhouse
Cache and session storedocker compose restart appdocker compose up -d redis
Websocket connectiondocker compose restart appdocker compose up -d redis, then check WEBSOCKET_ENDPOINT
Object storage servicedocker compose restart appdocker compose up -d minio
LLM request gatewaydocker compose restart appdocker compose up -d agentcc-gateway
Async task enginedocker compose restart appdocker compose up -d temporal
Trace ingestiondocker compose restart appdocker compose up -d fi-collector
Agent fixer (evals)docker compose up -d serving (only with the ml profile; without it the row reads Optional)docker compose up -d serving
Code execution sandboxdocker compose restart app, or with the sandbox profile docker compose up -d code-executordocker compose up -d code-executor

In Standalone, Redis, object storage, the gateway, Temporal, the trace collector and the built-in code sandbox all run inside the app container, so restarting app brings them back. docker compose logs app shows why one stopped. The code executor needs a host that allows privileged: true. If the screen keeps waiting for the instance, start the API with docker compose up -d app (Distributed: backend) and read its logs.

On Helm the screen gives kubectl commands with your namespace and Deployment names filled in: kubectl -n <namespace> get pods for a bundled datastore, the values key to check for an external one (such as postgres.external), and the component’s logs for the rest.

For SSL/TLS certificate, serve the UI and the API over https through a reverse proxy with a valid certificate. The check reads FRONTEND_URL and VITE_HOST_API (on Helm, urls.app and urls.api), but change them together with the other public URLs, such as APP_URL, which builds invite and password-reset links. Security & TLS has proxy examples and the full set of URLs. If a check keeps failing, Troubleshooting covers the common causes.

When Continue is blocked

Three things hold you on the checks screen:

  • The instance is not reachable yet. The screen reads “Waiting for your instance to power up. Normal on a first run.” while containers start.
  • The results are still being revealed one by one.
  • You are in Production and at least one check reads Failed.

The screen keeps polling while services come up. It stops once every row is Ready or Optional, or once the results have not changed for a minute. Re-run pre-flight probes everything again without reloading the page. The server caches each result for three seconds, so clicking faster than that returns the same answer.

To read the same results from a script, call the endpoint the screen uses. It needs no authentication; mode=live is Production and mode=experiment is Test flight:

curl -s "http://localhost:8000/api/setup-checks/?mode=live"

After Continue

Continue sends you to sign-in when the instance already has an account, such as the one ./bin/install asked you for, and to sign-up when it has none. If you are already signed in, it takes you into the app. Users & sign-in covers creating accounts.

Once nothing blocks you, the screen lists what to do next:

  1. Open Keys in the sidebar and copy your API key and secret key.
  2. Send a first trace from the same machine, with FI_BASE_URL set to the collector URL the screen shows (http://localhost:4318 by default):
pip install fi-instrumentation-otel
export FI_API_KEY="YOUR_API_KEY" FI_SECRET_KEY="YOUR_SECRET_KEY" FI_BASE_URL="http://localhost:4318"
from fi_instrumentation import register
from fi_instrumentation.fi_types import ProjectType

tracer_provider = register(project_name="my-first-project", project_type=ProjectType.OBSERVE)
with tracer_provider.get_tracer("quickstart").start_as_current_span("hello-future-agi") as span:
    span.set_attribute("input.value", "Hello, Future AGI")
tracer_provider.force_flush()

Open Tracing in the sidebar: my-first-project holds the span. On Docker Compose the collector listens on the install’s host only, so an SDK on another machine needs a reverse proxy in front of 127.0.0.1:4318 and FI_COLLECTOR_PUBLIC_URL set to the proxy’s URL (see Environment variables). The tracing guide goes further.

Launch mode is not a profile

Profiles decide which containers run and are set in .env before the stack starts. The launch mode is a choice in the browser that changes nothing about your deployment. A service a profile leaves out reads Optional rather than Failed, so a local Standalone install without profiles passes pre-flight in either mode.

Dive deeper

Was this page helpful?

Questions & Discussion