How do you set up NGINX as a Kubernetes Ingress controller?
Quick Answer
The NGINX Ingress Controller runs as a pod inside your cluster. It watches for Ingress resources and automatically generates NGINX config to route external HTTP/HTTPS traffic to the right services based on hostnames and URL paths.
Detailed Answer
Think of a large office building with one front desk. When a visitor arrives and asks for marketing, the receptionist sends them to floor three. If they ask for engineering, they go to floor five. The NGINX Ingress Controller works the same way for a Kubernetes cluster -- it is the single entry point that reads routing rules and sends traffic to the right internal service based on the hostname or URL path in the request.
The NGINX Ingress Controller is deployed as a Deployment or DaemonSet, usually in its own namespace called ingress-nginx. It runs the NGINX binary inside a container and watches the Kubernetes API for Ingress resources. When you create an Ingress object with rules for host-based or path-based routing, the controller picks up the change and rebuilds the nginx.conf file on the fly, then reloads NGINX without dropping active connections. Each Ingress rule maps a hostname-plus-path combination to a backend Service and port. The controller looks up the Service's endpoints (the actual pod IPs) and creates upstream blocks for them.
Behind the scenes, the controller uses the Kubernetes informer pattern to watch for changes to Ingress, Service, Endpoint, Secret, and ConfigMap resources. When something changes, it runs a sync loop that builds a new NGINX config from a template and compares it to the running one. If they differ, it writes the new config and triggers a reload. Newer versions use NGINX's dynamic module and Lua-based upstream balancing to update endpoints without a full reload, which lowers the risk of dropped connections during deployments. TLS certificates referenced in Ingress resources through secretName are pulled from Kubernetes Secrets and written to disk for NGINX to use.
In production, you expose the Ingress Controller using a Service of type LoadBalancer, which creates a cloud load balancer (like an AWS NLB or GCP LB) that points to the controller pods. Annotations on Ingress resources let you customize behavior per route -- setting timeouts, enabling CORS, adding rate limits, or turning on authentication. A ConfigMap lets you tune global NGINX settings like proxy-body-size, use-gzip, and worker-processes. You should also set up a default backend to show a custom 404 page for requests that don't match any Ingress rule.
A common mistake is creating Ingress resources before deploying the controller, which means nothing processes the rules and traffic just fails silently. Another frequent issue is forgetting to set the correct ingress class (kubernetes.io/ingress.class or the newer ingressClassName field) when you have multiple controllers in the same cluster. Without it, a rule might get picked up by the wrong controller or ignored entirely. Also, changes to TLS Secrets aren't always instant because the sync loop has a small delay, and a misconfigured certificate chain causes silent SSL handshake failures that only show up in the NGINX error logs inside the pod.