Sudarshan Murthy
Sudarshan Murthy

Reputation: 379

How to redirect URL based on http header in nginx ingress?

My requests are being proxied through Cloudflare which sets a header indicating the country in a http header based on the IP address. I want to redirect the requests with certain paths based on this header in Nginx ingress controller. How do I do this?

Upvotes: 1

Views: 9618

Answers (1)

Dawid Kruk
Dawid Kruk

Reputation: 9877

Currently Ingress resource definition for nginx-ingress does not support header based routing.

I found a workaround to route a request by it's header (I've included the steps below) with following annotation:

    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }

Other possible solutions/workarounds:


As for a workaround:

Assuming that (for example purposes):

  • There are 2 Deployments: hello,goodbye
  • Both are associated with their services with names: hello-service, goodbye-service

The Ingress resource will be configured in a way that hello should always answer, but with the addition of configuration-snippet the traffic will be redirected to goodbye.

Responses of this deployments:

|     hello      |    goodbye     |
|----------------|----------------|
| Hello, world!  | Hello, world!  |
| Version: 2.0.0 | Version: 1.0.0 | # notice the version

Example of hello deployment with a service attached to it:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 1
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50001"
---
apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  selector:
    app: hello
  ports:
    - name: hello-port
      port: 5678 # IMPORTANT
      targetPort: 50001
  type: NodePort

To get the goodbye deployment please substitute the hello for goodbye and change the image version to 1.0.

Ingress definition to reroute the request by a header looks like this:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-ingress 
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }
spec:
  rules:
  - host: 
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-service 
          servicePort: hello-port

By default this Ingress definition without the configuration-snippet would always route the traffic to hello-service and then to hello pods. By adding the:

    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }

it will check if the header named LocationHeader is present and if it matches PL. If it does it will send the request to goodbye-service by it's DNS name.

Focusing on:

  • http://goodbye-service.default.svc.cluster.local:5678
  • http://service_name.namespace.svc.cluster.local:port (dns name without values)

After applying this Ingress resource you should be able to send a request with LocationHeader=PL (with Postman for example) and get the response:

Hello, world!
Version: 1.0.0
Hostname: goodbye-5758448754-wr64c

When I tried to use map directive I was getting following messages:

  • nginx: [emerg] "map" directive is not allowed here in /tmp/nginx-OMMITED

Upvotes: 17

Related Questions