X
Popular Searches

How to Redirect to “www” with Nginx Ingress

Graphic showing the Kubernetes logo

You’ll often want to deploy a web application to the root of your domain, as well as the “www” subdomain. This helps users discover your service. Nginx Ingress has built-in support for the procedure.

Here’s how to deploy a workload with two ingress hosts, “www” and your bare domain. Anyone visiting “www” will proceed as normal. Visitors to the domain root will be redirected to the “www” subdomain. By using a redirect, you reduce the risk that both endpoints could show in search results.

Using the Annotation

Nginx Ingress provides a Kubernetes annotation that lets you configure this behaviour. Adding the annotation to your Ingress resource enables the redirect infrastructure. You don’t need to manually write the rewrite logic into your Nginx configuration.

nginx.ingress.kubernetes.io/from-to-www-redirect: "true"

Set this annotation in the metadata.annotations field of your Ingress’ resource definition. A complete working example is provided in the next section.

Setting up Your Hosts

You should add your Ingress host configuration in the usual way. You only need one host line. Use the “www” domain here – Nginx Ingress will automatically handle the redirect from the bare domain. If you prefer, you can write the bare domain instead. Nginx Ingress will then redirect to it, from www.

Advertisement

Add the rest of the ingress configuration below the host line. You’ll need to indicate the HTTP path to serve (usually /) and the service to route traffic to.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  namespace: my-namespace
  annotations:
    kubernetes.io/ingress.class: nginx-ingress
    nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
  rules:
    - host: www.example.com
      http:
        paths:
        - path: /
          backend:
            serviceName: my-service
            servicePort: 80

This minimal working example should allow you to see the redirect in action. Visiting the bare domain will immediately take you to “www” instead. You can be sure users interact with your site via a single entrypoint, even though there’s two possible ingress hosts.

Adding HTTPS Support

The manifest shown above lacks support for HTTPS. In a real scenario, you’ll almost certainly want to ensure all your ingress hosts are covered by a TLS certificate.

Getting HTTPS working with this configuration requires you to add both your hosts to a single TLS certificate. Here’s an updated manifest with TLS support:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  namespace: my-namespace
  annotations:
    kubernetes.io/ingress.class: nginx-ingress
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
  rules:
    - host: www.example.com
      http:
        paths:
        - path: /
          backend:
            serviceName: my-service
            servicePort: 80
  tls:
    - hosts:
        - example.com
        - www.example.com
      secretName: ingress-tls-secret

With only five more lines of YAML, you should now have working HTTPS on both the possible ingress hosts. This assumes you’re got an active certificate issuer in your cluster – we’re using letsencrypt-prod, provided by cert-manager. You should follow the documentation to install cert-manager if there’s no certificate controller available.

You can also choose an alternative certificate controller. You’d need to update the cluster-issuer ingress annotation with the name of an issuer provided by your controller. You won’t need to change the tls section of the manifest – this will work with all Kubernetes certificate controllers.

Making the Domain a Variable

We can convert the manifest into a Helm chart to avoid having to repeat the domain name. In this example, we’ll assume your domain name is set as ingressDomain in your Helm chart’s values.yaml.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  namespace: my-namespace
  annotations:
    kubernetes.io/ingress.class: nginx-ingress
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
  rules:
    - host: {{ print "www." .Values.ingressDomain }}
      http:
        paths:
        - path: /
          backend:
            serviceName: my-service
            servicePort: 80
  tls:
    - hosts:
        - {{ print .Values.ingressDomain }}
        - {{ print "www" .Values.ingressDomain }}
      secretName: ingress-tls-secret
Advertisement

If you ever need to change your domain name, you’ll now only have to update the value in one place. This also permits use of the manifest within CI environments. Your CI server might use your chart to spin up a new staging environment for each branch, creating a dynamic domain (e.g. my-branch.example.com) to set as ingressDomain.

Handling Development Environments

We’ve now got a functioning www-redirect working! You can stop here and deploy to production if you want, as the main goal of this tutorial has been achieved.

That said, there are some issues with the approach we’ve shown, particularly when working within CI development environments. Currently, each environment would have www prepended to its original domain.

A way to resolve this is to replace ingressDomain with two independent variables:

  • ingressBase – your base domain, e.g. example.com
  • ingressDomain – the currently used domain, for this deployment, e.g. my-branch.example.com

You can then use Helm variable comparisons to only enable the www-redirect when you’re in a production environment.

spec:
  rules:
    {{ if eq .Values.ingressDomain .Values.ingressBase }}
    - host: {{ print "www." .Values.ingressDomain }}
    {{ else }}
    - host: {{ print .Values.ingressDomain }}
    {{ end }}
      http:
        paths:
          - path: /
            backend:
              serviceName: my-service
              servicePort: 80
  tls:
    - hosts:
      - {{ .Values.ingressDomain }}
      {{ if eq .Values.ingressDomain .Values.ingressBase }}
      - {{ print "www." .Values.ingressDomain }}
      {{ end }}
      secretName: {{ .Values.ingressTlsSecret }}
Advertisement

When deploying to production, set ingressDomain to the base domain – it should have the same value as ingressBase. The if condition will get matched, so the www ingress will be created.

When you’re deploying to a subdomain environment, the differing values of ingressDomain and ingressBase will disable the www-redirect.

Conclusion

Redirecting from a bare domain to the “www” subdomain is a fundamental expectation of many public-facing websites. Using Nginx Ingress, you could apply this traditional behaviour to your containerised workloads deployed in the cloud.

Add the annotation to your ingress resource and make sure both hosts are listed in its spec. Finish off by checking that the pair are also listed in any TLS certificates. Users should never talk to an unsecured endpoint, even if they’re going to be redirected away from it.

James Walker James Walker
James Walker is a contributor to CloudSavvy IT. He is the founder of Heron Web, a UK-based digital agency providing bespoke software development services to SMEs. He has experience managing complete end-to-end web development workflows, using technologies including Linux, GitLab, Docker, and Kubernetes. Read Full Bio »

The above article may contain affiliate links, which help support CloudSavvy IT.