Kubernetes Nginx Ingress HTTP to HTTPS redirect via 301 instead of 308?

10/2/2018

We are running a couple of k8s clusters on Azure AKS. The service (ghost blog) is behind the Nginx ingress and secured with a cert from Letsencrypt. All of that works fine but the redirect behavior is what I am having trouble with.

The Ingress correctly re-directs from http://whatever.com to https://whatever.com — the issue is that it does so using a 308 redirect which strips all post/page Meta anytime a user shares a page from the site.

The issue results in users who share any page of the site on most social properties receiving a 'Preview Link' — where the title of the page and the page meta preview do not work and are instead replaced with '308 Permanent Redirect' text — which looks like this:

enter image description here

From the ingress-nginx docs over here I can see that this is the intended behavior (ie. 308 redirect) what I believe is not intended is the interaction with social sharing services when those services attempt to create a page preview.

While the issue would be solved by Facebook (or twitter, etc etc) pointing direct to the https site by default, I currently have no way to force those sites to look to https for the content that will be used to create the previews.

Setting Permanent Re-Direct Code

I can also see that it looks like I should be able to set the redirect code to whatever I want it to be (I believe a 301 redirect will allow Facebook et al. to correctly pull post/page snippet meta), docs on that found here.

The problem is that when I add the redirect-code annotation as specified:

nginx.ingress.kubernetes.io/permanent-redirect-code: "301"

I still get a 308 re-direct on my resources despite being able to see (from my kubectl proxy) that the redirect-code annotation correctly applied. For reference, my full list of annotations on my Ingress looks like this:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ghost-ingress
  annotations:
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/permanent-redirect-code: "301"

To reiterate — my question is; what is the correct way to force a redirect to https via a custom error code (in my case 301)?

-- Necevil
kubernetes
kubernetes-ingress
nginx-ingress

2 Answers

10/3/2018

These directions are for Azure AKS users but the solution for this solution for facebook / social property preview links showing as 308 permanent redirect will probably work on any cloud provider (though it has not been tested) — you would just need to change the way you login / get your credentials etc.

Thanks to Rico for the solution! Since this is only tested with Facebook you may or may not want to go the ConfigMap application route (which Rico mentions above) this walks through manually editing the ConfigMap as opposed to using kubectl apply -f to apply one saved locally.

  1. Pickup AZ Credentials for your cluser (az login)
  2. Assume the role for your cluster: az aks get-credentials --resource-group yourGroup --name your-cluster
  3. Browse your Cluster: az aks browse --resource-group yourGroup --name your-cluster
  4. Navigate to the namespace containing your Ingress nGinx containers (not the backend services — although they could be in the same NS).
  5. On the left hand side navigation menu (just above settings) find the 'ConfigMaps' tab and click it.
  6. Edit the 'Data' element of the YAML and add the following line (note the quotes around both the name and number in the key/value): "data": { "some-other-setting-here": "false", "http-redirect-code": "301" } You will need a comma after each key/value line except the last.
  7. Restart your nginx-controller POD by deleting it make SURE you don't delete the deployment like I did.
  8. If you want to be productive you can upgrade your nginx install (from helm) which will restart / re-create the container in the process by using: helm upgrade ngx-ingress stable/nginx-ingress Where ngx-ingress is the name of your helm install. Also note that using the '--reuse-values' flag will cause your upgrade to fail (re: https://github.com/helm/helm/issues/4337)
  9. If you don't know the name you used for nginx when you installed it from Helm originally you can use helm list to find it.
  10. Finally to test and make sure your Re-Directs are using the correct ConfigMap code, curl your http site with: curl myhttpdomain.com You should receive something like this:

```

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.15.3</center>
</body>
</html>

```

One important thing to note here is that if you are making the change to a 301 re-direct to try to fix the preview link for facebook or one of the other social media properties (twitter etc etc) then in all likelihood this will not fix any link to any page / post that you have already linked to — at least not right away.

The social properties all use intense caching to limit their resource usage but you can check to see if the above fixes your preview link issue by linking to a NEW page / post that you have not previously referenced.

Be Aware of Implications for 'POST'

So the major reason that nginx-ingress uses a code 308 is because it keeps the 'body' / payload intact in cases where you are sending a POST request (as opposed to a normal GET request link you do with a browser etc).

For me this wasn't a concern but if you are for whatever reason posting to the http address and expecting that to be re-directed seamlessly that will probably not work — after you swap to the 301 redirect discussed in post that is.

HOWEVER if you are not expecting a seamless redirect when sending POST requests (I think most people probably are not, I know I am not) then I think this is the best way to fix the Facebook 308 Permanent redirect behavior.

-- Necevil
Source: StackOverflow

10/2/2018

My guess is the TLS redirect shadows the nginx.ingress.kubernetes.io/permanent-redirect-code annotation.

You can actually change the ConfigMap for your nginx-configuration so that the default redirect is 301. That's the configuration your nginx ingress controller uses for nginx itself. The ConfigMap looks like this:

apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  name: nginx-configuration
  namespace: ingress-nginx
data:
  use-proxy-protocol: "true"
  http-redirect-code: "301"

You can find more about the ConfigMap options here. Note that if you change the ConfigMap you'll have to restart your nginx-ingress-controller pod.

You can also shell into the nginx-ingress-controller pod and see the actual nginx configs that the controller creates:

kubectl -n ingress-nginx exec -it nginx-ingress-controller-xxxxxxxxxx-xxxxx bash
www-data@nginx-ingress-controller-xxxxxxxxx-xxxxx:/etc/nginx$ cat /etc/nginx/nginx.conf
-- Rico
Source: StackOverflow