Skip to main content

Overview

Nginx is a high-performance web server and reverse proxy. This template deploys Nginx as a stateless reverse proxy that routes incoming requests by path to other workloads in the same GVC, so several internal services can share one public endpoint. The nginx.conf is generated from your locations values and mounted into the container from a secret. A default install also deploys a small example backend and routes every request to it, so you can confirm the proxy works before pointing it at your own services.
This template does not create a GVC. It deploys into an existing GVC that you already have, and every workload it proxies to must already exist in that same GVC.

What Gets Created

Prerequisites

None for a default install. To proxy to your own services, each target workload must already exist in the same GVC, and its internal firewall must allow traffic from RELEASE_NAME-nginx (for example same-gvc, or a workload list that includes the proxy).

Installation

Install the template into an existing GVC. No --set values are required:
To install using another method, follow the instructions for your preferred tool:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

Proxy Workload

  • proxyWorkload.image — the Nginx container image.
  • proxyWorkload.port — the container port exposed by the workload. Leave it at 80: the generated nginx.conf listens on 80 and the health probes check port 80, neither of which follows this value.
  • proxyWorkload.capacityAI — enables Control Plane CapacityAI on the proxy workload.
  • proxyWorkload.timeoutSeconds — the workload request timeout in seconds.

Resources

  • resources.cpu / resources.memory — the CPU and memory limit for each Nginx replica.

Autoscaling

  • autoscaling.minScale / autoscaling.maxScale — the minimum and maximum replica count. The proxy is stateless, so raising maxScale scales it horizontally.
  • autoscaling.maxConcurrency — the maximum number of concurrent requests per replica.
The scaling metric is fixed in the chart: CPU, with a 50 percent target.

Example Backend

When true, the chart deploys RELEASE_NAME-example and routes every / request to it. Set it to false before routing to your own services; otherwise the example keeps the / route.

Locations

Each entry becomes one Nginx location block that forwards matching requests to a workload in the same GVC: Enter only the workload name in workload. The chart builds the fully qualified internal hostname itself, WORKLOAD_NAME.GVC_NAME.cpln.local, and uses it for both the upstream address and the Host header sent to the target. Example routing two paths to two services:

Built-in Routes

Two routes are always present, whatever locations contains: Any 500, 502, 503 or 504 from an upstream workload is replaced with the /fail response, so the client sees the JSON error body rather than the upstream page.

Connecting

Read the canonical endpoint:
Then check the built-in health route:
A response of {"success":true,"message":"OK"} means Nginx is serving. With the example backend enabled, a request to https://CANONICAL_ENDPOINT/ returns the example greeting page.

Operations

Changing the Routing

The nginx.conf lives in the RELEASE_NAME-nginx-config secret and is rebuilt from your values on every Helm upgrade. Edit locations (and enableExample) in your values file, then upgrade:
The values file must use the chart’s nesting, exactly as the blocks in Configuration show. A flat dotted key is accepted without error and silently changes nothing. The configuration is mounted as a file, and a running replica keeps the file it started with. Force a redeployment so every replica starts with the new nginx.conf:
Then confirm a route you changed answers on the public endpoint. Whether the upgrade alone restarts the proxy has not been verified on this template, so run the redeployment every time. Edit routing through Helm values only. Whether a later upgrade overwrites a hand edit to the secret has not been verified, so keep your routing in your values file and re-check the secret after every upgrade.

Upgrading From 1.1.1 or Earlier

Versions 1.1.1 and earlier defaulted proxyWorkload.image to nginx:latest. Version 1.1.2 pins it to nginx:1.31.4, so an upgrade that does not set the image restarts the proxy on the pinned version. The proxy holds no data, so nothing needs to be migrated. To keep a specific image, set proxyWorkload.image explicitly.

Scaling and Availability

The proxy is stateless, so it scales horizontally. The shipped default runs exactly one replica (minScale: 1, maxScale: 1), which means a restart or redeployment briefly interrupts traffic. Set autoscaling.minScale to 2 or more for an endpoint other systems depend on, and raise autoscaling.maxScale to let it scale out under load.

Troubleshooting

Symptom: You added locations, but requests to / still return the example greeting page.Cause: enableExample is still true, so the example backend keeps the / route.Fix: Set enableExample: false, run a Helm upgrade, then force a redeployment as described in Changing the Routing.
Symptom: Requests to one of your paths return 500 with {"success":false,"message":"Error"}.Cause: The upstream returned a 5xx or could not be reached. The usual reasons are a workload value that does not match the target name exactly, a wrong port, or a target whose internal firewall does not allow RELEASE_NAME-nginx.Fix: Check that the target exists in the same GVC and listens on the configured port, put only the bare workload name in workload, and allow the proxy in the target’s internal firewall. Read the proxy logs to see the upstream error:
Symptom: After an upgrade the proxy restarts repeatedly, while cpln helm upgrade itself reported success.Cause: locations is written into nginx.conf as-is, so a malformed entry is only caught when Nginx starts. Two entries with the same path, or a / entry while enableExample is true, produce a duplicate location that Nginx refuses to load.Fix: Read the startup error in the logs, correct the entry in your values, and upgrade again:
Symptom: The upgrade succeeded, but the proxy still routes the old way.Cause: The running replicas are still using the nginx.conf they started with.Fix: Force a redeployment:

Important Notes

  • Set enableExample: false before routing to your own services; the default sends all / traffic to the example backend.
  • Put only the bare workload name in locations[].workload; the chart appends .GVC_NAME.cpln.local itself.
  • Each target workload’s internal firewall must allow RELEASE_NAME-nginx, or its route returns the JSON error body.
  • The proxy is always open to the internet; there is no value to make it private.
  • Leave proxyWorkload.port at 80; Nginx and its health probes are fixed to that port.
  • After changing routing, force a redeployment so the replicas load the new nginx.conf.
  • The example backend image, gcr.io/knative-samples/helloworld-go, publishes only :latest and cannot be pinned; it does not affect the proxy.

External References

Nginx Documentation

Official Nginx documentation

Nginx Location Directive

How location paths and regex modifiers are matched

Nginx Reverse Proxy Guide

Proxying requests to upstream servers

Nginx Template

View the source files, default values, and chart definition