Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 212 additions & 0 deletions docs/content/guides/recipes/howto-nginx-gateway-routes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
---
type: docs
title: "How-To: Use NGINX Gateway Fabric with Radius routes"
linkTitle: "NGINX Gateway routes"
description: "Configure Radius.Compute/routes recipes to use NGINX Gateway Fabric."
weight: 300
categories: "How-To"
tags: ["recipes", "Kubernetes", "Networking"]
---

This guide shows platform operators how to install Radius without the default Contour ingress controller, install [NGINX Gateway Fabric](https://docs.nginx.com/nginx-gateway-fabric/), and configure the `Radius.Compute/routes` recipe to attach application routes to a Kubernetes Gateway API `Gateway`.

Use this pattern when your platform team wants to manage the Kubernetes Gateway controller separately from Radius while still letting application authors use portable Radius route resources.

## Prerequisites

- [Setup a supported Kubernetes cluster]({{< ref "/guides/installation/overview#supported-clusters" >}})
- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
- [Helm](https://helm.sh/docs/intro/install/)
- [rad CLI]({{< ref "installation#step-1-install-the-rad-cli" >}})

The examples use:

- Radius environment name: `default`
- Application namespace: `nginx-radius-demo`
- Gateway name: `radius`
- Route hostname: `nginx.example.com`

## Step 1: Install Radius without Contour

Install Radius and skip the default Contour installation:

```bash
rad install kubernetes --skip-contour-install
```

Create a resource group, workspace, and environment:

```bash
rad group create default
rad workspace create kubernetes default --group default --force
rad group switch default

rad env create default --preview
kubectl create namespace nginx-radius-demo
rad env update default --kubernetes-namespace nginx-radius-demo --preview
```

## Step 2: Install NGINX Gateway Fabric

Install the Gateway API standard channel CRDs:

```bash
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.0/standard-install.yaml
```

The standard channel includes the `GatewayClass`, `Gateway`, and `HTTPRoute` resources used in this guide. Use the experimental channel only if your route recipes need experimental Gateway API resources such as `TLSRoute`, `TCPRoute`, or `UDPRoute`.

Install NGINX Gateway Fabric:

```bash
helm upgrade --install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
--namespace nginx-gateway \
--create-namespace \
--wait

kubectl wait --timeout=5m \
--namespace nginx-gateway \
deployment/ngf-nginx-gateway-fabric \
--for=condition=Available
```

Create `gateway.yaml`:

```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: radius
namespace: nginx-radius-demo
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
```

Apply the Gateway:

```bash
kubectl apply -f gateway.yaml
kubectl wait --timeout=5m \
--namespace nginx-radius-demo \
gateway/radius \
--for=condition=Programmed
```

## Step 3: Configure Bicep extensions

Create `bicepconfig.json`. Use the current Radius release version, such as `0.58`.

```json
{
"experimentalFeaturesEnabled": {
"extensibility": true
},
"extensions": {
"radius": "br:biceptypes.azurecr.io/radius:<release-version>"
}
}
```

## Step 4: Register a routes recipe pack

Create `nginx-routes-recipe-pack.bicep`:

{{< rad file="snippets/nginx-routes-recipe-pack.bicep" embed=true >}}

Deploy the recipe pack and attach it to the environment:

```bash
rad deploy nginx-routes-recipe-pack.bicep \
--group default \
--environment /planes/radius/local/resourceGroups/default/providers/Radius.Core/environments/default

rad env update default --recipe-packs nginx-gateway --preview
```

The `gatewayName` and `gatewayNamespace` parameters tell the `Radius.Compute/routes` recipe which Kubernetes Gateway should receive generated `HTTPRoute` resources. This changes the route implementation in the environment without changing application code.

## Step 5: Deploy an application with a route

Create `app.bicep`:

{{< rad file="snippets/app.bicep" embed=true >}}

Deploy the application:

```bash
rad deploy app.bicep \
--group default \
--environment /planes/radius/local/resourceGroups/default/providers/Radius.Core/environments/default \
--parameters routeHostname=nginx.example.com
```

Radius deploys the container through the `Radius.Compute/containers` recipe and creates a Kubernetes `HTTPRoute` through the `Radius.Compute/routes` recipe.

## Step 6: Verify traffic

Check that the Gateway and route are accepted:

```bash
kubectl get gateway radius --namespace nginx-radius-demo
kubectl get httproute --namespace nginx-radius-demo
```

For local clusters, port-forward the NGINX Gateway service:

```bash
kubectl get service \
--namespace nginx-radius-demo \
--selector gateway.networking.k8s.io/gateway-name=radius \
--output name
```

Use the returned service name to port-forward traffic:

```bash
kubectl port-forward \
--namespace nginx-radius-demo \
service/<service-name> \
8080:80
```

In another terminal, send a request with the route hostname:

```bash
curl -H "Host: nginx.example.com" http://127.0.0.1:8080/
```

You should see the default NGINX welcome page.

## Clean up

Delete the application:

```bash
rad app delete nginx-radius-demo --yes
```

If you no longer need the NGINX recipe pack, first update the environment to use another recipe pack or delete the environment that references it. Then delete the recipe pack:

```bash
rad recipe-pack delete nginx-gateway --group default --yes
```

Uninstall NGINX Gateway Fabric:

```bash
helm uninstall ngf --namespace nginx-gateway
kubectl delete namespace nginx-gateway
```

## Further reading

- [Radius Recipes]({{< ref "/guides/recipes" >}})
- [Kubernetes installation]({{< ref "/guides/installation/kubernetes-install" >}})
- [Application networking]({{< ref "/guides/applications/networking/overview" >}})
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
extension radius

param environment string
param routeHostname string = 'nginx.example.com'

resource app 'Radius.Core/applications@2025-08-01-preview' = {
name: 'nginx-radius-demo'
properties: {
environment: environment
}
}

resource web 'Radius.Compute/containers@2025-08-01-preview' = {
name: 'web'
properties: {
environment: environment
application: app.id
containers: {
web: {
image: 'nginx:alpine'
ports: {
http: {
containerPort: 80
protocol: 'TCP'
}
}
}
}
}
}

resource route 'Radius.Compute/routes@2025-08-01-preview' = {
name: 'web'
properties: {
environment: environment
application: app.id
kind: 'HTTP'
hostnames: [
routeHostname
]
rules: [
{
matches: [
{
httpPath: '/'
}
]
destinationContainer: {
resourceId: web.id
containerName: 'web'
containerPort: web.properties.containers.web.ports.http.containerPort
}
}
Comment thread
willdavsmith marked this conversation as resolved.
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
extension radius

param recipeTag string = '0.58'

resource recipePack 'Radius.Core/recipePacks@2025-08-01-preview' = {
name: 'nginx-gateway'
location: 'global'
properties: {
recipes: {
'Radius.Compute/containers': {
recipeKind: 'bicep'
recipeLocation: 'ghcr.io/radius-project/kube-recipes/containers:${recipeTag}'
}
'Radius.Compute/routes': {
recipeKind: 'bicep'
recipeLocation: 'ghcr.io/radius-project/kube-recipes/routes:${recipeTag}'
parameters: {
gatewayName: 'radius'
gatewayNamespace: 'nginx-radius-demo'
}
}
}
}
}