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