---
title: "NGINX Gateway Fabric: Installation, Routing, and Ingress Migration | Hostman Docs"
description: "Learn how to install NGINX Gateway Fabric on Kubernetes, configure Gateway and HTTPRoute to route HTTP traffic across services, and migrate from Nginx Ingress using ingress2gateway."
---

> For the complete documentation index for AI agents, see [llms.txt](https://hostman.com/llms.txt).

NGINX Gateway Fabric is a Kubernetes Gateway API controller that uses NGINX to handle incoming traffic. You can use it to publish HTTP, HTTPS, gRPC, TCP, and UDP services, configure routing by domain and path, manage TLS, and gradually transition from Ingress to the Gateway API.

Gateway API is the evolution of Ingress. Instead of a single Ingress resource, it splits responsibilities across several dedicated objects:

-   `GatewayClass` defines which controller will manage the gateways.
-   `Gateway` describes the entry point: ports, protocols, domains, and TLS settings.
-   `HTTPRoute` defines HTTP traffic routing rules to backend services.
-   `GRPCRoute`, `TCPRoute`, `UDPRoute`, `TLSRoute` handle other traffic types.

NGINX Gateway Fabric watches Gateway API resources and uses them to create an NGINX data plane: NGINX pods and a service through which external traffic enters the cluster and is routed to Kubernetes services.

## Installation

Before installing NGINX Gateway Fabric from the dashboard, you need to manually install the Gateway API CRDs.

Specify the NGINX Gateway Fabric version in the `ref` parameter. For example, for version `v2.6.3`:

```shell
kubectl kustomize "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.6.3" | kubectl apply -f -
```

After installing the CRDs:

1.  Go to the **Kubernetes** section and click on the cluster.
2.  Navigate to the **Addons** tab and select **NGINX Gateway Fabric**.
3.  (Optional) Enable **Advanced setup** to edit `values.yaml`. For most use cases, the defaults are a good starting point.
4.  Click **Install**.
5.  Wait for the process to complete and verify that the NGINX Gateway Fabric pods are running:

```shell
kubectl get pods -n nginx-gateway
```

All pods should show a `Running` status.

You can also confirm that the Gateway API resources are available in the cluster:

```shell
kubectl api-resources | grep gateway.networking.k8s.io
```

A standard installation of NGINX Gateway Fabric creates a `GatewayClass` named `nginx`. Check its status:

```shell
kubectl get gatewayclass nginx
```

The `ACCEPTED` column should show `True`.

## Usage Example

This example shows how to configure NGINX Gateway Fabric to accept HTTP traffic on a single external IP and route requests to two different services:

-   `http://app.example.com/service1 routes to service1`
-   `http://app.example.com/service2 routes to service2`

Start by creating a dedicated namespace:

```shell
kubectl create namespace nginx-gateway-example
```

### Create a ConfigMap

Create a file called `configmap.yaml` with HTML pages for both services:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
 name: nginx-pages
 namespace: nginx-gateway-example
data:
 service1.html: |
   <html>
     <head><title>Service 1</title></head>
     <body><h1>Service 1</h1></body>
   </html>
 service2.html: |
   <html>
     <head><title>Service 2</title></head>
     <body><h1>Service 2</h1></body>
   </html>
```

Apply the manifest:

```shell
kubectl apply -f configmap.yaml
```

### Create Deployments and Services

Create `service1.yaml`:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
 name: service1
 namespace: nginx-gateway-example
spec:
 replicas: 2
 selector:
   matchLabels:
     app: service1
 template:
   metadata:
     labels:
       app: service1
   spec:
     containers:
       - name: nginx
         image: nginx:latest
         ports:
           - containerPort: 80
         volumeMounts:
           - name: html
             mountPath: /usr/share/nginx/html
     volumes:
       - name: html
         configMap:
           name: nginx-pages
           items:
             - key: service1.html
               path: index.html
---
apiVersion: v1
kind: Service
metadata:
 name: service1
 namespace: nginx-gateway-example
spec:
 selector:
   app: service1
 ports:
   - name: http
     port: 80
     targetPort: 80
 type: ClusterIP
```

Create `service2.yaml`:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
 name: service2
 namespace: nginx-gateway-example
spec:
 replicas: 2
 selector:
   matchLabels:
     app: service2
 template:
   metadata:
     labels:
       app: service2
   spec:
     containers:
       - name: nginx
         image: nginx:latest
         ports:
           - containerPort: 80
         volumeMounts:
           - name: html
             mountPath: /usr/share/nginx/html
     volumes:
       - name: html
         configMap:
           name: nginx-pages
           items:
             - key: service2.html
               path: index.html
---
apiVersion: v1
kind: Service
metadata:
 name: service2
 namespace: nginx-gateway-example
spec:
 selector:
   app: service2
 ports:
   - name: http
     port: 80
     targetPort: 80
 type: ClusterIP
```

Apply both manifests:

```shell
kubectl apply -f service1.yaml
kubectl apply -f service2.yaml
```

Verify the pods are running:

```shell
kubectl get pods -n nginx-gateway-example
```

### Create a Gateway

The `Gateway` resource defines the external entry point for your application. With a standard NGINX Gateway Fabric installation, it manages Gateways that use `gatewayClassName: nginx`.

Create `gateway.yaml`:

```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
 name: app-gateway
 namespace: nginx-gateway-example
spec:
 gatewayClassName: nginx
 listeners:
   - name: http
     hostname: app.example.com
     protocol: HTTP
     port: 80
     allowedRoutes:
       namespaces:
         from: Same
```

Apply it:

```shell
kubectl apply -f gateway.yaml
```

Once the `Gateway` is created, NGINX Gateway Fabric will deploy an NGINX data plane and a load balancer in the `nginx-gateway-example` namespace. Check the status with:

```shell
kubectl get gateway app-gateway -n nginx-gateway-example
```

Wait until `PROGRAMMED` shows `True` and `ADDRESS` shows an external IP.

You can also inspect the resources that were created:

```shell
kubectl get deployments -n nginx-gateway-example
kubectl get svc -n nginx-gateway-example
```

> [!NOTE]
> NGINX Gateway Fabric creates a dedicated NGINX data plane for each `Gateway`, so you don't need to create a separate `LoadBalancer` service as you would with a classic Ingress controller setup.

### Create an HTTPRoute

`HTTPRoute` defines the routing rules.

Create `httproute.yaml`:

```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
 name: app-route
 namespace: nginx-gateway-example
spec:
 parentRefs:
   - name: app-gateway
 hostnames:
   - app.example.com
 rules:
   - matches:
       - path:
           type: PathPrefix
           value: /service1
     filters:
       - type: URLRewrite
         urlRewrite:
           path:
             type: ReplacePrefixMatch
             replacePrefixMatch: /
     backendRefs:
       - name: service1
         port: 80
   - matches:
       - path:
           type: PathPrefix
           value: /service2
     filters:
       - type: URLRewrite
         urlRewrite:
           path:
             type: ReplacePrefixMatch
             replacePrefixMatch: /
     backendRefs:
       - name: service2
         port: 80
```

Apply it:

```shell
kubectl apply -f httproute.yaml
```

Confirm the route is accepted:

```shell
kubectl get httproute app-route -n nginx-gateway-example -o yaml
```

The resource status should include both conditions:

```shell
status: "True"
type: Accepted
status: "True"
type: ResolvedRefs
```

This `HTTPRoute` accepts requests for `app.example.com` and routes them to different services based on the path prefix. The `URLRewrite` filter strips the `/service1` and `/service2` prefixes, replacing them with `/`, so NGINX inside each service serves its main page correctly.

### Verify the Setup

Add the load balancer IP as an A record for `app.example.com` in your DNS settings. Once DNS propagates, test both endpoints:

```shell
curl http://app.example.com/service1
curl http://app.example.com/service2
```

If DNS hasn't propagated yet, you can test by IP using the `Host` header:

```shell
curl -H "Host: app.example.com" http://<EXTERNAL_IP>/service1
curl -H "Host: app.example.com" http://<EXTERNAL_IP>/service2
```

Both requests should return the respective Service 1 and Service 2 pages.

### Clean Up

To remove all resources created in this example, run:

```shell
kubectl delete namespace nginx-gateway-example
```

This does not uninstall the NGINX Gateway Fabric add-on. To remove it, go to the **Addons** tab in the cluster dashboard.

## Migrating from Nginx Ingress to NGINX Gateway Fabric

You can run NGINX Gateway Fabric alongside Nginx Ingress and migrate routes gradually. This lets you test Gateway API resources on a separate external IP before switching DNS records or redirecting traffic to the new Gateway.

To automate the conversion of existing Ingress resources, use the [ingress2gateway](https://github.com/kubernetes-sigs/ingress2gateway) utility. It reads Ingress resources from your cluster or from YAML files and outputs equivalent Gateway API resources: `Gateway`, `HTTPRoute`, and related objects.

> [!NOTE]
> **Important**: `ingress2gateway` is a helpful starting point, but it is not a fully automatic migration tool. Some Nginx Ingress annotations may not be supported or may require manual configuration after conversion.

### Prerequisites

Before migrating, make sure your cluster is ready:

-   Nginx Ingress and NGINX Gateway Fabric are both installed.
-   Existing Ingress resources are working correctly through Nginx Ingress.
-   A `GatewayClass` named `nginx` exists in the cluster.

If Nginx Ingress was installed from the Hostman dashboard, it uses an `IngressClass` named `nginx`. You will need this name when running `ingress2gateway`.

Check that both classes are present:

```shell
kubectl get ingressclass
kubectl get gatewayclass
```

The output should include an `IngressClass` named `nginx` and a `GatewayClass` named `nginx`.

### Install ingress2gateway

If you have Go installed locally, run:

```shell
go install github.com/kubernetes-sigs/ingress2gateway@v1.1.0
```

The binary will be placed in `$(go env GOPATH)/bin`. Make sure this directory is in your PATH.

Alternatively, install via Homebrew:

```shell
brew install ingress2gateway
```

Or download a prebuilt binary from the [project releases page](https://github.com/kubernetes-sigs/ingress2gateway/releases).

### Source Setup

In this example, the migration targets an application already published through Nginx Ingress.

The cluster has a namespace called `ingress-migration-demo` containing:

-   An Ingress resource named `migration-source`
-   Services `service1` and `service2`
-   Two routing rules for the domain `app.example.com`:
    -   `/service1` routes to `service1`
    -   `/service2` routes to `service2`

Verify the source Ingress:

```shell
kubectl get ingress -n ingress-migration-demo
```

The `CLASS` column should show `nginx`.

### Convert Ingress Resources

To convert the Ingress to Gateway API resources, run:

```shell
ingress2gateway print \
  --providers=ingress-nginx \
  --ingress-nginx-ingress-class=nginx \
  --namespace=ingress-migration-demo > gateway-migration.yaml
```

The flags in this command:

-   `print` outputs the generated resources to stdout; the `>` redirect saves them to `gateway-migration.yaml`.
-   `--providers=ingress-nginx` specifies the source Ingress controller type.
-   `--ingress-nginx-ingress-class=nginx` filters for Ingress resources using the `nginx` class.
-   `--namespace=ingress-migration-demo` scopes the conversion to the source namespace.

### Review and Fix the Output

Open `gateway-migration.yaml` and review the generated resources before applying them.

Check the `gatewayClassName` field in the `Gateway` resource. For a standard NGINX Gateway Fabric installation, the value should be `nginx`:

```yaml
spec:
  gatewayClassName: nginx
```

Also review the `HTTPRoute` rules. Some Ingress annotations may be converted into filters or match types that need manual adjustment. For example, for standard path prefix routing, use `PathPrefix`:

```yaml
rules:
 - matches:
     - path:
         type: PathPrefix
         value: /service1
   filters:
     - type: URLRewrite
       urlRewrite:
         path:
           type: ReplacePrefixMatch
           replacePrefixMatch: /
   backendRefs:
     - name: service1
       port: 80
```

If the generated file contains `RegularExpression` routes or unsupported annotations, check their compatibility with NGINX Gateway Fabric and replace them with supported Gateway API rules.

### Apply the Gateway API Resources

Once you're satisfied with the output, apply it:

```shell
kubectl apply -f gateway-migration.yaml
```

Verify the `Gateway` has been created and has received an external IP:

```shell
kubectl get gateway -A
```

Check that the `HTTPRoute` has been accepted by the controller:

```shell
kubectl get httproute -A
kubectl describe httproute <route-name> -n <namespace>
```

The `HTTPRoute` status should show both `Accepted=True` and `ResolvedRefs=True`.

### Test Before Switching Traffic

While your DNS records still point to the old Nginx Ingress, verify the new `Gateway` by sending requests directly to its external IP with a `Host` header:

```shell
curl -H "Host: app.example.com" http://<EXTERNAL_IP>/<path>
```

Where:

-   `app.example.com` is the domain from your `HTTPRoute`.
-   `<EXTERNAL_IP>` is the IP address of the new `Gateway`.
-   `<path>` is the path handled by the route.

Compare the responses from the old Ingress and the new `Gateway`. If everything looks correct, update your DNS records to point to the new load balancer's IP.
