Kubernetes Services of type ClusterIP expose applications only within the cluster — external traffic cannot reach them directly. An Ingress resource solves this by providing HTTP/HTTPS routing from outside the cluster to internal services based on hostnames and URL paths. The Nginx Ingress Controller is the most widely deployed ingress controller, running as a pod inside the cluster that watches for Ingress resource changes and dynamically updates Nginx configuration to route traffic accordingly. It supports SSL termination (handling TLS at the ingress layer so backend services receive plain HTTP), path-based routing (different paths to different services), virtual hosting (different hostnames to different services), and rate limiting. This guide covers installing the Nginx Ingress Controller on RHEL 9 and configuring Ingress rules for TLS termination and path-based routing.

Prerequisites

  • Kubernetes cluster running on RHEL 9
  • Helm installed

Step 1 — Install Nginx Ingress Controller

# Install via Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm install nginx-ingress ingress-nginx/ingress-nginx 
    --namespace ingress-nginx 
    --create-namespace 
    --set controller.service.type=NodePort 
    --set controller.service.nodePorts.http=30080 
    --set controller.service.nodePorts.https=30443

# Verify the ingress controller is running
kubectl get pods -n ingress-nginx
kubectl get service -n ingress-nginx

Step 2 — Create a TLS Secret

# Generate a self-signed certificate for testing
openssl req -x509 -nodes -days 365 -newkey rsa:2048 
    -keyout /tmp/tls.key 
    -out /tmp/tls.crt 
    -subj "/CN=myapp.example.com"

# Create a Kubernetes TLS Secret
kubectl create secret tls myapp-tls 
    --cert=/tmp/tls.crt 
    --key=/tmp/tls.key 
    --namespace myapp

Step 3 — Create Ingress Resources

# /tmp/myapp-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: myapp
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com
    secretName: myapp-tls
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80
kubectl apply -f /tmp/myapp-ingress.yaml
kubectl get ingress -n myapp
kubectl describe ingress myapp-ingress -n myapp

Step 4 — Rate Limiting and Auth Annotations

# Add rate limiting and auth to an Ingress via annotations:
annotations:
  # Rate limit: 100 requests per minute per IP
  nginx.ingress.kubernetes.io/limit-rps: "100"
  # Basic authentication (using a htpasswd secret)
  nginx.ingress.kubernetes.io/auth-type: basic
  nginx.ingress.kubernetes.io/auth-secret: basic-auth
  nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"

Conclusion

The Nginx Ingress Controller on RHEL 9 provides a production-ready HTTP/HTTPS gateway for Kubernetes workloads with TLS termination, path routing, virtual hosting, and rate limiting through annotation-based configuration. For bare-metal deployments, using NodePort service type (as configured above) exposes the ingress on specific node ports — for a more production-like external IP, install MetalLB (a load balancer for bare-metal Kubernetes) alongside the ingress controller to assign external IPs from your network range via LoadBalancer type services.

Next steps: How to Deploy Applications to Kubernetes on RHEL 9, How to Configure Kubernetes RBAC on RHEL 9, and How to Install ArgoCD on RHEL 9.