Kubernetes Nginx ingress: traffic redirect using annotations demystified

Ionut Craciunescu
Wealth Wizards Engineering
4 min readMay 13, 2020
Follow the signs

Redirect HTTP traffic or rewrite URLs using Kubernetes ingress annotations and Nginx ingress controller. This article explains annotations usage and their effect on the resulting nginx.conf configuration file.

Originally published on Linux Recruit Blog.

1. nginx.ingress.kubernetes.io/rewrite-target

Example 1:

apiVersion: networking.k8s.io/v1beta1 
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /destination$1$2
name: destination-home
namespace: myNamespace
spec:
rules:
- host: nginx.redirect
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /source(/|$)(.*)

This one does a transparent reverse proxy.
It does not update the Location header so the URL in the browser does not change.

Example 2:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: https://nginx.redirect/destination$1$2
name: destination-home
namespace: myNamespace
spec:
rules:
- host: nginx.redirect
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /source(/|$)(.*)

This one changes the Location header and the URL in the browser is updated:

HTTP/1.1 302 Moved Temporarily
curl -I http://nginx.redirect/source
Location: https://nginx.redirect/destination
HTTP/1.1 302 Moved Temporarily
curl -I http://nginx.redirect/source/bar
Location: https://nginx.redirect/destination/bar

This is because the replacement string as specified in rewrite-target
annotation starts with https:// .
From nginx docs:

In addition, a URL for temporary redirect with the code 302 can be specified as  the sole parameter. Such a parameter should start with the “http://”, “https://”,  or “$scheme” string. 
..............
If the specified regular expression matches a request URI, URI is changed as specified in the replacement string. The rewrite directives are executed sequentially in order of their appearance in the configuration file. It is possible to terminate further processing of the directives using flags. If a replacement string starts with “http://”, “https://”, or “$scheme”, the processing stops and the redirect is returned to a client.

Using nginx.ingress.kubernetes.io/permanent-redirect-code: ‘308’annotation has no effect on the code returned as this is controlled by the rewrite rule in nginx.conf . The directive added in nginx.conf is similar to:

rewrite “(?i)/source(/|$)(.*)” https://nginx.redirect/destination$1$2 break;

Syntax: break;
Default: —
Context: server, location, if
Stops processing the current set of ngx_http_rewrite_module directives. If a directive is specified inside the location, further processing of the request continues in this location.

If you need to control the return code using a rewrite rule, then you need to use a return directive after the rewrite directive. More info here: https://www.nginx.com/blog/creating-nginx-rewrite-rules.
I assume this can be used using nginx.ingress.kubernetes.io/configuration-snippet: | (I have not tried it yet).

This one is nice: defines the Application Root that the Controller must redirect if it’s in / context:

$ echo "
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/app-root: /destination
name: approot
namespace: default
spec:
rules:
- host: approot.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
" | kubectl create -f -

In the resulting nginx.conf an if statement will be added to the server context :

if ($uri = /) {
return 302 /destination
}

2. nginx.ingress.kubernetes.io/configuration-snippet: |

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/source(/?)$ https://nginx.redirect/destination$1 permanent;
name: destination-home
namespace: myNamespace
spec:
rules:
- host: nginx.redirect
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /source

This one looks like it gives the greatest control over the redirect/rewrite as it will add the additional configuration snippet to the resulting nginx.conf location.

permanent: returns a permanent redirect with the 301 code.

Additional docs here.

3. nginx.ingress.kubernetes.io/server-snippet: |

Use carefully. While it can be used similar to the one above (only the annotation is slightly different) it will add your custom config to the server block in the resulting nginx.conf , thus taking effect server wide. A redirect/rewrite rule placed in here will be processed before any other statement in a location directive (controlled by a kubernetes ingress resource) so it might lead to undesired behaviour.

Additional docs here.

4. nginx.ingress.kubernetes.io/permanent-redirect

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: https://nginx.redirect/destination
nginx.ingress.kubernetes.io/permanent-redirect-code: '308'
name: destination-home
namespace: myNamespace
spec:
rules:
- host: nginx.redirect
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /source

Pretty self explanatory, works a treat 😄

curl -I  http://nginx.redirect/source
HTTP/1.1 308
Permanent Redirect
Location: https://nginx.redirect/destination
curl -I http://nginx.redirect/source/bar
HTTP/1.1 308
Permanent Redirect
Location: https://nginx.redirect/destination

It adds an if statement in the nginx.conf under /source location as follows:

if ($uri ~* /source) {
return 308 https://nginx.redirect/destination;
}

Additional docs: annotations.md#permanent-redirect and here.

Permanent Redirect

This annotation allows to return a permanent redirect instead of sending data to the upstream. For example nginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com would redirect everything to Google.

Permanent Redirect Code

This annotation allows you to modify the status code used for permanent redirects. For example nginx.ingress.kubernetes.io/permanent-redirect-code: ‘308’ would return your permanent-redirect with a 308.

Temporal Redirect

This annotation allows you to return a temporal redirect (Return Code 302) instead of sending data to the upstream. For example nginx.ingress.kubernetes.io/temporal-redirect: https://www.google.com would redirect everything to Google with a Return Code of 302 (Moved Temporarily)

--

--