Kubernetes Nginx ingress: traffic redirect using annotations demystified
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/destinationHTTP/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, ifStops 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/destinationcurl -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)