> ## Documentation Index
> Fetch the complete documentation index at: https://docs.foggyhq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Install Foggy (Self-Hosted)

> Install Foggy in your Kubernetes cluster in about 15 minutes. Bring your own Anthropic API key, keep your data in your perimeter.

## 1. Prerequisites

* **Kubernetes cluster** 1.27 or newer (EKS, GKE, AKS, or self-managed) with permission to create `ClusterRole` and `ClusterRoleBinding`
* **`kubectl`** and **`helm`** installed locally
* **PostgreSQL plan.** Decide before install:
  * **External managed Postgres** (AWS RDS, Cloud SQL, Azure Database, CloudNativePG). Recommended for any production use.
  * **Bundled Postgres.** Single in-cluster pod, no HA, manual backups. Evaluation only.
* **Anthropic API key.** [Create one at console.anthropic.com](https://console.anthropic.com).
* **Foggy license key** (signed JWT). Delivered privately by the Foggy team after you confirm trial terms. Covered by the [Terms of Service](https://foggyhq.com/terms).

## 2. Install

```bash theme={null}
helm repo add foggy https://foggylabs.github.io/helm-charts
helm repo update
```

```bash theme={null}
kubectl create namespace foggy
helm install foggy foggy/foggy --namespace foggy
```

Resources created:

* `ServiceAccount`, `ClusterRole`, `ClusterRoleBinding` (see [Kubernetes RBAC](./rbac))
* Three `Deployment`s: `foggy-agent` (investigation engine), `foggy-console-backend` (API + DB migrations), `foggy-console-frontend` (static React UI served by nginx)
* `Service`s for internal routing
* Bundled `PostgreSQL` (unless `postgresql.enabled: false` + `externalDatabase.url`)
* Two `Secret`s: `foggy-admin` (temporary admin password) and `foggy-secrets` (auto-generated `JWT_SECRET`, `AGENT_API_TOKEN`, `CONNECTOR_ENCRYPTION_KEY`)

To preview every resource before install, see the `helm template` tip in [Kubernetes RBAC](./rbac#default-clusterrole).

<Warning>
  For production (including paid trials), set `postgresql.enabled: false` and point `externalDatabase.url` at an external managed database before first install. Migrating bundled → external mid-trial is harder than starting external. See [§2.5 Production values](#2-5-production-values).
</Warning>

## 2.5 Production values

Save as `values-production.yaml`, edit the Postgres URL, install with `-f`.

```yaml values-production.yaml theme={null}
# Foggy production values.
#
# Customize this file and install with:
#   helm install foggy foggy/foggy -n foggy -f values-production.yaml
#
# LLM provider API keys (Anthropic / OpenAI / OpenRouter / Azure) are NOT
# configured here — they are entered through the UI after first login
# (Settings → LLM Providers) and stored Fernet-encrypted in the database.

# --- PostgreSQL -------------------------------------------------------------
# Production default: external managed Postgres (AWS RDS, Cloud SQL, Azure
# Database, CloudNativePG, Neon, etc). Bundled Postgres is evaluation-only.
postgresql:
  enabled: false

externalDatabase:
  # URL scheme MUST start with `postgresql+asyncpg://` — Foggy's backend
  # uses SQLAlchemy's async engine, which requires an async driver.
  # Plain `postgres://` or `postgresql://` fails at startup with
  # `InvalidRequestError: The asyncio extension requires an async driver`.
  #
  # Most managed Postgres services (AWS RDS, Cloud SQL, Azure Database,
  # Neon) enforce TLS by default — append `?sslmode=require` to match.
  url: "postgresql+asyncpg://USER:PASSWORD@HOST:5432/DBNAME?sslmode=require"

  # Alternative: reference an existing Kubernetes Secret with a `url` key
  # (e.g. generated by external-secrets-operator from your secret manager):
  #   existingSecret: foggy-database-url
  #   existingSecretKey: url

# --- Ingress ----------------------------------------------------------------
# Turn on after you've verified first install via kubectl port-forward.
# Typical production shape: Ingress + cert-manager-issued TLS.
ingress:
  enabled: false
  # className: nginx
  # host: foggy.your-company.com
  # tls:
  #   enabled: true
  #   secretName: foggy-tls

# --- Kubernetes RBAC --------------------------------------------------------
# Default: cluster-wide read-only on workloads, services, pod logs, events.
# Narrow to specific namespaces if your security team requires it.
rbac:
  enabled: true
  scope: cluster  # or `namespace` + `namespaces: [ns1, ns2]`

# --- Admin bootstrap --------------------------------------------------------
# Default: chart generates a random admin password into the `foggy-admin`
# Secret. Alternative: disable generation and supply the Secret yourself.
# admin:
#   generatePassword: false
#   existingSecret: my-pre-created-foggy-admin

# --- Observability (opt-in) -------------------------------------------------
# OpenTelemetry traces/metrics/logs via OTLP/gRPC. Disabled by default.
# Set `observability.otel.endpoint` to your collector; the chart wires
# OTEL_EXPORTER_OTLP_ENDPOINT into both the console-backend and agent pods.
# observability:
#   otel:
#     endpoint: "http://otel-collector.observability.svc.cluster.local:4317"
#
# Langfuse (LLM tracing) — opt-in on the agent via extraEnv:
# agent:
#   extraEnv:
#     - name: LANGFUSE_PUBLIC_KEY
#       value: "pk-lf-..."
#     - name: LANGFUSE_SECRET_KEY
#       value: "sk-lf-..."
#     - name: LANGFUSE_HOST
#       value: "https://cloud.langfuse.com"
#
# PostHog (product analytics) — opt-in on the console backend via extraEnv:
# consoleBackend:
#   extraEnv:
#     - name: POSTHOG_API_KEY
#       value: "phc_..."
```

Full value reference:

```bash theme={null}
helm show values foggy/foggy
```

## 3. Access the UI

Retrieve the temporary admin password:

```bash theme={null}
kubectl get secret foggy-admin -n foggy \
  -o jsonpath='{.data.password}' | base64 -d
```

Port-forward the Console service:

```bash theme={null}
kubectl port-forward -n foggy svc/foggy-console 8080:80
```

Open `http://localhost:8080`. For production TLS + Ingress, see [What's next](#6-whats-next).

## 4. Initial setup

### 4a. Change password and set admin email

Log in with `admin@foggy.local` and the temporary password from §3. Set:

* **Your real admin email.** Replaces `admin@foggy.local` for all subsequent logins.
* **A new password.** 8-64 characters, at least one uppercase, one lowercase, one digit, one special character.

### 4b. Activate your license

Paste your Foggy license JWT and click **Activate**. Verification happens locally in the backend (no network call, no phone-home). On success, Foggy renames your workspace to the `customer_name` claim in the JWT.

License details (customer name, plan, expiry) are visible in **Settings → License** for admin users. A warning banner appears in the app header 7 days before expiry.

### 4c. Configure your LLM provider

`/llm-provider-setup` is a **blocking step**: chat is disabled until a key is saved. Paste your Anthropic API key (starts with `sk-ant-api03-...`) and click **Save and continue**.

Key storage: Foggy Fernet-encrypts the key using `CONNECTOR_ENCRYPTION_KEY` (auto-generated by the Helm chart into the `foggy-secrets` Kubernetes Secret on first install) and persists the ciphertext in the PostgreSQL `llm_credentials` table. The plaintext key never leaves your cluster; the backend decrypts it in memory each time it dispatches an investigation.

Rotation: **Settings → LLM Providers** → paste a new key and save. No pod restart required. The display shows only the last 4 characters (`sk-ant-••••••••••••••••••XYZ1`) plus a **Test key** button that validates against Anthropic `/v1/models` without blocking save.

On save, Foggy redirects to your workspace dashboard at `/p/1`.

## 5. Connect a data source and run your first investigation

Kubernetes is already connected via the pod's in-cluster ServiceAccount. Ask questions immediately; Foggy investigates using read-only `kubectl`.

For richer investigations, click **Connectors** in the left sidebar. Supported integrations:

* **Observability**: Grafana, Grafana Cloud, Prometheus, OpenSearch, Datadog, Sentry
* **ChatOps**: Slack (investigations can also be triggered from Slack), Webhook (for custom alertmanager / PagerDuty integrations)
* **Tickets**: Linear, Jira
* **Code**: GitHub

Click **Connect**, paste credentials, save. Green means connected; red means validation failed.

Try a starter prompt (**New chat** in the sidebar):

> "Are any pods in the default namespace in CrashLoopBackOff? Investigate and tell me the root cause."

Foggy streams reasoning, runs `kubectl`, and returns a root-cause summary with evidence links.

## 6. What's next

* **[Kubernetes RBAC](./rbac).** Full permissions list — share with your security team before install.
* **[Upgrades](./upgrades).** Applying new Foggy releases.
* **Production hardening.** Enable Ingress with TLS, migrate to external Postgres, invite team members.

Upgrade via values file (recommended; avoids `--set` escaping issues with URL special characters):

```bash theme={null}
helm upgrade foggy foggy/foggy --namespace foggy -f values-production.yaml
```

Or inline via `--set-string` (use `--set-string` rather than `--set` so Helm doesn't split the connection-string `?` / `=` characters):

```bash theme={null}
helm upgrade foggy foggy/foggy --namespace foggy \
  --set ingress.enabled=true \
  --set ingress.host=foggy.your-company.com \
  --set postgresql.enabled=false \
  --set-string externalDatabase.url="postgresql+asyncpg://user:pass@db.your-company.com:5432/foggy?sslmode=require"
```

* **Invite team members.** Click your avatar → **Members**. Enter email, pick a role. They receive an invite link; once they sign in, they're added to your workspace.
