Reputation: 835
I have a kubernetes setup that looks like this:
nginx ingress -> load balancer -> nginx app
after getting an SSL certificate for www.foo.com, I've installed it in my nginx ingress as a secret, and it works as expected - traffic to www.foo.com
gets redirected to the https
version instead, and browsers display a secure connection indicator. Great.
What hasn't been easy, however, is getting the ingress to redirect non-www traffic to the www version of the site. I've tried using kubernetes.io/from-to-www-redirect: "true"
, but it doesn't seem to do anything - navigating to foo.com
doesn't redirect me to the www version of the url, but either takes me to an insecure version of my site, or navigates me to default backend - 404
depending on whether i include foo.com
as a host with it's own path in my ingress.
I have been able to set up a patchy redirect by adding the following to my actual application's nginx config -
server {
listen 80;
server_name foo.com;
return 301 http://www.foo.com$request_uri;
}
UPDATE: from-to-www-redirect
DOES work; you just have to reference it with nginx.ingress.kubernetes.io
rather than kubernetes.io
as I was. But, this only works for foo.com
- typing in https://foo.com
explicitly causes browsers to display a security warning and no redirect to the proper URL of https://www.foo.com
occurs.
Here's my current config for the nginx ingress itself:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: foo-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: www.foo.com
http:
paths:
- backend:
serviceName: foo-prod-front
servicePort: 80
path: /
tls:
- hosts:
- www.foo.com
secretName: tls-secret
Upvotes: 14
Views: 11031
Reputation: 3779
The solution that worked for me is the one from @demisx but on my first try, the solution was not working for another reason. I had more than one ingress with reference to the "example.com" root host and as described on the documentation this was omitting my www redirect rule.
Documentation refers that "If at some point a new Ingress is created with a host equal to one of the options (like domain.com) the annotation will be omitted."
Ingress 1 - to handle example.com
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: example-frontend
servicePort: 80
path: /
tls:
- hosts:
- example.com
- www.example.com
secretName: tls-secret
Ingress 2 - to handle example.com/news
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-https-ingress-news
spec:
rules:
- host: example.com. # <--------- I HAD ANOTHER REFERENCE
http:
paths:
- backend:
serviceName: example-news
servicePort: 80
path: /news
- host: www.example.com
http:
paths:
- backend:
serviceName: example-news
servicePort: 80
path: /news
tls:
- hosts:
- example.com
- www.example.com
secretName: tls-secret
Make sure that you don't have any other ingress created with the root domain otherwise the redirect will not work as documentation refers. I removed the reference to example.com host on ingress 2 and then immediately started to work.
Ingress 1 - to handle example.com
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: example-frontend
servicePort: 80
path: /
tls:
- hosts:
- example.com
- www.example.com
secretName: tls-secret
Ingress 2 - to handle example.com/news
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-https-ingress-news
spec:
rules:
# <--------- removed the other reference to the root host
- host: www.example.com
http:
paths:
- backend:
serviceName: example-news
servicePort: 80
path: /news
tls:
- hosts:
- example.com
- www.example.com
secretName: tls-secret
Note: By the way, I didn't need to add the forward annotation to the 2nd ingress cause is already handled by the first ingress. I'm not sure though, if the order of deployment matters for nginx ingress controllers so take this as a note only and try to confirm yourself.
Upvotes: 1
Reputation: 7786
I have the following doing the job with the latest nginx-ingress 0.25.1
:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-rule-web
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/from-to-www-redirect: 'true'
spec:
rules:
- host: foo.org
http:
paths:
- path: /
backend:
serviceName: web
servicePort: 80
tls:
- hosts:
- foo.org
- www.foo.org
secretName: letsencrypt-prod
Upvotes: 8
Reputation: 1164
I found the docs to be confusing here as well. Below is an example i have working. I believe you need to define the naked url in tls certs to avoid a cert error(your cert needs to be valid for both foo.com and www.foo.com). You CANNOT list the naked url under rules: hosts because that will get picked up prior to the redirect.
http://foo.com -> https://www.foo.com
https://foo.com -> https://www.foo.com
http://www.foo.com -> https://www.foo.com
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: foo-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: www.foo.com
http:
paths:
- backend:
serviceName: foo-frontend
servicePort: 80
path: /
tls:
- hosts:
- foo.com
- www.foo.com
secretName: tls-secret
Upvotes: 7
Reputation: 930
You need to add the certificate for the domain you want to be redirected:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: foo-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: foo.com
http:
paths:
- backend:
serviceName: foo-prod-front
servicePort: 80
path: /
- host: www.foo.com
http:
paths:
- backend:
serviceName: foo-prod-front
servicePort: 80
path: /
tls:
- hosts:
- foo.com
- www.foo.com
secretName: tls-secret
I am not completely sure, whether from-to-www-redirect
works with this setup, but you can replace it with the following lines, which do work:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($host = 'foo.com' ) {
rewrite ^ https://www.foo.com$request_uri permanent;
}
Upvotes: 16
Reputation: 5903
This is rather a problem with your ssl certificate than the nginx ingress configuration. My guess is that your certificate is only valid for foo.com
and not for www.foo.com
. If you access www.foo.com
your browser shows a security warning because the certificate isn't valid for the domain you are visiting.
Upvotes: 1