diff --git a/src/components/Breadcrumb.astro b/src/components/Breadcrumb.astro deleted file mode 100644 index 8b90bb7d..00000000 --- a/src/components/Breadcrumb.astro +++ /dev/null @@ -1,55 +0,0 @@ ---- -import SectionSwitcher from './SectionSwitcher.astro'; - -const currentPath = Astro.url.pathname; -const pathParts = currentPath.split('/').filter(Boolean); - -function toTitleCase(str: string) { - return str - .split('-') - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(' '); -} - -// Skip 'docs' from breadcrumb display since we show it via the section switcher -const breadcrumbParts = pathParts.filter(part => part !== 'docs'); -const breadcrumbs = breadcrumbParts.map((part, index) => { - // Build href from the original path parts - const originalIndex = pathParts.indexOf(part); - return { - label: toTitleCase(part), - href: '/' + pathParts.slice(0, originalIndex + 1).join('/'), - isLast: index === breadcrumbParts.length - 1, - }; -}); - -// Only show crumbs after the first one (which is shown in the section switcher) -const trailCrumbs = breadcrumbs.slice(1); ---- - - diff --git a/src/components/SectionSwitcher.astro b/src/components/SectionSwitcher.astro deleted file mode 100644 index 80bba85a..00000000 --- a/src/components/SectionSwitcher.astro +++ /dev/null @@ -1,210 +0,0 @@ ---- -/** - * Section Switcher Dropdown - * PostHog-style dropdown for switching between documentation sections. - * Shows the current section with an icon and lets users jump to any other section. - */ -import { tabNavigation, type NavTab } from '../lib/navigation'; - -const currentPath = Astro.url.pathname; - -// All navigable sections from the Docs tab -const docsTab = tabNavigation.find(t => t.tab === 'Docs'); -const sections = docsTab?.groups || []; - -// Find the current section based on URL -function getCurrentSection() { - // Check specific tabs first - for (const tab of tabNavigation) { - if (tab.href !== '/docs' && currentPath.startsWith(tab.href)) { - return { title: tab.tab, icon: tab.icon, href: tab.href }; - } - } - - // Check within docs groups - for (const group of sections) { - for (const item of group.items) { - if (item.href && (currentPath === item.href || currentPath.startsWith(item.href + '/'))) { - return { title: group.group, icon: group.icon || 'default', href: item.href }; - } - if (item.items) { - for (const child of item.items) { - if (child.href && (currentPath === child.href || currentPath.startsWith(child.href + '/'))) { - return { title: group.group, icon: group.icon || 'default', href: item.href || child.href }; - } - } - } - } - } - - return { title: 'Docs', icon: 'book', href: '/docs' }; -} - -const current = getCurrentSection(); - -// Build dropdown items from all sections + tabs -interface DropdownItem { - title: string; - icon: string; - href: string; - description?: string; -} - -const dropdownItems: DropdownItem[] = [ - ...sections.map(g => ({ - title: g.group, - icon: g.icon || 'default', - href: g.items[0]?.href || '/docs', - description: '', - })), - // Add other tabs - { title: 'Integrations', icon: 'plug', href: '/docs/integrations', description: '' }, - { title: 'Guides', icon: 'book', href: '/docs/cookbook', description: '' }, - { title: 'SDK Reference', icon: 'code', href: '/docs/sdk', description: '' }, - { title: 'API Reference', icon: 'webhook', href: '/docs/api', description: '' }, -]; - -const iconPaths: Record = { - 'rocket': 'M13 10V3L4 14h7v7l9-11h-7z', - 'table': 'M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z', - 'play': 'M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z M21 12a9 9 0 11-18 0 9 9 0 0118 0z', - 'chart': 'M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z', - 'zap': 'M13 10V3L4 14h7v7l9-11h-7z', - 'flask': 'M9 3v2m6-2v2M9 19h6m-3-11V3M5 21h14a2 2 0 002-2v-4a2 2 0 00-.586-1.414l-5-5A2 2 0 0014 8V3a1 1 0 00-1-1h-2a1 1 0 00-1 1v5a2 2 0 01-.586 1.414l-5 5A2 2 0 004 15v4a2 2 0 002 2z', - 'eye': 'M15 12a3 3 0 11-6 0 3 3 0 016 0z M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z', - 'compass': 'M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9', - 'gauge': 'M13 7h8m0 0v8m0-8l-8 8-4-4-6 6', - 'shield': 'M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z', - 'brain': 'M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z', - 'plug': 'M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1', - 'book': 'M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253', - 'code': 'M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4', - 'webhook': 'M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4', - 'default': 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z', -}; - -function getIconPath(icon: string): string { - return iconPaths[icon] || iconPaths.default; -} ---- - -
- - - - - -
- - diff --git a/src/components/Sidebar.astro b/src/components/Sidebar.astro index be417906..2df4e379 100644 --- a/src/components/Sidebar.astro +++ b/src/components/Sidebar.astro @@ -89,6 +89,62 @@ function getIconPath(icon?: string): string { return iconPaths[icon || 'default'] || iconPaths.default; } +// ── Lifecycle-ordered product dropdown (Docs tab only) ────────────────────── +// Reorders the Docs section dropdown from alphabetical to agent-development- +// lifecycle order, grouped under lightweight phase headers. This is dropdown-only +// and does NOT reorder the `groups` array in navigation.ts, so the page list below +// still follows nav order. "Resources" is intentionally omitted; "Falcon AI" sits +// last; a "Reference" group links out to the Integrations/Guides/SDK/API tabs. +// The dropdown only renders when a tab exposes multiple groups (today that's the +// Docs tab); any other multi-group tab falls back to a single unlabelled list. +interface DropdownItem { title: string; icon: string; href: string; } +interface DropdownSection { phase: string; items: DropdownItem[]; } + +const groupLookup = new Map( + allGroups.map(g => [g.group, { icon: g.icon || 'default', href: g.items[0]?.href || '/docs' }]) +); +// Single source for turning a group title into a dropdown item. +const toItem = (title: string): DropdownItem => { + const g = groupLookup.get(title); + return { title, icon: g?.icon || 'default', href: g?.href || '/docs' }; +}; + +const phasedOrder: { phase: string; titles: string[] }[] = [ + { phase: 'Start', titles: ['Get Started'] }, + { phase: 'Observe & diagnose', titles: ['Observability', 'Error Feed'] }, + { phase: 'Evaluate & measure', titles: ['Evaluation', 'Simulation', 'Dataset'] }, + { phase: 'Improve', titles: ['Optimization', 'Annotations'] }, + { phase: 'Build & connect', titles: ['Prompt', 'Prototype', 'Agent Playground', 'Knowledge Base', 'Agent Command Center'] }, + { phase: 'Protect', titles: ['Protect'] }, + { phase: 'Assistant', titles: ['Falcon AI'] }, +]; + +// Reference links live in their own top-level tabs; surface them at the bottom. +const referenceItems: DropdownItem[] = [ + { title: 'Integrations', icon: 'plug', href: '/docs/integrations' }, + { title: 'Guides', icon: 'book', href: '/docs/cookbook' }, + { title: 'SDK Reference', icon: 'code', href: '/docs/sdk' }, + { title: 'API Reference', icon: 'webhook', href: '/docs/api' }, +]; + +let dropdownSections: DropdownSection[]; +if (isDocsTab) { + dropdownSections = phasedOrder + .map(p => ({ phase: p.phase, items: p.titles.filter(t => groupLookup.has(t)).map(toItem) })) + .filter(s => s.items.length > 0); + + // Future-proofing: surface any Docs group not placed above (besides the hidden + // "Resources") under "More" so new products never silently vanish. + const placed = new Set([...phasedOrder.flatMap(p => p.titles), 'Resources']); + const leftovers = allGroups.map(g => g.group).filter(t => !placed.has(t)).map(toItem); + if (leftovers.length) dropdownSections.push({ phase: 'More', items: leftovers }); + + dropdownSections.push({ phase: 'Reference', items: referenceItems }); +} else { + // Other multi-group tabs: one unlabelled section (empty phase hides the header). + dropdownSections = [{ phase: '', items: allGroups.map(g => toItem(g.group)) }]; +} + // Infer HTTP method from API endpoint title for sidebar badges const isApiTab = activeTab?.tab === 'API'; @@ -139,26 +195,34 @@ function inferApiMethod(title: string): { method: string; css: string } | null { class="absolute left-3 right-3 mt-1 py-1 bg-[var(--color-bg-secondary)] border border-[var(--color-border-default)] rounded-xl shadow-xl shadow-black/20 z-50 hidden opacity-0 transition-all duration-150 max-h-[60vh] overflow-y-auto hide-scrollbar" data-section-dropdown > - {allGroups.map((group) => { - const isCurrent = group.group === activeGroup?.group; - const firstHref = group.items[0]?.href || '/docs'; - return ( - - - - - {group.group} - - ); - })} + {dropdownSections.map((section, sectionIndex) => ( +
0 && "mt-1.5 pt-1.5 border-t border-[var(--color-border-default)]/60"]}> + {section.phase && ( +
+ {section.phase} +
+ )} + {section.items.map((item) => { + const isCurrent = item.title === activeGroup?.group; + return ( + + + + + {item.title} + + ); + })} +
+ ))} )} 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).