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

# Ingress — NGINX, Istio, Kong, Traefik, and others

> NGINX Ingress, NGINX Gateway Fabric, community ingress-nginx, Istio, Kong, and Traefik using bundled manifests under examples/endpoints/.

## Overview

If you are not using a cloud-managed load balancer (see [GCP load balancer](/ax/selfhosting/installation/gcp/ingress-gcp-load-balancer) or [Azure load balancer](/ax/selfhosting/installation/azure/ingress-azure-load-balancer)), you can expose Arize AX with **NGINX Ingress (NGINX Inc)**, **NGINX Gateway Fabric**, **ingress-nginx (community)**, **Istio**, **Kong**, **Traefik**, or another controller that supports TLS, long-lived connections, and gRPC where needed.

All examples assume:

* The Arize AX operator has created the **`internalendpoints-app`** `Service` in the **`arize`** namespace (TLS on **port 443**).
* You replace placeholder domains and TLS material before `kubectl apply`.
* You align **`appBaseUrl`** / **`expBaseUrl`** (and **`ingressMode`**) in `values.yaml` with your hostname plan—see [Configuring ingress endpoints](/ax/selfhosting/installation/ingress/configuring-endpoints), especially the **Ingress Controllers** table for `ingressMode` and optional pod TLS fields.

Example sources live in the extracted distribution under:

```text theme={null}
examples/endpoints/
├── nginx/
│   ├── single-endpoint/
│   │   ├── nginx-ingress.yaml                     # NGINX Inc — Ingress API (terminate at ingress)
│   │   ├── nginx-transportserver-passthrough.yaml # NGINX Inc — TLS passthrough (TransportServer)
│   │   ├── nginx-gateway-fabric.yaml              # NGINX Inc — Gateway API
│   │   └── nginx-legacy.yaml                      # Community ingress-nginx (deprecated path)
│   └── multi-endpoint/
│       ├── nginx-ingress.yaml
│       ├── nginx-gateway-fabric.yaml
│       └── nginx-legacy.yaml
├── istio/
│   ├── app-services.yaml               # Gateway + VirtualService + EnvoyFilter
│   └── envoy-filter-http2.yaml         # Same EnvoyFilter recipe, standalone
├── kong/
│   └── app-services.yaml               # Kong Ingress
└── traefik/
    └── app-services.yaml               # Traefik Ingress + IngressRoute
```

Copy the file you need into a working file, edit placeholders, then apply from the extract root, for example:

```bash theme={null}
kubectl apply -n arize -f my-nginx-ingress.yaml
```

Adjust **`ingressClassName`** (or Gateway **`gatewayClassName`**) to match the class installed in your cluster.

<Tabs>
  <Tab title="NGINX Inc (Ingress API)">
    **Paths:** `nginx/single-endpoint/nginx-ingress.yaml` and `nginx/multi-endpoint/nginx-ingress.yaml`\
    **Docs:** [NGINX Ingress Controller](https://docs.nginx.com/nginx-ingress-controller/) (OSS or NGINX Plus)

    These manifests use the **`networking.k8s.io/v1` `Ingress`** API with **`ingressClassName: nginx`**. Traffic is forwarded to **`internalendpoints-app:443`**. TLS is terminated at the ingress using a **`kubernetes.io/tls`** secret in `arize` (for example `arize-app-services-tls` in the single-endpoint file).

    **Single host (`nginx/single-endpoint/nginx-ingress.yaml`):**

    * One hostname (`{{CUSTOMER_DOMAIN}}`) for UI, GraphQL, REST, OTLP, and Arrow Flight through the unified internal endpoint service.
    * **`ConfigMap`** `nginx-ingress` in your NGINX install namespace (default comment uses `nginx-ingress`) sets **`http2: "true"`** so gRPC and HTTP/2 behave correctly—rename the ConfigMap or namespace if your Helm release differs (for example NGINX Plus chart defaults).
    * Key **`Ingress` annotations:** `nginx.org/ssl-services` and `nginx.org/grpc-services` set to **`internalendpoints-app`**, plus long **`proxy-read-timeout` / `proxy-send-timeout`** (7200s) for large exports and streams.

    **Multiple hosts (`nginx/multi-endpoint/nginx-ingress.yaml`):**

    * Separate **`Ingress`** objects per role: **`arize-app`** (UI / GraphQL), **`arize-api`** (REST), **`arize-otlp`** (OTLP), **`arize-flight`** (Arrow Flight), each with its own TLS secret and host (`{{CUSTOMER_APP_DOMAIN}}`, `{{CUSTOMER_API_DOMAIN}}`, etc.).
    * OTLP and Flight ingresses include **`nginx.org/grpc-services: "internalendpoints-app"`**; app/API ingresses rely on **`nginx.org/ssl-services`** for HTTPS to the backend.

    **`values.yaml` alignment (from file headers):**

    * Single-endpoint: `appBaseUrl: "https://{{CUSTOMER_DOMAIN}}"`, `expBaseUrl: "{{CUSTOMER_DOMAIN}}"`.
    * Multi-endpoint: `appBaseUrl: "https://{{CUSTOMER_APP_DOMAIN}}"`, `expBaseUrl: "{{CUSTOMER_FLIGHT_DOMAIN}}"` (Flight host for export-related settings).

    After apply, point DNS at the NGINX Service / LoadBalancer IP and verify with `kubectl -n arize describe ingress <name>`.
  </Tab>

  <Tab title="NGINX TLS passthrough (TransportServer)">
    **Path:** `nginx/single-endpoint/nginx-transportserver-passthrough.yaml`\
    **Docs:** [TransportServer resources](https://docs.nginx.com/nginx-ingress-controller/configuration/transportserver-resource/)

    Use this when TLS must terminate at the Arize pod (same model as OpenShift passthrough routes or Layer-4 NLB passthrough). F5 NGINX Ingress Controller does **not** expose TLS passthrough via an `Ingress` annotation; configure a **`TransportServer`** with listener **`tls-passthrough`** / protocol **`TLS_PASSTHROUGH`**.

    **Prerequisites:**

    * Enable **`controller.enableTLSPassthrough`** on the NGINX Ingress Controller (NGINX Ingress Operator: `spec.controller.enableTLSPassthrough: true` on the `NginxIngress` CR).
    * Set **`ingressMode: "tls"`** and supply a pod-facing certificate whose **SAN/CN matches the public hostname** via **`internalEndpointsAppTlsCert`** / **`internalEndpointsAppTlsKey`** (or **`internalEndpointsAppTlsSecretName`**). The auto-generated in-cluster cert is not valid for clients hitting the external domain.
    * Do **not** apply a terminating **`Ingress`** for the same hostname on port 443 alongside this `TransportServer`.

    **Single host (`nginx/single-endpoint/nginx-transportserver-passthrough.yaml`):**

    * SNI hostname **`{{CUSTOMER_DOMAIN}}`** routes opaque TLS to **`internalendpoints-app:443`**.
    * DNS targets the **same** NGINX Ingress Controller Service LoadBalancer IP as other examples (`TransportServer` does not allocate a separate VIP).

    After apply, verify with `kubectl -n arize describe transportserver arize-app-tls-passthrough` and test `https://{{CUSTOMER_DOMAIN}}`.
  </Tab>

  <Tab title="NGINX Gateway Fabric">
    **Paths:** `nginx/single-endpoint/nginx-gateway-fabric.yaml` and `nginx/multi-endpoint/nginx-gateway-fabric.yaml`\
    **Docs:** [NGINX Gateway Fabric](https://docs.nginx.com/nginx-gateway-fabric/)

    These examples use the **Kubernetes Gateway API** (`Gateway`, `HTTPRoute`, `GRPCRoute`) with **`gatewayClassName: nginx`**. Client TLS is terminated on the **`Gateway`** using **`arize-app-services-tls`**. The backend is still **`internalendpoints-app:443`** (HTTPS/gRPC on the pod side).

    **Single-endpoint file highlights:**

    * **`BackendTLSPolicy`** validates the upstream using a CA stored in ConfigMap `backend-cert`—populate `ca.crt` with PEM from the backend secret, for example:

    ```bash theme={null}
    kubectl -n arize get secret internalendpoints-app-tls -o jsonpath='{.data.tls\.crt}' | base64 -d
    ```

    * **`HTTPRoute`** and **`GRPCRoute`** attach to the same `Gateway` and route all paths to `internalendpoints-app` port **443**.

    **Multi-endpoint** follows the same pattern with separate hostnames and routes per the comments in that file.

    Ensure your cluster runs **NGINX Gateway Fabric** and the **`GatewayClass`** named `nginx` (or edit `gatewayClassName` to match your installation).
  </Tab>

  <Tab title="ingress-nginx (community)">
    **Paths:** `nginx/single-endpoint/nginx-legacy.yaml` and `nginx/multi-endpoint/nginx-legacy.yaml`\
    **Docs:** [ingress-nginx](https://kubernetes.github.io/ingress-nginx/)

    The upstream **ingress-nginx** project is headed for retirement; the manifest headers link to the Kubernetes announcement and recommend **NGINX Inc** or **Gateway Fabric** for new deployments.

    These examples mirror the NGINX Inc layout but use **`nginx.ingress.kubernetes.io/*`** annotations and **`spec.ingressClassName: nginx`**. The backend is **`internalendpoints-app:443`** with **`nginx.ingress.kubernetes.io/backend-protocol: GRPCS`** in the single-endpoint sample so the controller speaks TLS+gRPC to the service.

    Use only if you already run community ingress-nginx and are planning a migration.
  </Tab>

  <Tab title="Istio">
    **Paths:** `istio/app-services.yaml` and (optional) `istio/envoy-filter-http2.yaml`\
    **Docs:** [Istio ingress gateway](https://istio.io/latest/docs/tasks/traffic-management/ingress/)

    **`istio/app-services.yaml`** defines:

    1. **`Gateway`** `arize-app-services-gw` in `arize`, bound to pods with **`istio: ingressgateway`**, port **443**, TLS mode **SIMPLE**, and **`credentialName: arize-app-services-tls`** (create this TLS secret in **`arize`** so Istio can mount it for the gateway).
    2. **`VirtualService`** routing host `arize-app.<domain>` to **`internalendpoints-app:443`** for all paths.
    3. **`EnvoyFilter`** `flightserver-http2-settings` tuning HTTP/2 frame limits for workloads labeled **`app: flightserver`** (Arrow Flight throughput).

    **`istio/envoy-filter-http2.yaml`** contains the same EnvoyFilter tuning as a standalone file—use it if you prefer to manage that object separately; do **not** duplicate the same resource name if you already applied `app-services.yaml`.

    Set **`ingressMode: istio`** in `values.yaml` per [Configuring ingress endpoints](/ax/selfhosting/installation/ingress/configuring-endpoints). Replace **`arize-app.<domain>`** in the manifest with your real hostname; keep **`appBaseUrl` / `expBaseUrl`** consistent.
  </Tab>

  <Tab title="Kong">
    **Path:** `kong/app-services.yaml`\
    **Docs:** [Kong Ingress Controller](https://docs.konghq.com/kubernetes-ingress-controller/)

    Single **`Ingress`** with **`ingressClassName: kong`**, TLS host `arize-app.<domain>`, and backend **`internalendpoints-app:443`**. Kong annotations request **HTTPS and gRPCS** to the upstream, no body size cap, and long read/write timeouts (2 hours) to match large exports:

    * `konghq.com/protocols: https,grpcs`
    * `konghq.com/read-timeout` / `write-timeout` / `connect-timeout` in milliseconds

    Create the TLS secret **`arize-app-services-tls`** referenced in the manifest. Install the Kong Ingress Controller and a matching `IngressClass` named **`kong`** (or change `ingressClassName`).

    Use **`ingressMode: tls`** (default for Kong in the shared controller table) unless your platform team specifies otherwise.
  </Tab>

  <Tab title="Traefik">
    **Path:** `traefik/app-services.yaml`\
    **Docs:** [Traefik](https://doc.traefik.io/traefik/)

    Traefik terminates TLS in front of the unified `internalendpoints-app` service (HTTP, REST, gRPC, OTLP, and Flight). For that pattern, Arize AX must be deployed with TLS **off** on the pod-facing path and HTTP/2 cleartext (h2c) from the ingress to the service.

    In `values.yaml`, set:

    ```yaml theme={null}
    ingressMode: "notls"
    ```

    Make a copy of the example manifest.

    ```bash theme={null}
    cp ./examples/endpoints/traefik/app-services.yaml my-app-services.yaml
    ```

    Edit hostnames, TLS secrets, Traefik entry points (`websecure` in the sample), and optional `IngressRoute` / `TLSStore` resources to match your cluster. If you only need one routing mechanism, you may remove either the standard `Ingress` or the `IngressRoute` to avoid duplicate routes. The sample `TLSStore` and `default-ingress-cert` Secret use `kube-system`; if Traefik is installed in another namespace, put those resources (or equivalents) there, or omit them if you do not need a Traefik default certificate.

    Apply the manifest after the Arize AX services exist.

    ```bash theme={null}
    kubectl -n arize apply -f my-app-services.yaml
    ```

    Verify DNS resolves to your Traefik load balancer.

    ```bash theme={null}
    nslookup arize-app.<my-organization-domain>
    ```

    Open `https://arize-app.<my-organization-domain>` in a browser. Add URL parameters to `values.yaml` if they are not already set:

    ```yaml theme={null}
    appBaseUrl: "https://arize-app.<my-organization-domain>"
    expBaseUrl: "arize-app.<my-organization-domain>"
    ```
  </Tab>
</Tabs>

## After you apply

1. **`kubectl -n arize describe ingress <name>`** (or **`kubectl describe gateway`** / routes for Gateway API) until addresses are assigned.
2. Create **DNS A/AAAA** (or CNAME) records to that address.
3. Update **`values.yaml`** with **`appBaseUrl`** and **`expBaseUrl`**, then upgrade the release or operator values as you do for other changes.
4. Confirm **`ingressMode`** and any **`internalEndpointsAppTlsCert` / `internalEndpointsAppTlsKey`** requirements from the [Ingress Controllers](/ax/selfhosting/installation/ingress/configuring-endpoints#ingress-controllers) table.

## Cross-reference

* Cloud load balancer paths: [GCP load balancer](/ax/selfhosting/installation/gcp/ingress-gcp-load-balancer), [Azure load balancer](/ax/selfhosting/installation/azure/ingress-azure-load-balancer).
* AWS, OpenShift, and generic controller guidance: [Configuring ingress endpoints](/ax/selfhosting/installation/ingress/configuring-endpoints).
