QUIC isn’t just HTTP/2 over TLS; it’s a fundamental reimagining of transport protocols that makes HTTP/3 feel like a completely new invention.

Let’s see QUIC in action with an Nginx Ingress controller configured for HTTP/3. Imagine we have a simple Deployment for our web application:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

And a Service to expose it internally:

apiVersion: v1
kind: Service
metadata:
  name: my-web-app-service
spec:
  selector:
    app: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Now, the crucial part is the Ingress resource. For QUIC (HTTP/3), we need to enable UDP support on the Ingress controller and configure Nginx to listen on UDP ports.

Here’s a sample Ingress resource. Notice the annotations and the ingressClassName.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-web-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/enable-quic: "true"
    nginx.ingress.kubernetes.io/quic-listen-ports: "443"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  ingressClassName: nginx-quic # This class name is key
  tls:
  - hosts:
    - example.com
    secretName: my-tls-secret # Ensure you have a TLS secret named 'my-tls-secret'
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-web-app-service
            port:
              number: 80

To make this work, your Nginx Ingress controller itself needs to be deployed with QUIC enabled. This typically involves:

  1. Deploying an Nginx Ingress controller configured for QUIC: You’ll need to build or use a pre-built image of the Nginx Ingress controller that supports QUIC. The standard Nginx Ingress controller deployment often requires modification to listen on UDP. A common way to achieve this is by modifying the args in the controller’s Deployment manifest to include flags that enable UDP listeners. For example, you might see something like:

    args:
      - /nginx-ingress-controller
      - --publish-service=$(POD_NAMESPACE)/$(SERVICE_NAME)
      - --election-id=nginx-ingress-controller
      - --controller-class=k8s.io/ingress-nginx
      # These are crucial for QUIC
      - --default-backend=default-backend/default-backend
      - --configmap=$(POD_NAMESPACE)/nginx-configuration
      - --validating-webhook=:8443
      - --validating-webhook-certificate=/usr/local/certificates/cert
      - --validating-webhook-key=/usr/local/certificates/key
      # Add UDP port configuration here if your controller deployment supports it directly
      # Or ensure your Nginx config will pick it up via annotations
    

    More commonly, the Nginx Ingress controller image is built with Nginx Plus or a custom Nginx build that includes the QUIC module. The nginx.ingress.kubernetes.io/enable-quic: "true" annotation then instructs the controller to generate Nginx configuration that listens on UDP.

  2. Kubernetes Service for the Ingress Controller: The Service resource exposing your Nginx Ingress controller needs to expose both TCP (for HTTP/1.1 and HTTPS) and UDP (for HTTP/3) ports.

    apiVersion: v1
    kind: Service
    metadata:
      name: ingress-nginx-controller
      namespace: ingress-nginx # Or wherever your controller is deployed
    spec:
      type: LoadBalancer
      selector:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/instance: ingress-nginx
      ports:
        - name: http
          protocol: TCP
          port: 80
          targetPort: 80
        - name: https
          protocol: TCP
          port: 443
          targetPort: 443
        - name: quic # This port is for UDP
          protocol: UDP
          port: 443
          targetPort: 443
    

    This Service will get a LoadBalancer IP, and clients will connect to this IP. The LoadBalancer will forward TCP traffic to the controller’s TCP ports and UDP traffic to the controller’s UDP port.

  3. TLS Certificates: QUIC, like HTTP/2 and HTTP/1.1 over TLS, requires TLS certificates for encryption. The tls section in your Ingress resource specifies the Kubernetes Secret containing your TLS certificate and private key. Ensure my-tls-secret exists and is correctly configured.

The mental model here is that the Ingress resource, when annotated for QUIC, tells the Nginx Ingress controller to modify its internal Nginx configuration. It adds listen directives for UDP ports (specified by quic-listen-ports) and configures Nginx to handle HTTP/3 requests on those ports. The controller’s Service then exposes these UDP ports via a LoadBalancer.

When a client attempts to connect to example.com via HTTP/3, it will perform a QUIC handshake. This handshake happens over UDP. If successful, the client and server establish a QUIC connection, and HTTP/3 frames are exchanged within this connection. The Nginx Ingress controller, listening on the UDP port, processes these frames, routes them to your my-web-app-service over standard TCP, and sends responses back.

The ability to establish connections over UDP, combined with advanced features like connection migration and multiplexing, is what makes QUIC so powerful. It bypasses the limitations of TCP’s Head-of-Line Blocking (HOLB) at the transport layer, meaning packet loss on one stream doesn’t stall other streams within the same connection. This is a significant departure from how TCP operates, where HOLB is a persistent challenge for HTTP/2.

Most people understand QUIC as "HTTP/3," but the real magic is in the underlying QUIC transport protocol. It uses UDP for its transport, allowing for a much more flexible and resilient connection establishment and data transfer mechanism. This includes features like 0-RTT connection establishment (after the initial handshake) and connection migration, where a client’s IP address or port can change without dropping the connection.

The next hurdle you’ll likely face is tuning Nginx’s QUIC-specific parameters for performance and understanding how load balancers upstream of your Kubernetes cluster handle UDP traffic.

Want structured learning?

Take the full Quic course →