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

# Gateway, Ingress & Routes

> Configure Gateway API, Kubernetes Ingress, or OpenShift Routes for Cobi

## Platform Choice

The chart supports Gateway API, Kubernetes Ingress, and OpenShift Routes for the user-facing app/API path. Enable **one** depending on your platform.

| Platform              | Mechanism                      | Values key                |
| --------------------- | ------------------------------ | ------------------------- |
| Kubernetes, preferred | Gateway API with Envoy Gateway | `gateway.enabled`         |
| Kubernetes, nginx     | `Ingress`                      | `ingress.enabled`         |
| OpenShift             | `Route`                        | `openshift.route.enabled` |

***

## Kubernetes — Gateway API with Envoy Gateway

Gateway API is the preferred option for the kOps v2 rehearsal profile and for self-hosted clusters that already run Envoy Gateway.

### Prerequisites

Install Gateway API CRDs, cert-manager with Gateway support, and Envoy Gateway:

```bash theme={null}
kubectl apply --server-side -f \
  https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/standard-install.yaml

helm upgrade --install cert-manager oci://quay.io/jetstack/charts/cert-manager \
  --version v1.20.2 \
  --namespace cert-manager \
  --create-namespace \
  --set crds.enabled=true \
  --set config.enableGatewayAPI=true

helm upgrade --install eg oci://docker.io/envoyproxy/gateway-helm \
  --version v1.7.3 \
  --namespace envoy-gateway-system \
  --create-namespace
```

Create or reuse a `GatewayClass` named `eg`. On AWS kOps, the kOps v2 reference configures Envoy's data-plane Service as an internet-facing NLB.

### Values

```yaml theme={null}
ingress:
  enabled: false

gateway:
  enabled: true
  gatewayClass:
    create: false
    name: eg
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  tls:
    enabled: true
    app:
      secretName: cobi-dashboard-app-tls
    api:
      secretName: cobi-dashboard-api-tls
    connect:
      secretName: cobi-dashboard-connect-tls
  app:
    enabled: true
    hostname: app.example.com
  api:
    enabled: true
    hostname: api.example.com
    timeouts:
      request: 0s
      backendRequest: 0s
  connect:
    enabled: true
    hostname: connect.example.com
    timeouts:
      request: 0s
      backendRequest: 0s
  minio:
    enabled: false
  grafana:
    enabled: false
```

Set the corresponding application URLs:

```bash theme={null}
# Frontend
--from-literal=VITE_API_BASE_URL="https://api.example.com"
--from-literal=VITE_API_SANDBOX_URL="https://api.example.com"

# Backend
--from-literal=BETTER_AUTH_URL="https://api.example.com"
--from-literal=FRONTEND_URL="https://app.example.com"
--from-literal=CONNECT_SERVICE_URL="http://cobi-dashboard-connect:8000"
```

### Verify

```bash theme={null}
kubectl get gateway -n cobi
kubectl get httproute -n cobi
kubectl get svc -n envoy-gateway-system
```

***

## Kubernetes — Ingress

The frontend and backend each get their own Ingress and their own hostname. The frontend makes API calls to the backend hostname directly — there is no `/api` path proxying.

### Prerequisites

Install `ingress-nginx` before deploying the chart:

```bash theme={null}
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  --set controller.replicaCount=2
```

Wait for the LoadBalancer IP or hostname:

```bash theme={null}
kubectl get svc -n ingress-nginx ingress-nginx-controller \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
```

Create DNS A records for both hostnames pointing at this address.

### Separate-host values

Ingress is configured under the top-level `ingress` block:

```yaml theme={null}
gateway:
  enabled: false

ingress:
  enabled: true
  className: nginx
  annotations: {}
  tls:
    - secretName: cobi-dashboard-tls
      hosts:
        - app.example.com
        - api.example.com
        - connect.example.com
  app:
    enabled: true
    host: app.example.com
  api:
    enabled: true
    host: api.example.com
  connect:
    enabled: true
    host: connect.example.com
  minio:
    enabled: false
  grafana:
    enabled: false
```

Set the corresponding URLs in the frontend and backend Secrets:

```bash theme={null}
# Frontend — points at the backend hostname
--from-literal=VITE_API_BASE_URL="https://api.example.com"

# Backend — points at itself, the frontend, and the in-cluster Connect service
--from-literal=BETTER_AUTH_URL="https://api.example.com"
--from-literal=FRONTEND_URL="https://app.example.com"
--from-literal=CONNECT_SERVICE_URL="http://cobi-dashboard-connect:8000"
```

### Shared-host values

Shared-host mode routes the frontend at `/` and the backend at `ingress.apiPrefix`:

```yaml theme={null}
ingress:
  enabled: true
  className: nginx
  host: cobi.example.com
  apiPrefix: /api
  tls:
    - secretName: cobi-dashboard-tls
      hosts:
        - cobi.example.com
```

### TLS — cert-manager (recommended)

```bash theme={null}
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set crds.enabled=true
```

```yaml theme={null}
# cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx
```

```bash theme={null}
kubectl apply -f cluster-issuer.yaml
```

Add the annotation under the top-level `ingress` block:

```yaml theme={null}
ingress:
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  tls:
    - secretName: cobi-dashboard-tls
      hosts:
        - app.example.com
        - api.example.com
```

### TLS — Pre-existing certificates

```bash theme={null}
kubectl create secret tls cobi-dashboard-tls --cert=tls.crt --key=tls.key --namespace cobi
```

***

## OpenShift — Frontend and API Routes

OpenShift uses Routes instead of Ingress. The chart creates Routes for the frontend and backend API. Connect stays internal through `CONNECT_SERVICE_URL` unless your deployment needs a public Connect endpoint.

### Values

```yaml theme={null}
ingress:
  enabled: false

gateway:
  enabled: false

# Enable OpenShift Routes
openshift:
  route:
    enabled: true
    host: dashboard.apps.cluster.example.com
    api:
      enabled: true
      host: api.apps.cluster.example.com
```

The Routes use **edge TLS termination** — TLS is terminated at the OpenShift router, plain HTTP to the pods.

### Generated Route resources

```yaml theme={null}
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: cobi-dashboard-frontend
  namespace: cobi
spec:
  host: dashboard.apps.cluster.example.com
  to:
    kind: Service
    name: cobi-dashboard-frontend
  port:
    targetPort: http
  tls:
    termination: edge
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: cobi-dashboard-backend
  namespace: cobi
spec:
  host: api.apps.cluster.example.com
  to:
    kind: Service
    name: cobi-dashboard-backend
  port:
    targetPort: http
  tls:
    termination: edge
```

Set the corresponding URLs in the frontend and backend Secrets:

```bash theme={null}
# Frontend — points at the backend route hostname
--from-literal=VITE_API_BASE_URL="https://api.apps.cluster.example.com"

# Backend — use the public API URL created for your backend
--from-literal=BETTER_AUTH_URL="https://api.apps.cluster.example.com"
--from-literal=FRONTEND_URL="https://dashboard.apps.cluster.example.com"
```

***

## Observability (Grafana)

Expose the Grafana UI from the `otel-lgtm` component when `otelLgtm.enabled: true`:

```yaml theme={null}
ingress:
  enabled: true
  grafana:
    enabled: true
    host: grafana.example.com
```

***

## Internal Service Addresses

When configuring Secrets, use these ClusterIP hostnames (release name `cobi-dashboard`, namespace `cobi`):

| Service         | Internal address                       |
| --------------- | -------------------------------------- |
| Backend         | `cobi-dashboard-backend:3000`          |
| Frontend        | `cobi-dashboard-frontend:8080`         |
| Connect         | `cobi-dashboard-connect:8000`          |
| PostgreSQL      | `cobi-dashboard-postgresql:5432`       |
| Qdrant          | `cobi-dashboard-qdrant:6333`           |
| MinIO (API)     | `cobi-dashboard-minio:9000`            |
| MinIO (Console) | `cobi-dashboard-minio:9001`            |
| vLLM            | `cobi-dashboard-vllmstack-engine:8000` |
