Ingress-nginx: [nginx] Redirect with added trailing slash

Created on 25 Apr 2017  路  7Comments  路  Source: kubernetes/ingress-nginx

Nginx by default automatically adds HTTP redirect /foo -> /foo/ when using prefix match with trailing slash location /foo/ which is redirected to a backend (documented in the last paragraph here). This behavior is useful when serving a web application at http://example.com/foo/ and a user accesses http://example.com/foo. Unfortunately, this behavior is broken when using ingress.kubernetes.io/rewrite-target annotation, which turns location match into a non-prefix regex one.
I would argue that the behavior of adding a trailing slash by HTTP redirect on the base path of an web application exposed through an non-root Ingress (with or without a rewrite target) is very useful and should either work by default, or be enabled via some separate annotation.
I was unable to find a workaround in the latest version of Nginx ingress controller. Using /foo ingress path does not work as it breaks relative links inside the web application.
Also, if #619 would be fixed by unconditionally enabling regular expressions, even the currently working cases (without rewrite) will break.

lifecyclrotten

Most helpful comment

Related: https://github.com/kubernetes/contrib/issues/1884

As a workaround ingress.kubernetes.io/configuration-snippet can be used (based on this comment by @hartmut-co-uk):

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: app
  annotations:
    ingress.kubernetes.io/rewrite-target: /
    # adds 301 redirect with trailing slash
    ingress.kubernetes.io/configuration-snippet: |
      rewrite ^(/app)$ $1/ permanent;
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /app
        backend:
          serviceName: app
          servicePort: 80

This works with ingress.kubernetes.io/rewrite-target: / probably by accident, the configuration snippet is being added just before other rewrite rules:

# Parts of generated /etc/nginx/nginx.conf

        location ~* ^/app {
            set $proxy_upstream_name "default-routes-app-80";
            port_in_redirect off;

            # enforce ssl on server side
            if ($pass_access_scheme = http) {
                return 301 https://$host$request_uri;
            }

# ...

            rewrite ^(/app)$ $1/ permanent;
        rewrite /app/(.*) /$1 break;
        rewrite /app / break;
        proxy_pass http://default-routes-app-80;

        }

All 7 comments

Related: https://github.com/kubernetes/contrib/issues/1884

As a workaround ingress.kubernetes.io/configuration-snippet can be used (based on this comment by @hartmut-co-uk):

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: app
  annotations:
    ingress.kubernetes.io/rewrite-target: /
    # adds 301 redirect with trailing slash
    ingress.kubernetes.io/configuration-snippet: |
      rewrite ^(/app)$ $1/ permanent;
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /app
        backend:
          serviceName: app
          servicePort: 80

This works with ingress.kubernetes.io/rewrite-target: / probably by accident, the configuration snippet is being added just before other rewrite rules:

# Parts of generated /etc/nginx/nginx.conf

        location ~* ^/app {
            set $proxy_upstream_name "default-routes-app-80";
            port_in_redirect off;

            # enforce ssl on server side
            if ($pass_access_scheme = http) {
                return 301 https://$host$request_uri;
            }

# ...

            rewrite ^(/app)$ $1/ permanent;
        rewrite /app/(.*) /$1 break;
        rewrite /app / break;
        proxy_pass http://default-routes-app-80;

        }

Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.

Prevent issues from auto-closing with an /lifecycle frozen comment.

If this issue is safe to close now please do so with /close.

Send feedback to sig-testing, kubernetes/test-infra and/or @fejta.
/lifecycle stale

Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten.
Rotten issues close after an additional 30d of inactivity.

If this issue is safe to close now please do so with /close.

Send feedback to sig-testing, kubernetes/test-infra and/or @fejta.
/lifecycle rotten
/remove-lifecycle stale

Rotten issues close after 30d of inactivity.
Reopen the issue with /reopen.
Mark the issue as fresh with /remove-lifecycle rotten.

Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/close

Further to what @rutsky mentioned in his comment if you are using nginx ingress controller specifically and your annotations start with nginx as follows:
metadata: name: ingress-tutorial annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/rewrite-target: "/" nginx.ingress.kubernetes.io/configuration-snippet: | rewrite ^(/app)$ $1/ permanent;

Your annotation should start with nginx. and hence should read as nginx.ingress.kubernetes.io/configuration-snippet as opposed to ingress.kubernetes.io/configuration-snippet

Please keep in mind that while @ProProgrammer 's solution works 301 redirects are PERMANENT.

The unintended byproducts of forcing a trailing slash via 301 can be enough to get you fired.

It's likely safer to start with a 302 temporal redirect if you're just futzing around trying to get something operational.

Per the NGINX docs you can use the redirect param instead of the permanent param to provide a 302 instead of a 301 redirect.

  name: ingress-tutorial
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: "/"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite ^(/app)$ $1/ redirect;

I can't quite get that rewrite rule/block to work. It redirects me to the (internal) load balancer IP.

Is there another config to explicitly set the host? nginx doesn't work if I specify the host (there's an internal load balancer), I think the DNS name is getting dropped from the public load balancer.

Was this page helpful?
0 / 5 - 0 ratings