In Kubernetes, a Service gives pods a stable address inside the cluster. To make web apps reachable from the internet by host name and path, with TLS, you use an Ingress plus an Ingress controller. The most common controller is ingress-nginx, which runs NGINX, and configures it automatically from Ingress resources.
Kubernetes basics: Kubernetes deployments and services and kubectl cheat sheet.
Note: the Kubernetes project announced the retirement of the community ingress-nginx project, and best-effort maintenance ended in March 2026. Existing installations keep working, but receive no further fixes. For new clusters, consider an actively maintained controller (for example Traefik, which k3s ships by default, or a Gateway API implementation). The concepts below apply to Ingress in general.
How it fits together
Internet → (LoadBalancer / node ports 80,443) → ingress-nginx controller → Service → Pods
- Ingress resource: routing rules (host
app.example.com→ servicewebon port 80). - Ingress controller: the proxy that implements the rules.
Install with Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace
kubectl get pods,svc -n ingress-nginx
See Helm tutorial.
On VPS clusters without a cloud load balancer, the controller’s Service of type LoadBalancer stays “Pending”. Options:
- hostNetwork / hostPort mode, so the controller listens directly on ports 80/443 of the node(s):
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx -n ingress-nginx --create-namespace \
--set controller.hostNetwork=true --set controller.kind=DaemonSet --set controller.service.type=ClusterIP
- MetalLB to hand out IPs from your servers’ extra IP addresses;
- k3s ships Traefik as its built-in ingress, so you may not need ingress-nginx at all. See k3s.
Point your DNS A record at the node’s public IP.
Route a host to a service
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
kubectl apply -f ingress.yaml
kubectl get ingress
curl -H "Host: app.example.com" http://<node-ip>/
Several hosts and paths can share one controller, so one entry point serves many apps.
TLS with cert-manager
Add a tls section, and let cert-manager obtain Let’s Encrypt certificates automatically:
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts: [app.example.com]
secretName: app-example-com-tls
Useful annotations (ingress-nginx)
| Annotation | Purpose |
|---|---|
nginx.ingress.kubernetes.io/proxy-body-size |
Upload size limit |
nginx.ingress.kubernetes.io/ssl-redirect |
Force HTTPS (default true with TLS) |
nginx.ingress.kubernetes.io/limit-rps |
Rate limiting per client IP |
nginx.ingress.kubernetes.io/whitelist-source-range |
Allow only certain IP ranges |
nginx.ingress.kubernetes.io/proxy-read-timeout |
Long requests, WebSockets |
Troubleshooting
kubectl describe ingress web
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller
kubectl get endpoints web # does the service have ready pods?
- 404 from nginx: the host or path doesn’t match, or
ingressClassNameis missing. - 503: the service has no ready endpoints. Check pods and readiness probes. See Kubernetes debugging pods.
Ingress vs Gateway API
The newer Gateway API (Gateway, HTTPRoute) is more expressive, and is the long-term direction for Kubernetes traffic routing. Many controllers (Envoy Gateway, Traefik, Cilium, NGINX Gateway Fabric) implement it.
Quick reference
| Task | Command / field |
|---|---|
| Install | helm install ingress-nginx ingress-nginx/ingress-nginx -n ingress-nginx --create-namespace |
| Route | Ingress with host, path, backend.service |
| Class | ingressClassName: nginx |
| TLS | tls: + cert-manager annotation |
| Logs | kubectl logs -n ingress-nginx deploy/ingress-nginx-controller |
Related: Kubernetes vs Docker Compose and Kubernetes security basics.