+ ))}
)}
diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts
index 8f8646a3..6bd49aac 100644
--- a/src/lib/navigation.ts
+++ b/src/lib/navigation.ts
@@ -60,13 +60,28 @@ export const tabNavigation: NavTab[] = [
title: 'Self-Hosting',
items: [
{ title: 'Overview', href: '/docs/self-hosting' },
- { title: 'System requirements', href: '/docs/self-hosting/requirements' },
- { title: 'Environment variables', href: '/docs/self-hosting/environment' },
- { title: 'Configuration', href: '/docs/self-hosting/configuration' },
- { title: 'Docker Compose', href: '/docs/self-hosting/docker-compose' },
- { title: 'Production', href: '/docs/self-hosting/production' },
- { title: 'User management', href: '/docs/self-hosting/user-management' },
- { title: 'Troubleshooting and FAQs', href: '/docs/self-hosting/troubleshooting' },
+ { title: 'Requirements', href: '/docs/self-hosting/requirements' },
+ { title: 'Installation', href: '/docs/self-hosting/installation' },
+ {
+ title: 'Configuration',
+ items: [
+ { title: 'System configuration', href: '/docs/self-hosting/configuration/system' },
+ { title: 'Environment variables', href: '/docs/self-hosting/configuration/environment' },
+ ]
+ },
+ {
+ title: 'Production',
+ items: [
+ { title: 'Overview', href: '/docs/self-hosting/production' },
+ { title: 'Checklist', href: '/docs/self-hosting/production/checklist' },
+ { title: 'Security & TLS', href: '/docs/self-hosting/production/security-tls' },
+ { title: 'Backups & restore', href: '/docs/self-hosting/production/backups-restore' },
+ { title: 'Monitoring', href: '/docs/self-hosting/production/monitoring' },
+ { title: 'Upgrades & rollback', href: '/docs/self-hosting/production/upgrades-rollback' },
+ ]
+ },
+ { title: 'Troubleshooting & FAQs', href: '/docs/self-hosting/troubleshooting' },
+ { title: 'Support', href: '/docs/self-hosting/support' },
]
},
{
diff --git a/src/lib/redirects.ts b/src/lib/redirects.ts
index 93b7acbb..2625e00c 100644
--- a/src/lib/redirects.ts
+++ b/src/lib/redirects.ts
@@ -306,4 +306,5 @@ export const redirectMap: Record = {
'/sdk-reference/python-sdk-client': '/docs/sdk',
'/sdk-reference/testcase': '/docs/sdk/testcase',
'/sdk-reference/tracing': '/docs/sdk/tracing',
+ '/docs/self-hosting/environment': '/docs/self-hosting/configuration/environment',
};
diff --git a/src/pages/docs/cookbook/self-hosting/docker-compose-quickstart.mdx b/src/pages/docs/cookbook/self-hosting/docker-compose-quickstart.mdx
index 58c7fb85..5a368dc5 100644
--- a/src/pages/docs/cookbook/self-hosting/docker-compose-quickstart.mdx
+++ b/src/pages/docs/cookbook/self-hosting/docker-compose-quickstart.mdx
@@ -68,7 +68,7 @@ MAILGUN_DOMAIN=mg.your-domain.com
If you don't have Mailgun, skip this. You can still create a user and set a password via the Django shell in [Step 4](#step-4).
-See [Environment Variables](/docs/self-hosting/environment) for the full list of knobs.
+See [Environment Variables](/docs/self-hosting/configuration/environment) for the full list of knobs.
@@ -199,7 +199,7 @@ docker compose down -v
Full deployment modes (full stack, dev overlay, frontend-only)
-
+
Every secret, port, and runtime flag the stack reads
diff --git a/src/pages/docs/self-hosting.mdx b/src/pages/docs/self-hosting.mdx
index dd3c9fbf..28ddd24f 100644
--- a/src/pages/docs/self-hosting.mdx
+++ b/src/pages/docs/self-hosting.mdx
@@ -1,49 +1,28 @@
---
-title: "Self-Hosting Future AGI: Deploy on Your Own Infrastructure"
-description: "Deploy the full Future AGI platform on your own infrastructure using Docker Compose. Follow the step-by-step guide to get all services running locally."
+title: "Self-hosting Future AGI"
+description: "Run the entire Future AGI platform on your own infrastructure with Docker Compose. Your traces, datasets, evaluations, and model calls stay inside your network"
---
-## About
+Future AGI is fully open-source. Self-hosting runs the **entire stack on your own machines**, so all traces, datasets, evaluations, and model calls stay within your network. The backend is Django, the frontend is React + Vite, and the LLM gateway is Go, all deployed together with Docker Compose
-Future AGI is fully open-source. Self-hosting runs the entire stack on your machines — all traces, datasets, evaluations, and model calls stay within your network. Backend is Django, frontend is React + Vite, LLM gateway is Go.
+## When to self-host
-Not sure if you need this? The hosted version at [app.futureagi.com](https://app.futureagi.com) is easier to operate. Self-host when you need **data residency**, **air-gapped environments**, **cost control at scale**, or **deep customization**.
+The [**cloud hosted version**](https://app.futureagi.com) is the easiest way to run Future AGI, with nothing to operate. Self-host when you need:
-## Quick start
+- **Data residency**: keep all data inside your own network
+- **Air-gapped environments**: run with no outbound dependencies
+- **Cost control at scale**: own the infrastructure
+- **Deep customization**: modify the open-source stack to fit your needs
-```bash
-git clone https://github.com/future-agi/future-agi.git
-cd future-agi
-cp .env.example .env
-docker pull futureagi/future-agi:v1.8.19_base
-docker compose up
-```
-
-First boot builds from source (~10–15 min). After `Application startup complete`:
-
-| Service | URL |
-|---|---|
-| Frontend | http://localhost:3000 |
-| Backend API | http://localhost:8000 |
-| PeerDB UI | http://localhost:3001 — `peerdb` / `peerdb` |
-
-## Deployment options
-
-| Option | Status |
-|---|---|
-| Docker Compose | Available |
-| Helm / Kubernetes | Coming soon |
-| Air-gapped | Coming soon |
+## What you deploy
-## Architecture
-
-21 containers across four layers.
+Self-hosting brings up the full platform (around **21 containers, with no external dependencies**) across four layers:
```
Browser
└─ frontend (React/nginx)
- └─ backend (Django) ──── gateway (Go) ──── OpenAI · Anthropic · Gemini · Bedrock
- ├── postgres primary DB + WAL replication
+ └─ backend (Django) ──── gateway (Go) ──── OpenAI · Anthropic · Gemini · Bedrock
+ ├── postgres primary database
├── clickhouse analytics store
├── redis cache / pub-sub
├── minio object storage
@@ -52,51 +31,31 @@ Browser
postgres ──── PeerDB CDC ──── clickhouse (continuous replication)
```
-**Application** — `frontend` · `backend` · `worker` · `gateway` · `serving` · `code-executor`
-
-**Data** — `postgres` · `clickhouse` · `redis` · `minio`
+- **Application**: `frontend`, `backend`, `worker`, `gateway`, `serving`, `code-executor`
+- **Data**: `postgres`, `clickhouse`, `redis`, `minio`
+- **Workflow**: `temporal`
+- **CDC**: PeerDB (continuous Postgres → ClickHouse replication)
-**Workflow** — `temporal`
+Everything runs on your machines; nothing leaves your network. The full service-by-service breakdown lives in [Configure](/docs/self-hosting/configuration).
-**CDC (PeerDB)** — `peerdb-catalog` · `peerdb-temporal` · `peerdb-minio` · `peerdb-flow-api` · `peerdb-flow-worker` · `peerdb-flow-snapshot-worker` · `peerdb-server` · `peerdb-ui` · `peerdb-temporal-init` · `peerdb-init`
+## Deployment options
-| Layer | Service | Purpose |
-|---|---|---|
-| App | `frontend` | React SPA served by nginx |
-| App | `backend` | Django REST + gRPC + WebSocket API |
-| App | `worker` | Temporal worker — evals, agent loops, data jobs |
-| App | `gateway` | Go LLM proxy — routing, retries, rate limits, logging |
-| App | `serving` | Embeddings and small model inference |
-| App | `code-executor` | nsjail-sandboxed eval code runner (`privileged: true` required) |
-| Data | `postgres` | Primary DB — users, traces, datasets, evals, prompts |
-| Data | `clickhouse` | Analytics DB — replicated from Postgres via PeerDB |
-| Data | `redis` | Cache, rate limits, WebSocket pub/sub |
-| Data | `minio` | S3-compatible object storage (swap for S3 in prod) |
-| Workflow | `temporal` | Durable workflow engine — shares main Postgres |
-| CDC | PeerDB stack | Continuous Postgres → ClickHouse replication (10 services) |
+| Option | Status |
+|---|---|
+| Docker Compose | Available |
+| Helm / Kubernetes | Coming soon |
+| Air-gapped | Coming soon |
-## Next Steps
+## Where to go next
-
-
- Hardware tiers, platform compatibility, ports reference.
-
-
- Setup, deployment modes, day-to-day operations.
-
-
- Full `.env` reference — secrets, ports, flags, keys.
-
-
- LLM gateway providers, PeerDB mirrors, Temporal workers.
-
-
- Create accounts via email or Django shell.
+
+
+ System requirements, prerequisites, environment variables, and setup
-
- Hardening, backups, monitoring, upgrades.
+
+ Fixes for common errors and answers to frequent questions
-
- Solutions for every known error.
+
+ Get help from the Future AGI team and community
diff --git a/src/pages/docs/self-hosting/configuration/environment.mdx b/src/pages/docs/self-hosting/configuration/environment.mdx
new file mode 100644
index 00000000..e978151e
--- /dev/null
+++ b/src/pages/docs/self-hosting/configuration/environment.mdx
@@ -0,0 +1,130 @@
+---
+title: "Environment variables"
+description: "Complete .env reference for a self-hosted Future AGI instance"
+---
+
+## In this page
+
+Every setting the stack reads at boot comes from a single `.env` file in the repo root. This page is the complete reference, grouped by what each variable does. The stack boots fine with the shipped defaults. The only thing you *must* change before sharing the instance is the `CHANGEME` secrets.
+
+```bash
+cp .env.example .env
+```
+
+
+Doing a local trial? Skip to [Installation](/docs/self-hosting/installation). The defaults work as-is. Come back here when you're ready to set secrets, add LLM provider keys, or turn on email.
+
+
+## Required Secrets
+
+Replace every `CHANGEME` in this group before anyone else can reach the instance. Generate each value with the command shown.
+
+| Variable | Generate with | Used by |
+|---|---|---|
+| `SECRET_KEY` | `openssl rand -hex 32` | Django sessions, CSRF, password reset |
+| `PG_PASSWORD` | `openssl rand -base64 24` | PostgreSQL auth |
+| `MINIO_ROOT_PASSWORD` | `openssl rand -base64 24` | MinIO object storage auth |
+| `AGENTCC_INTERNAL_API_KEY` | `openssl rand -hex 32` | Backend and gateway shared secret |
+
+
+`PG_PASSWORD` is written to the Postgres volume on **first boot only**. If you change it after the volume exists, authentication fails. See the fix in [Troubleshooting](/docs/self-hosting/troubleshooting). Set it before your first `docker compose up`.
+
+
+## Database Credentials
+
+| Variable | Default | Notes |
+|---|---|---|
+| `PG_USER` | `futureagi` | PostgreSQL username |
+| `PG_PASSWORD` | `CHANGEME` | **Must change** |
+| `PG_DB` | `futureagi` | PostgreSQL database name |
+| `MINIO_ROOT_USER` | `futureagi` | MinIO username |
+| `MINIO_ROOT_PASSWORD` | `CHANGEME` | **Must change** |
+| `CH_USE_REPLICATED_ENGINES` | `false` | `true` only for multi-node ClickHouse |
+
+## Ports
+
+Every service port is configurable. The full table (defaults, what each binds to, and exposure scope) lives in [Requirements](/docs/self-hosting/requirements#network-ports), so you can plan firewall rules in one place.
+
+## Backend Runtime
+
+| Variable | Default | Description |
+|---|---|---|
+| `ENV_TYPE` | `development` | One of `development`, `staging`, or `prod`. Prod mode disables debug output and enables `check --deploy` |
+| `FAST_STARTUP` | `false` | Skip migrations on restart (dev only). Always `false` in production |
+| `GRANIAN_WORKERS` | `1` | ASGI worker processes. Set to your CPU count in production |
+| `GRANIAN_THREADS` | `2` | Threads per worker |
+| `ENABLE_GRPC` | `true` | Enable the gRPC endpoint |
+| `ENABLE_HTTP` | `true` | Enable the HTTP/REST endpoint |
+
+## Temporal Worker
+
+| Variable | Default | Description |
+|---|---|---|
+| `TEMPORAL_NAMESPACE` | `default` | Temporal namespace |
+| `TEMPORAL_ALL_QUEUES` | `true` | Single worker polls all queues. Set `false` and use the dev overlay for per-queue workers |
+| `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` | `50` | Max concurrent activity tasks |
+| `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` | `50` | Max concurrent workflow tasks |
+
+Tuning guidance lives in [System configuration](/docs/self-hosting/configuration/system#temporal-workers).
+
+## LLM Gateway
+
+| Variable | Default | Description |
+|---|---|---|
+| `AGENTCC_INTERNAL_API_KEY` | `CHANGEME` | **Must change.** The backend authenticates gateway calls with this shared secret |
+
+Setting a key here is only half the job. The gateway also needs a `config.yaml` listing the providers it may route to. See [System configuration](/docs/self-hosting/configuration/system#llm-gateway).
+
+## LLM Provider Keys
+
+Set a key for each provider you'll use and leave the rest blank. These are read by the gateway via `${VAR}` interpolation in `config.yaml`.
+
+| Variable | Provider |
+|---|---|
+| `OPENAI_API_KEY` | OpenAI |
+| `ANTHROPIC_API_KEY` | Anthropic |
+| `GOOGLE_API_KEY` | Google Gemini |
+| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_REGION` | AWS Bedrock + S3 |
+
+## Email (Mailgun)
+
+Email delivery powers self-service sign-up and password reset. Without it, you create users from the Django shell during [Installation](/docs/self-hosting/installation). Set these to turn on the email flow:
+
+| Variable | Description |
+|---|---|
+| `MAILGUN_API_KEY` | Mailgun private API key |
+| `MAILGUN_SENDER_DOMAIN` | Verified Mailgun sending domain |
+| `DEFAULT_FROM_EMAIL` | `From:` address for outbound email |
+| `SERVER_EMAIL` | `From:` address for Django admin error email |
+
+## Frontend Build-Time
+
+
+These are baked into the JavaScript bundle at Vite build time. Changing them requires a rebuild: `docker compose build frontend`.
+
+
+| Variable | Default | Description |
+|---|---|---|
+| `VITE_HOST_API` | `http://localhost:8000` | Backend URL as seen by the browser. In production, use your public backend URL |
+| `VITE_ENVIRONMENT` | `development` | Frontend analytics and feature flags |
+
+## Optional
+
+| Variable | Default | Description |
+|---|---|---|
+| `RECAPTCHA_ENABLED` | `false` | Enable reCAPTCHA on registration |
+| `RECAPTCHA_SECRET_KEY` | `(none)` | reCAPTCHA v2/v3 server-side key |
+| `VITE_GOOGLE_SITE_KEY` | `(none)` | reCAPTCHA client-side key (requires a frontend rebuild) |
+| `FUTURE_AGI_CLOUD_API_KEY` | `(none)` | Enterprise-tier Cloud features only. Leave blank for the open-source build |
+| `FUTURE_AGI_CLOUD_API_URL` | `https://api.futureagi.com` | Do not change |
+
+## Dive deeper
+
+
+
+ Point the LLM gateway at your providers and set up PeerDB mirrors
+
+
+ Harden the instance before exposing it to users
+
+
diff --git a/src/pages/docs/self-hosting/configuration/system.mdx b/src/pages/docs/self-hosting/configuration/system.mdx
new file mode 100644
index 00000000..b28489dc
--- /dev/null
+++ b/src/pages/docs/self-hosting/configuration/system.mdx
@@ -0,0 +1,143 @@
+---
+title: "System configuration"
+description: "Configure the LLM gateway, PeerDB replication, and Temporal workers for your self-hosted instance."
+---
+
+## In this page
+
+A few parts of the stack are configured outside `.env`: the LLM gateway needs a `config.yaml` listing its providers, PeerDB needs its replication mirrors running, and Temporal workers can be tuned for throughput. This page covers all three. Set your secrets and provider keys in [Environment Variables](/docs/self-hosting/configuration/environment) first, since the config here references them.
+
+## LLM Gateway
+
+The gateway is a Go proxy that routes every model call the platform makes. It reads a `config.yaml` that lists which providers it may use and which models each exposes.
+
+
+Model calls fail until this file exists. The gateway ships with `config.example.yaml` (OpenAI enabled) but **not** a live `config.yaml`. You create one in the steps below.
+
+
+
+
+```bash
+cp agentcc-gateway/config.example.yaml \
+ agentcc-gateway/config.yaml
+```
+
+
+
+Edit `config.yaml`: uncomment the providers you want and reference their keys with `${VAR}` interpolation. Set the matching keys (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, …) in `.env`. See the provider examples below.
+
+
+
+Point the gateway volume at your `config.yaml` in `docker-compose.yml`:
+
+```yaml
+volumes:
+ - ./agentcc-gateway/config.yaml:/app/config.yaml:ro
+```
+
+```bash
+docker compose up -d --force-recreate gateway
+```
+
+
+
+
+`config.yaml` is gitignored and holds live API keys. Treat it as a secret. Never commit it.
+
+
+### Provider Examples
+
+
+
+```yaml
+providers:
+ openai:
+ api_key: "${OPENAI_API_KEY}"
+ api_format: "openai"
+ models: [gpt-4o, gpt-4o-mini]
+
+ anthropic:
+ api_key: "${ANTHROPIC_API_KEY}"
+ api_format: "anthropic"
+ models: [claude-opus-4-5, claude-sonnet-4-5]
+
+ gemini:
+ api_key: "${GOOGLE_API_KEY}"
+ api_format: "gemini"
+ models: [gemini-2.0-flash, gemini-1.5-pro]
+```
+
+
+```yaml
+providers:
+ bedrock:
+ api_key: "${AWS_SECRET_ACCESS_KEY}"
+ api_format: "bedrock"
+ region: "${AWS_REGION}"
+ access_key: "${AWS_ACCESS_KEY_ID}"
+ models: [anthropic.claude-3-5-sonnet-20241022-v2:0]
+```
+
+
+```yaml
+providers:
+ vertex:
+ base_url: "https://us-central1-aiplatform.googleapis.com"
+ api_key: "${GOOGLE_ACCESS_TOKEN}"
+ api_format: "gemini"
+ headers:
+ x-gcp-project: "${GCP_PROJECT_ID}"
+ x-gcp-location: "us-central1"
+ models: [gemini-2.0-flash-001]
+```
+
+Vertex uses a Bearer token, not a static API key. Rotate `GOOGLE_ACCESS_TOKEN` with a sidecar that calls `gcloud auth print-access-token`.
+
+
+
+For routing rules, rate limits, caching, and the full config reference, see [Agent Command Center → Self-Hosted](/docs/command-center/deployment/self-hosted).
+
+## PeerDB Replication
+
+PeerDB continuously replicates Postgres tables into ClickHouse (change-data-capture) so trace and eval analytics stay fast. It runs on its own. The only thing you typically touch is a first-boot timing fix.
+
+
+**First-boot timing.** `peerdb-init` runs the moment the stack starts, sometimes before Django has finished its migrations. If mirrors show "not started" in the PeerDB UI, re-run init once the backend is up:
+
+```bash
+docker compose logs -f backend # wait for "Application startup complete"
+docker compose run --rm peerdb-init bash /setup.sh # re-run init
+```
+
+
+Verify at [http://localhost:3001](http://localhost:3001). Mirrors should move to `running` within seconds. Re-run the same init command after any upgrade that changes replicated tables.
+
+## Temporal Workers
+
+Temporal runs the platform's background jobs and evaluation pipelines. How those jobs are distributed across workers depends on one flag.
+
+**All-queue (default).** One worker polls every task queue. Controlled by `TEMPORAL_ALL_QUEUES=true` in `.env`. This is the right setup for most self-hosted deployments.
+
+**Per-queue (dev overlay).** Six dedicated workers, one per queue, brought up by the [dev overlay](/docs/self-hosting/installation#other-ways-to-run-it):
+
+| Service | Queue | Typical concurrency |
+|---|---|---|
+| `worker-default` | `default` | 100 |
+| `worker-tasks-s` | `tasks_s` | 200 |
+| `worker-tasks-l` | `tasks_l` | 50 |
+| `worker-tasks-xl` | `tasks_xl` | 10 |
+| `worker-trace-ingestion` | `trace_ingestion` | 100 |
+| `worker-agent-compass` | `agent_compass` | 50 |
+
+Tune throughput with `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` and `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` in `.env`. The Temporal UI is available in dev mode at [http://localhost:8085](http://localhost:8085).
+
+## Dive Deeper
+
+
+
+ Hardening, backups, and monitoring before going live.
+
+
+ Fixes for gateway, PeerDB, and Temporal errors.
+
+
diff --git a/src/pages/docs/self-hosting/docker-compose.mdx b/src/pages/docs/self-hosting/docker-compose.mdx
index 1ce057d7..c039421e 100644
--- a/src/pages/docs/self-hosting/docker-compose.mdx
+++ b/src/pages/docs/self-hosting/docker-compose.mdx
@@ -23,7 +23,7 @@ First boot builds from source (~10–15 min). When the backend logs `Application
- **Backend API** — [http://localhost:8000](http://localhost:8000)
- **PeerDB UI** — [http://localhost:3001](http://localhost:3001) · `peerdb` / `peerdb`
-Replace `CHANGEME` secrets in `.env` before sharing the instance with others. See [Environment Variables](/docs/self-hosting/environment).
+Replace `CHANGEME` secrets in `.env` before sharing the instance with others. See [Environment Variables](/docs/self-hosting/configuration/environment).
---
@@ -112,7 +112,7 @@ docker compose run --rm peerdb-init bash /setup.sh
## Next Steps
-
+
Configure secrets, ports, and runtime flags in `.env`.
diff --git a/src/pages/docs/self-hosting/environment.mdx b/src/pages/docs/self-hosting/environment.mdx
deleted file mode 100644
index 0967ef80..00000000
--- a/src/pages/docs/self-hosting/environment.mdx
+++ /dev/null
@@ -1,118 +0,0 @@
----
-title: "Self-Hosting Environment Variables"
-description: "Full .env reference for self-hosted Future AGI — secrets, database credentials, runtime flags, LLM provider keys, email, and frontend build-time configuration."
----
-
-## About
-
-Reference for every environment variable the stack reads from `.env`. Grouped by purpose: secrets, database credentials, runtime flags, LLM provider keys, email, and frontend build-time config.
-
-```bash
-cp .env.example .env
-```
-
-The stack boots fine with defaults. Replace `CHANGEME` secrets before sharing with others.
-
-## Required secrets
-
-| Variable | Generate with | Used by |
-|---|---|---|
-| `SECRET_KEY` | `openssl rand -hex 32` | Django sessions, CSRF, password reset |
-| `PG_PASSWORD` | `openssl rand -base64 24` | PostgreSQL auth |
-| `MINIO_ROOT_PASSWORD` | `openssl rand -base64 24` | MinIO object storage auth |
-| `AGENTCC_INTERNAL_API_KEY` | `openssl rand -hex 32` | Backend ↔ gateway shared secret |
-
-## Database credentials
-
-| Variable | Default | Notes |
-|---|---|---|
-| `PG_USER` | `futureagi` | PostgreSQL username |
-| `PG_PASSWORD` | `CHANGEME` | **Must change** |
-| `PG_DB` | `futureagi` | PostgreSQL database name |
-| `MINIO_ROOT_USER` | `futureagi` | MinIO username |
-| `MINIO_ROOT_PASSWORD` | `CHANGEME` | **Must change** |
-| `CH_USE_REPLICATED_ENGINES` | `false` | `true` only for multi-node ClickHouse |
-
-## Ports
-
-All configurable. See [Requirements → Ports reference](/docs/self-hosting/requirements#ports-reference) for the full table with defaults and exposure scope.
-
-## Backend runtime
-
-| Variable | Default | Description |
-|---|---|---|
-| `ENV_TYPE` | `development` | `development` · `staging` · `prod` — prod mode disables debug output, enables `check --deploy` |
-| `FAST_STARTUP` | `false` | Skip migrations on restart (dev only). Always `false` in production. |
-| `GRANIAN_WORKERS` | `1` | ASGI worker processes. Set to CPU count in production. |
-| `GRANIAN_THREADS` | `2` | Threads per worker. |
-| `ENABLE_GRPC` | `true` | Enable gRPC endpoint. |
-| `ENABLE_HTTP` | `true` | Enable HTTP/REST endpoint. |
-
-## Temporal worker
-
-| Variable | Default | Description |
-|---|---|---|
-| `TEMPORAL_NAMESPACE` | `default` | Temporal namespace. |
-| `TEMPORAL_ALL_QUEUES` | `true` | Single worker polls all queues. Set `false` + use dev overlay for per-queue workers. |
-| `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` | `50` | Max concurrent activity tasks. |
-| `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` | `50` | Max concurrent workflow tasks. |
-
-## LLM gateway
-
-| Variable | Default | Description |
-|---|---|---|
-| `AGENTCC_INTERNAL_API_KEY` | `CHANGEME` | **Must change.** Backend authenticates gateway calls with this. |
-
-## LLM provider keys
-
-Leave blank for providers you're not using.
-
-| Variable | Provider |
-|---|---|
-| `OPENAI_API_KEY` | OpenAI |
-| `ANTHROPIC_API_KEY` | Anthropic |
-| `GOOGLE_API_KEY` | Google Gemini |
-| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_REGION` | AWS Bedrock + S3 |
-
-## Email (Mailgun)
-
-Required for email-based sign-up and password reset. Without these, create users via the Django shell — see [User Management](/docs/self-hosting/user-management).
-
-| Variable | Description |
-|---|---|
-| `MAILGUN_API_KEY` | Mailgun private API key |
-| `MAILGUN_SENDER_DOMAIN` | Verified Mailgun sending domain |
-| `DEFAULT_FROM_EMAIL` | `From:` address for outbound emails |
-| `SERVER_EMAIL` | Django admin error emails |
-
-## Frontend build-time
-
-
-These are baked into the JS bundle at Vite build time. Changing them requires rebuilding: `docker compose build frontend`
-
-
-| Variable | Default | Description |
-|---|---|---|
-| `VITE_HOST_API` | `http://localhost:8000` | Backend URL as seen by the browser. In production: your public backend URL. |
-| `VITE_ENVIRONMENT` | `development` | Frontend analytics and feature flags. |
-
-## Optional
-
-| Variable | Default | Description |
-|---|---|---|
-| `RECAPTCHA_ENABLED` | `false` | Enable reCAPTCHA on registration. |
-| `RECAPTCHA_SECRET_KEY` | — | reCAPTCHA v2/v3 server-side key. |
-| `VITE_GOOGLE_SITE_KEY` | — | reCAPTCHA client-side key (requires frontend rebuild). |
-| `FUTURE_AGI_CLOUD_API_KEY` | — | EE-tier Cloud features only. Leave blank for OSS. |
-| `FUTURE_AGI_CLOUD_API_URL` | `https://api.futureagi.com` | Do not change. |
-
-## Next Steps
-
-
-
- Set up LLM gateway providers and PeerDB mirrors.
-
-
- Hardening checklist for exposing the stack to users.
-
-
diff --git a/src/pages/docs/self-hosting/installation.mdx b/src/pages/docs/self-hosting/installation.mdx
new file mode 100644
index 00000000..9bc66c6d
--- /dev/null
+++ b/src/pages/docs/self-hosting/installation.mdx
@@ -0,0 +1,140 @@
+---
+title: "Installation"
+description: "Install a self-hosted Future AGI instance with Docker Compose."
+---
+
+Docker Compose is the supported way to run a self-hosted Future AGI instance.
+
+## In this page
+
+Confirm your host meets the [requirements](/docs/self-hosting/requirements) first, then `./bin/install` does the rest:
+
+- Bootstraps your `.env`
+- Brings up the stack
+- Waits for the backend health check
+- Prompts you to create the first user
+
+First boot pulls the app images from Docker Hub and builds the small fi-collector image from source, so give it a few minutes the first time.
+
+
+Run `git clone https://github.com/future-agi/future-agi.git && cd future-agi && ./bin/install`, then open [http://localhost:3000](http://localhost:3000).
+
+
+## Install
+
+
+
+```bash
+git clone https://github.com/future-agi/future-agi.git
+cd future-agi
+./bin/install # Windows: bin\install.ps1
+```
+
+The stack boots fine against an empty `.env`, so you can take the defaults for a local trial.
+
+By default the installer brings up the standard stack (around 12 containers). Add `--full` to include the PeerDB CDC stack (around 22 containers) that populates the analytics views.
+
+
+
+The installer prompts you at the end. If you passed `--skip-user-creation`, create the account from the CLI instead:
+
+```bash
+docker compose exec backend python manage.py create_user
+```
+
+You will be asked for an email, full name, and password. To script it, pass them inline:
+
+```bash
+docker compose exec backend python manage.py create_user \
+ --email you@example.com \
+ --name "Your Name" \
+ --password yourpassword
+```
+
+
+
+Log in at [http://localhost:3000](http://localhost:3000) with the user you just created. The backend API is at [http://localhost:8000](http://localhost:8000).
+
+
+
+### Installer flags
+
+| Flag | What it does |
+|---|---|
+| `--full` | Add the PeerDB CDC stack (around 22 containers) so the analytics views populate |
+| `--skip-user-creation` | Skip the first-user prompt; create the account later with `create_user` |
+| `--no-up` | Bootstrap `.env` only, without starting the stack |
+| `--wipe-volumes` | Remove stale project volumes before starting (destroys existing data) |
+| `--new-instance` | Start a fresh instance when existing volumes are detected |
+
+
+**Apple Silicon and arm64 hosts.** Prebuilt images are `linux/amd64`. On M-series Macs they run under Rosetta 2 (auto-enabled on Docker Desktop 4.16+), which is fine for evaluation with a 20 to 50 percent performance cost. For native arm64, build locally with `docker compose build` instead of pulling. On Linux arm64 such as Graviton, install `qemu-user-static`.
+
+
+## Install without the script
+
+The installer is a convenience wrapper, not a requirement. To run the same steps by hand:
+
+```bash
+cp .env.example .env # optional; an empty .env works for local
+docker compose up -d
+```
+
+Then create the first user with the same `create_user` command shown above.
+
+## Verify the stack
+
+Check that every service is healthy before you log in. Under-provisioned RAM is the most common reason the backend never finishes booting, so confirm the [requirements](/docs/self-hosting/requirements) if it stalls.
+
+```bash
+docker compose ps # every service should read "running" or "healthy"
+docker compose logs -f backend # watch for errors while it boots
+curl http://localhost:8000/health/
+```
+
+The instance is ready when `/health/` returns OK. That's the same check `./bin/install` polls while it waits for the backend.
+
+## Everyday operations
+
+A short reference for the commands you will use most:
+
+```bash
+# Tail logs
+docker compose logs -f backend worker
+
+# Shell into a container
+docker compose exec backend bash
+docker compose exec postgres psql -U futureagi -d futureagi
+
+# Stop the stack (data persists in named volumes)
+./bin/uninstall # or: docker compose down
+
+# Wipe all data and start clean
+./bin/uninstall --wipe-data # or: docker compose down -v
+
+# Remove everything: containers, volumes, .env, and built images
+./bin/uninstall --purge
+```
+
+## Other ways to run it
+
+| Mode | Command | Use it for |
+|---|---|---|
+| Standard (default) | `docker compose up -d` | Local evaluation, team installs, and VM self-hosting |
+| Development | `docker compose -f docker-compose.yml -f docker-compose.dev.yml up` | Contributing to Future AGI: hot reload, per-queue workers, host-accessible database ports, and the Temporal UI |
+| Frontend only | `docker compose -f docker-compose.frontend.yml up -d` | Pointing a local UI at a backend that runs elsewhere |
+
+
+For a frontend-only deploy, set `VITE_HOST_API` to the backend URL the browser can reach. It is applied when the container starts, so changing it needs only a restart of the frontend container, not a rebuild.
+
+
+## Dive deeper
+
+
+
+ Set provider keys, secrets, and runtime flags in `.env`
+
+
+ Tune the gateway, PeerDB, and Temporal workers
+
+
diff --git a/src/pages/docs/self-hosting/production.mdx b/src/pages/docs/self-hosting/production.mdx
index c5fbb682..fa37559a 100644
--- a/src/pages/docs/self-hosting/production.mdx
+++ b/src/pages/docs/self-hosting/production.mdx
@@ -1,137 +1,35 @@
---
-title: "Production Hardening & Operations"
-description: "Production readiness checklist — replace secrets, configure TLS, set up managed data stores, run Postgres/ClickHouse/MinIO backups, and follow the upgrade runbook."
+title: "Production"
+description: "What to harden before a self-hosted Future AGI instance goes live"
---
-## About
+Everything past a local trial happens here. The default Docker Compose stack boots with placeholder secrets, no TLS, and compose-managed data stores. That's fine on a laptop. Before real traffic reaches the instance, work through the flow below in order, then keep each page as a runbook.
-Run through this before exposing the stack to real users. Covers secrets, TLS, swapping in managed data stores, backup commands for Postgres/ClickHouse/MinIO, Prometheus monitoring, and the upgrade and rollback runbook.
+## In this page
-## Hardening checklist
+Production readiness for a self-hosted instance breaks into five steps. Do them in order the first time.
-**Secrets** — replace all `CHANGEME` values before going live:
+**Before you go live**
-```bash
-openssl rand -hex 32 # SECRET_KEY, AGENTCC_INTERNAL_API_KEY
-openssl rand -base64 24 # PG_PASSWORD, MINIO_ROOT_PASSWORD
-```
-
-**Runtime flags** in `.env`:
-- `ENV_TYPE=prod`
-- `FAST_STARTUP=false`
-- `GRANIAN_WORKERS=`
-
-**TLS** — the frontend and backend don't terminate TLS. Put Caddy, nginx, or Traefik in front:
-
-```
-# Caddyfile (simplest — auto-issues Let's Encrypt certs)
-app.yourcompany.com { reverse_proxy localhost:3000 }
-api.yourcompany.com { reverse_proxy localhost:8000 }
-```
-
-After setting up TLS, set `VITE_HOST_API=https://api.yourcompany.com` in `.env` and rebuild:
-
-```bash
-docker compose build frontend && docker compose up -d frontend
-```
-
-**Managed data stores** — for production, replace compose-managed services:
-
-| Replace | With | Change |
-|---|---|---|
-| `postgres` | RDS / Aurora / Cloud SQL | Set `PG_*` vars to managed endpoint |
-| `clickhouse` | ClickHouse Cloud | Set `CH_HOST`, `CH_PORT`, etc. |
-| `redis` | ElastiCache / Upstash | Set `REDIS_URL` |
-| `minio` | AWS S3 | Set `S3_ENDPOINT_URL=https://s3.amazonaws.com` + AWS creds |
-
-
-`code-executor` requires `privileged: true`. Run on EC2 / GCE instances — not Fargate or Cloud Run.
-
-
-**Secrets manager** — use AWS Secrets Manager, HashiCorp Vault, or GCP Secret Manager instead of a plain `.env` file.
-
----
-
-## Backups
-
-### PostgreSQL
-
-```bash
-# Backup
-docker compose exec postgres \
- pg_dump -U futureagi -d futureagi --format=custom \
- > backup-$(date +%F).dump
-
-# Restore
-docker compose exec -T postgres \
- pg_restore -U futureagi -d futureagi --clean --if-exists \
- < backup-2026-04-22.dump
-```
-
-Volumes: `future-agi_postgres-data` · `future-agi_clickhouse-data` · `future-agi_redis-data` · `future-agi_minio-data` · `future-agi_peerdb-catalog-data` · `future-agi_peerdb-minio-data`
-
-### ClickHouse
-
-```sql
-BACKUP TABLE default.traces TO S3('s3://your-bucket/ch-backup/', 'KEY', 'SECRET');
-```
-
-ClickHouse data can also be rebuilt from scratch by re-running PeerDB init since it replicates from Postgres.
-
-### MinIO
-
-```bash
-mc alias set local http://localhost:9005 futureagi
-mc alias set s3 https://s3.amazonaws.com
-mc mirror local/ s3/your-bucket/
-```
-
----
-
-## Monitoring
-
-Backend exposes Prometheus metrics at `http://localhost:8000/metrics`. Add a scraper:
-
-```yaml
-# prometheus.yml
-scrape_configs:
- - job_name: futureagi
- static_configs:
- - targets: ['localhost:8000']
- metrics_path: /metrics
-```
-
-Key signals: backend error rate, Temporal workflow success/failure, Postgres WAL lag (PeerDB health), ClickHouse query latency, PeerDB mirror status at [localhost:3001](http://localhost:3001).
-
----
-
-## Upgrades
-
-```bash
-git pull
-docker compose build
-docker compose up -d
-```
-
-Migrations run automatically. If a migration fails: `docker compose exec backend python manage.py migrate`
-
-If release notes mention PeerDB changes: `docker compose run --rm peerdb-init bash /setup.sh`
-
-**Rollback:**
-
-```bash
-git log --oneline -5
-git checkout
-docker compose build && docker compose up -d
-```
+
+
+ The go-live pass: secrets, prod runtime flags, and managed data stores
+
+
+ Terminate TLS in front of the stack and lock down secrets
+
+
-## Next Steps
+**Operating it**
-
-
- Symptoms, causes, and fixes for common errors.
+
+
+ Back up and restore Postgres, ClickHouse, and MinIO
+
+
+ Watch the health signals the stack actually exposes
-
- Tune the LLM gateway, PeerDB mirrors, and Temporal workers.
+
+ Pull a release, run migrations, and roll back safely
diff --git a/src/pages/docs/self-hosting/production/backups-restore.mdx b/src/pages/docs/self-hosting/production/backups-restore.mdx
new file mode 100644
index 00000000..5b0b257f
--- /dev/null
+++ b/src/pages/docs/self-hosting/production/backups-restore.mdx
@@ -0,0 +1,70 @@
+---
+title: "Backups & restore"
+description: "Back up and restore the data stores behind a self-hosted instance"
+---
+
+A self-hosted instance keeps state in a few stores: Postgres for application data, ClickHouse for the observability records (spans and traces), and MinIO for object storage. Redis is a cache (sessions, locks, rate limits, pub/sub), so it rebuilds on its own and doesn't need a backup. RabbitMQ holds the task queue: losing it drops in-flight background jobs, so drain it before planned downtime rather than backing it up.
+
+## Postgres
+
+Postgres holds the application data, so back it up on a schedule. Use the custom format, and pass `-T` so `docker compose exec` doesn't allocate a TTY and mangle the binary dump:
+
+```bash
+# Backup
+docker compose exec -T postgres \
+ pg_dump -U futureagi -d futureagi --format=custom \
+ > backup-$(date +%F).dump
+
+# Restore
+docker compose exec -T postgres \
+ pg_restore -U futureagi -d futureagi --clean --if-exists \
+ < backup-2026-04-22.dump
+```
+
+The named volumes that hold state. The compose project name is `futureagi`, so every volume is prefixed `futureagi_`:
+
+| Volume | Holds |
+|---|---|
+| `futureagi_postgres-data` | Postgres application data |
+| `futureagi_clickhouse-data` | ClickHouse spans and traces |
+| `futureagi_minio-data` | MinIO objects |
+| `futureagi_rabbitmq-data` | RabbitMQ task queue |
+| `futureagi_redis-data` | Redis cache (rebuildable) |
+| `futureagi_peerdb-catalog-data` | PeerDB replication catalog |
+| `futureagi_peerdb-minio-data` | PeerDB staging objects |
+| `futureagi_fi-collector-data` | fi-collector buffer |
+
+## ClickHouse
+
+ClickHouse is not just a replica anymore. Since the CH25 cutover (`CH25_DROP_LEGACY_CDC_CHAIN` defaults to `true`), the fi-collector writes `spans` straight to ClickHouse and Django dual-writes `traces`. PeerDB only rebuilds the tables it mirrors from Postgres, so if you lose ClickHouse the observability data does **not** come back from a PeerDB re-init. Back it up on its own:
+
+```sql
+BACKUP DATABASE default TO S3('s3://your-bucket/ch-backup/', 'KEY', 'SECRET');
+```
+
+
+Don't rely on PeerDB init to rebuild ClickHouse. It restores the mirrored Postgres tables, not the `spans` the collector writes directly. ClickHouse needs a real backup on its own schedule.
+
+
+## MinIO
+
+Mirror the MinIO bucket to S3 with the MinIO client:
+
+```bash
+mc alias set local http://localhost:9005 futureagi
+mc alias set s3 https://s3.amazonaws.com
+mc mirror local/ s3/your-bucket/
+```
+
+If you've already moved to [managed data stores](/docs/self-hosting/production/checklist), your provider's own backup tooling replaces these commands.
+
+## Dive deeper
+
+
+
+ Watch store health and replication lag
+
+
+ Roll back releases without losing data
+
+
diff --git a/src/pages/docs/self-hosting/production/checklist.mdx b/src/pages/docs/self-hosting/production/checklist.mdx
new file mode 100644
index 00000000..281fd201
--- /dev/null
+++ b/src/pages/docs/self-hosting/production/checklist.mdx
@@ -0,0 +1,69 @@
+---
+title: "Checklist"
+description: "The go-live pass before a self-hosted instance takes real traffic"
+---
+
+Run through this once before the stack is reachable by anyone else. Three things separate a laptop trial from a real deployment:
+
+- Replace the dev-only secret defaults
+- Bring the stack up with the production overlay, so it refuses to boot until those secrets are set
+- Move the compose-managed data stores to managed services
+
+## Replace the dev-only secrets
+
+The stack boots with dev-only placeholders baked into `docker-compose.yml`, values like `local-dev-only-not-for-production-replace-me`, and `futureagi` for the database passwords. It runs fine with them, which is the point on a laptop and the danger in production.
+
+What forces real secrets is the production overlay, `deploy/docker-compose.production.yml`. It re-binds each one with `${VAR:?}`, so the stack won't start until you've set them. Bring the stack up with that overlay and set, at minimum:
+
+- `SECRET_KEY`
+- `AGENTCC_INTERNAL_API_KEY`
+- `AGENTCC_ADMIN_TOKEN`
+- `PG_PASSWORD`
+- `MINIO_ROOT_PASSWORD`
+- `RABBITMQ_USER` and `RABBITMQ_PASSWORD`
+- `FRONTEND_URL` and `VITE_HOST_API`
+
+```bash
+openssl rand -hex 32 # SECRET_KEY, AGENTCC_INTERNAL_API_KEY, AGENTCC_ADMIN_TOKEN
+openssl rand -base64 24 # PG_PASSWORD, MINIO_ROOT_PASSWORD, RABBITMQ_PASSWORD
+```
+
+
+`PG_PASSWORD` is baked into the Postgres volume on the **first** boot, so set it before your first `docker compose up`. `MINIO_ROOT_PASSWORD` is read from the environment on every boot, so that one you can change and restart. The full field list is in [Environment variables](/docs/self-hosting/configuration/environment).
+
+
+## Switch the backend to production mode
+
+Set these runtime flags before going live:
+
+| Variable | Go-live value | Why |
+|---|---|---|
+| `ENV_TYPE` | `prod` | Disables debug output and runs Django `check --deploy` |
+| `FAST_STARTUP` | `false` | Always applies migrations on restart |
+| `GRANIAN_WORKERS` | your CPU count | One worker per core, up from the default `1` |
+
+## Move to managed data stores
+
+Compose-managed Postgres, ClickHouse, Redis, and MinIO are fine for a trial. For production, point the stack at managed services. The catch: the backend reads these hosts from **hardcoded values in the `backend` env block of `docker-compose.yml`** (`PG_HOST: postgres`, `CH_HOST: clickhouse`, `REDIS_URL: redis://redis:6379/0`, `S3_ENDPOINT_URL: http://minio:9000`), not from `.env`. Setting them in `.env` does nothing. You edit the compose file.
+
+| Replace | With | Edit in `docker-compose.yml` |
+|---|---|---|
+| `postgres` | RDS, Aurora, or Cloud SQL | `PG_HOST` / `PG_PORT` to the managed endpoint |
+| `clickhouse` | ClickHouse Cloud | `CH_HOST` / `CH_PORT` and the credentials |
+| `redis` | ElastiCache or Upstash | `REDIS_URL` |
+| `minio` | AWS S3 | `STORAGE_BACKEND: s3` and the S3 credentials |
+
+
+`code-executor` runs with `privileged: true`, so it can't run on ECS Fargate or Cloud Run. Put it on an EC2 or GCE instance. The platform matrix is in [Requirements](/docs/self-hosting/requirements).
+
+
+## Dive deeper
+
+
+
+ Put TLS in front of the stack and move secrets into a manager
+
+
+ Set up backups before the instance holds real data
+
+
diff --git a/src/pages/docs/self-hosting/production/monitoring.mdx b/src/pages/docs/self-hosting/production/monitoring.mdx
new file mode 100644
index 00000000..6774fd9c
--- /dev/null
+++ b/src/pages/docs/self-hosting/production/monitoring.mdx
@@ -0,0 +1,44 @@
+---
+title: "Monitoring"
+description: "Watch a self-hosted instance with the health signals it actually exposes"
+---
+
+The stack has no Prometheus `/metrics` endpoint yet (the fi-collector lists a metrics exporter as a TODO), so monitoring today is built from what the containers already expose: their Docker health checks, the fi-collector's admin health endpoint, and the PeerDB console. This page covers those and the signals worth watching.
+
+## Container health
+
+The data stores (Postgres, ClickHouse, Redis, RabbitMQ, MinIO, Temporal) ship Docker health checks; the application services just show `running`. Either way, `docker compose ps` is the fastest read on what's up:
+
+```bash
+docker compose ps # STATUS shows healthy / unhealthy per service
+docker stats # live CPU and memory per container
+```
+
+Watch memory on `clickhouse` and the Temporal `worker` first. They're the resource drivers, and an OOM there is the most common cause of a stall.
+
+## fi-collector health
+
+The fi-collector exposes an admin endpoint on `127.0.0.1:9464` (`FI_COLLECTOR_ADMIN_PORT`), which serves a health check. Hit it to confirm the collector is up:
+
+```bash
+curl -s http://localhost:9464/healthz
+```
+
+## PeerDB replication
+
+The Postgres-to-ClickHouse pipeline has its own console at [localhost:3001](http://localhost:3001). Mirror status there tells you whether trace analytics are keeping up with Postgres. A mirror in anything other than `running` means the dashboard is reading stale.
+
+
+A Prometheus metrics exporter is on the fi-collector roadmap. When it lands, scrape it here. Until then, the checks above are what the stack actually exposes.
+
+
+## Dive deeper
+
+
+
+ Keep the stack current without downtime
+
+
+ Symptoms, causes, and fixes for common errors
+
+
diff --git a/src/pages/docs/self-hosting/production/security-tls.mdx b/src/pages/docs/self-hosting/production/security-tls.mdx
new file mode 100644
index 00000000..51239b2a
--- /dev/null
+++ b/src/pages/docs/self-hosting/production/security-tls.mdx
@@ -0,0 +1,59 @@
+---
+title: "Security & TLS"
+description: "Terminate TLS in front of a self-hosted instance and lock down its secrets"
+---
+
+Neither the frontend nor the backend terminates TLS. In production you put a reverse proxy in front of the stack to handle certificates, then point the frontend at the HTTPS endpoint. This page covers both, plus where production secrets should live.
+
+## Terminate TLS with a reverse proxy
+
+Run Caddy, nginx, or Traefik in front of the stack. Caddy is the shortest path because it issues and renews Let's Encrypt certificates on its own:
+
+```
+# Caddyfile
+app.yourcompany.com { reverse_proxy localhost:3000 }
+api.yourcompany.com { reverse_proxy localhost:8000 }
+```
+
+
+
+ Point the proxy at the frontend on `localhost:3000` and the backend on `localhost:8000`. The full port list is in [Requirements](/docs/self-hosting/requirements#network-ports).
+
+
+ Set `VITE_HOST_API=https://api.yourcompany.com` in `.env`. The frontend container reads it on start and writes it into `config.js`, so no rebuild is needed.
+
+
+ ```bash
+ docker compose up -d frontend
+ ```
+
+
+
+
+`VITE_HOST_API` is applied when the frontend container starts, not at build time. If the browser still calls the old host after you change it, the container wasn't recreated: rerun `docker compose up -d frontend`.
+
+
+## Keep secrets out of the compose file
+
+For anything past a single trial host, store secrets in a dedicated manager instead of a plain `.env`:
+
+- AWS Secrets Manager
+- HashiCorp Vault
+- GCP Secret Manager
+
+Rotate the dev-only default secrets from the [Checklist](/docs/self-hosting/production/checklist) first, then move them into the manager and inject them at deploy time.
+
+## Isolate the code executor
+
+`code-executor` runs with `privileged: true` so it can sandbox evaluation code. Keep it on a host you control, an EC2 or GCE instance, never a managed-container platform that can't grant that flag.
+
+## Dive deeper
+
+
+
+ Protect the data behind the proxy
+
+
+ Tune the gateway, PeerDB, and Temporal workers
+
+
diff --git a/src/pages/docs/self-hosting/production/upgrades-rollback.mdx b/src/pages/docs/self-hosting/production/upgrades-rollback.mdx
new file mode 100644
index 00000000..4c2e382b
--- /dev/null
+++ b/src/pages/docs/self-hosting/production/upgrades-rollback.mdx
@@ -0,0 +1,59 @@
+---
+title: "Upgrades & rollback"
+description: "Pull a new release, run migrations, and roll back when one goes wrong"
+---
+
+Upgrades are a git pull and a rebuild, and migrations run automatically on boot. This page covers the routine upgrade, the two cases that need a manual step, and how to roll back.
+
+## Upgrade to a new release
+
+
+
+ ```bash
+ git pull
+ docker compose build
+ docker compose up -d
+ ```
+
+
+ Database migrations run automatically on backend startup. If one fails, run it by hand:
+ ```bash
+ docker compose exec backend python manage.py migrate
+ ```
+
+
+ When a release changes which Postgres tables are mirrored, re-run init. The container's entrypoint is already `bash /setup.sh`, so no arguments are needed:
+ ```bash
+ docker compose run --rm peerdb-init
+ ```
+
+
+
+
+PeerDB init only rebuilds the tables it mirrors from Postgres. It does **not** restore the `spans` the fi-collector writes straight to ClickHouse, so it is not a recovery path for lost ClickHouse data. For that, restore from a [ClickHouse backup](/docs/self-hosting/production/backups-restore).
+
+
+## Roll back a bad release
+
+Roll back to the previous commit and rebuild:
+
+```bash
+git log --oneline -5
+git checkout
+docker compose build && docker compose up -d
+```
+
+
+Checking out older code does not undo a migration that already ran. If a release applied a migration you need to reverse, roll it back before you switch code, or restore Postgres from a backup.
+
+
+## Dive deeper
+
+
+
+ Symptoms, causes, and fixes for common errors
+
+
+ Where to get help when you're stuck
+
+
diff --git a/src/pages/docs/self-hosting/requirements.mdx b/src/pages/docs/self-hosting/requirements.mdx
index 4e0ce3be..2589a712 100644
--- a/src/pages/docs/self-hosting/requirements.mdx
+++ b/src/pages/docs/self-hosting/requirements.mdx
@@ -1,24 +1,36 @@
---
-title: "Self-Hosting Requirements"
-description: "Hardware sizing tiers, supported platforms, OS compatibility, and network port requirements before deploying Future AGI with Docker Compose."
+title: "Requirements"
+description: "System requirements and support for self-hosting Future AGI."
---
-## About
+## In this page
-Hardware tiers, supported platforms, and the network ports each service uses. Read this first to size your environment before running [Docker Compose](/docs/self-hosting/docker-compose).
+Check three things before you install:
+
+- A host that meets the sizing for your usage
+- The required software: Docker and Git
+- A supported platform
+
+Get these right and the [Installation](/docs/self-hosting/installation) run works on the first try.
+
+
+For a local trial: **4 CPU cores, 8 GB RAM, 20 GB disk**, Docker Engine 24+, Docker Compose v2.20+, and Git.
+
## Hardware tiers
+Pick the row that matches how you'll use the instance. The stack runs on the Evaluation tier, but ClickHouse and the Temporal worker are the resource drivers. Under-provisioning RAM is the most common cause of a failed first boot.
+
| Tier | Use case | CPU | RAM | Disk |
|---|---|---|---|---|
| **Evaluation** | Local trial, single user | 4 cores | 8 GB | 20 GB |
-| **Team** | 1–20 users, regular eval runs | 8 cores | 16 GB | 50 GB |
+| **Team** | 1-20 users, regular eval runs | 8 cores | 16 GB | 50 GB |
| **Production** | 20+ users, high throughput | 16+ cores | 32+ GB | 200 GB+ SSD |
-Resource drivers: ClickHouse and Temporal worker each hold ~1 GB RAM at steady state. First image build is ~6 GB disk. ClickHouse grows with trace volume; Postgres stays small.
+ClickHouse and the Temporal worker each hold ~1 GB RAM at steady state. ClickHouse grows with trace volume over time; Postgres stays small. Pulling the images takes a few GB of disk on the first run.
-Docker Desktop (Mac/Windows): Settings → Resources → set RAM ≥ 8 GB, disk ≥ 64 GB. The defaults (2–4 GB RAM) will OOM-kill ClickHouse or the backend.
+On Docker Desktop (Mac/Windows), raise the limits in **Settings → Resources**: RAM ≥ 8 GB, disk ≥ 64 GB. The defaults (2-4 GB RAM) will OOM-kill ClickHouse or the backend before the stack finishes booting.
## Software
@@ -27,70 +39,80 @@ Docker Desktop (Mac/Windows): Settings → Resources → set RAM ≥ 8 GB, disk
|---|---|---|
| Docker Engine | 24.0+ | `docker --version` |
| Docker Compose | v2.20+ | `docker compose version` |
+| Git | 2.0+ | `git --version` |
+Install the tools with Homebrew, then start Colima:
```bash
-brew install docker docker-compose colima
+brew install docker docker-compose colima git
colima start --cpu 4 --memory 8 --disk 64
```
-Or install [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/install/mac-install/) and allocate ≥ 8 GB RAM in Settings → Resources.
+Install the tools with apt, then enable the Docker daemon:
```bash
-sudo apt-get install -y docker.io docker-compose-v2
+sudo apt-get install -y docker.io docker-compose-v2 git
sudo systemctl enable --now docker
sudo usermod -aG docker $USER # log out and back in
```
-Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/) with WSL 2 backend. Allocate ≥ 8 GB RAM in Settings → Resources.
+Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/) with the WSL 2 backend, then set the memory limit in WSL, not Docker's UI (the **Settings → Resources** sliders apply only to the Hyper-V backend):
+```powershell
+# add to %UserProfile%\.wslconfig
+[wsl2]
+memory=8GB
+# then apply:
+wsl --shutdown
+```
## Platform compatibility
-The `code-executor` service requires `privileged: true`. Platforms that block it will crash the service; the rest of the stack still runs.
+Future AGI runs on any host that allows **privileged containers**. The `code-executor` service needs `privileged: true` to sandbox the user code it runs for evaluations, so platforms that block privileged mode lose that one service: the rest of the stack still runs, but code-based eval features are unavailable.
| Platform | Supported | Notes |
|---|---|---|
| Linux bare metal / EC2 / GCE / Azure VM | Yes | Full support |
-| GKE / EKS with privileged enabled | Yes | Requires PodSecurityPolicy exception |
+| GKE / EKS with privileged enabled | Yes | Requires a PodSecurityPolicy exception |
| ECS Fargate | No | `privileged: true` not supported |
| Google Cloud Run | No | Same |
| Render / Railway / Fly.io | No | Managed platforms block privileged mode |
-## Ports reference
+Helm/Kubernetes support is on the roadmap. Docker Compose is the supported path today.
+
+## Network ports
-All ports are configurable via `.env`.
+Make sure these host ports are free before you install, or remap any that collide. Every published port reads from `.env` with a built-in default (for example `${FRONTEND_PORT:-3000}`), so you can change one without touching the Compose file.
-| Service | Default | Exposed to | `.env` key |
+| Service | Default | Bind | `.env` key |
|---|---|---|---|
| Frontend | `3000` | `0.0.0.0` | `FRONTEND_PORT` |
| Backend API | `8000` | `0.0.0.0` | `BACKEND_PORT` |
-| Gateway | `8090` | Internal only | `GATEWAY_PORT` |
-| Model serving | `8080` | Internal only | `SERVING_PORT` |
-| Code executor | `8060` | Internal only | `CODE_EXECUTOR_PORT` |
-| Postgres | `5432` | `127.0.0.1` (dev: public) | `PG_PORT` |
-| ClickHouse HTTP | `8123` | `127.0.0.1` (dev: public) | `CH_HTTP_PORT` |
-| ClickHouse TCP | `9000` | `127.0.0.1` (dev: public) | `CH_PORT` |
-| Redis | `6379` | `127.0.0.1` (dev: public) | `REDIS_PORT` |
+| Gateway | `8090` | `0.0.0.0` | `AGENTCC_GATEWAY_PORT` |
+| Model serving | `8080` | `0.0.0.0` | `SERVING_PORT` |
+| Code executor | `8060` | `0.0.0.0` | `CODE_EXECUTOR_PORT` |
+| Postgres | `5432` | `127.0.0.1` | `PG_PORT` |
+| ClickHouse HTTP | `8123` | `127.0.0.1` | `CH_HTTP_PORT` |
+| ClickHouse TCP | `9000` | `127.0.0.1` | `CH_PORT` |
+| Redis | `6379` | `127.0.0.1` | `REDIS_PORT` |
| MinIO API | `9005` | `127.0.0.1` | `MINIO_API_PORT` |
| MinIO console | `9006` | `127.0.0.1` | `MINIO_CONSOLE_PORT` |
-| Temporal | `7233` | `127.0.0.1` (dev: public) | `TEMPORAL_PORT` |
-| Temporal UI | `8085` | Dev mode only | `TEMPORAL_UI_PORT` |
+| Temporal | `7233` | `127.0.0.1` | `TEMPORAL_PORT` |
| PeerDB server | `9900` | `127.0.0.1` | `PEERDB_PORT` |
| PeerDB UI | `3001` | `0.0.0.0` | `PEERDB_UI_PORT` |
-In production, only the frontend and backend ports should be internet-facing, and only behind a TLS-terminating reverse proxy.
+The data stores (Postgres, ClickHouse, Redis, MinIO, Temporal) bind to `127.0.0.1`; the application services bind to `0.0.0.0`. PeerDB server and UI only run when you enable the CDC stack with `COMPOSE_PROFILES=full`, so those two ports are only in use in that mode.
-## Next Steps
+## Dive deeper
-
- Clone, configure, and run the full stack.
+
+ Clone the repo and bring the stack up with `./bin/install`
-
- Set secrets and tune runtime flags before first boot.
+
+ Set provider keys, secrets, and runtime flags in `.env`
diff --git a/src/pages/docs/self-hosting/support.mdx b/src/pages/docs/self-hosting/support.mdx
new file mode 100644
index 00000000..9ba30624
--- /dev/null
+++ b/src/pages/docs/self-hosting/support.mdx
@@ -0,0 +1,32 @@
+---
+title: "Support"
+description: "Where to get help running a self-hosted Future AGI instance"
+---
+
+Running the open-source stack and hit something these pages don't cover? Here's where to reach the team and the community, and what to include so you get a useful answer fast.
+
+## Where to get help
+
+
+
+ Ask the community and the team in the Future AGI Discord
+
+
+ Report a bug or request a feature on the open-source repo
+
+
+
+## Before you post
+
+A self-hosting question is easier to answer with the basics attached:
+
+- What you ran and what happened, with the exact error
+- Output of `docker compose ps` so the team can see which service is down
+- Logs from the failing service: `docker compose logs --tail=100`
+- Your platform (Linux host, EC2, GCE) and whether you're on managed data stores
+
+Most self-hosting questions are already answered in [Troubleshooting & FAQs](/docs/self-hosting/troubleshooting). Check there first.
+
+## Commercial support
+
+For managed hosting, an SLA, or help with a production rollout, reach out at [sales@futureagi.com](mailto:sales@futureagi.com).