When working with Nginx Ingress in Kubernetes, domain redirects are a common requirement. In your case, you want to redirect traffic from app.example.org to your primary domain example.org. Let's explore the most effective solutions.
Your existing Ingress configuration handles two hosts with the same backend service:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- example.org
- app.example.org
secretName: prod-tls
rules:
- host: example.org
http:
paths:
- path: /
backend:
serviceName: app-service
servicePort: 80
- host: app.example.org
http:
paths:
- path: /
backend:
serviceName: app-service
servicePort: 80
The most straightforward approach is using Nginx Ingress annotations to configure the redirect:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-redirect
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/permanent-redirect: https://example.org
nginx.ingress.kubernetes.io/permanent-redirect-code: "308"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- app.example.org
secretName: prod-tls
rules:
- host: app.example.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: dummy-service
port:
number: 80
For more control, you can use a configuration snippet:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-snippet
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($host = 'app.example.org') {
return 308 https://example.org$request_uri;
}
spec:
tls:
- hosts:
- example.org
- app.example.org
secretName: prod-tls
rules:
- host: example.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
- host: app.example.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
- Use 308 (Permanent Redirect) instead of 301 if you want to preserve the HTTP method
- Ensure your TLS configuration covers both domains
- The dummy service in the first solution can be any existing service, as it won't actually receive traffic
- Test redirects thoroughly as they can affect SEO and user experience
After applying the configuration, test it with curl:
curl -I http://app.example.org
curl -I https://app.example.org
You should see responses containing 308 Permanent Redirect and the Location: https://example.org header.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/permanent-redirect: "https://example.org$request_uri"
nginx.ingress.kubernetes.io/permanent-redirect-code: "308"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- app.example.org
secretName: prod-tls
rules:
- host: app.example.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: dummy-service
port:
number: 80
To properly redirect traffic from app.example.org to example.org, we need to create a separate Ingress resource dedicated to handling the redirect. The key annotations are:
nginx.ingress.kubernetes.io/permanent-redirect: "https://example.org$request_uri"
nginx.ingress.kubernetes.io/permanent-redirect-code: "308"
Here's a complete implementation example with dummy backend service:
apiVersion: v1
kind: Service
metadata:
name: dummy-service
spec:
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dummy-deployment
spec:
replicas: 1
selector:
matchLabels:
app: dummy
template:
metadata:
labels:
app: dummy
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
For more complex redirect scenarios, you can use configuration-snippet:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: snippet-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($host = 'app.example.org') {
return 308 https://example.org$request_uri;
}
spec:
rules:
- host: app.example.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
Make sure your TLS configuration includes both domains if you're using HTTPS redirects:
tls:
- hosts:
- example.org
- app.example.org
secretName: prod-tls
After applying the configuration, verify the redirect works:
curl -v -k https://app.example.org
# Should return 308 status code with Location: https://example.org/
If the redirect isn't working:
- Check ingress controller logs for errors
- Verify the annotation syntax is correct
- Ensure both hostnames resolve properly
- Check for conflicting Ingress resources