NGINX Ingress Controller - Solutions
Question 1: Simple Host-Based Routing with NGINX Ingress
Solution
# Create Ingress resource
kubectl create ingress host-based-ingress \
--namespace=nginx-practice-apps \
--class=nginx \
--rule="app.example.com/=frontend-service:8080" \
--rule="api.example.com/=backend-service:3000"
# Add DNS records to /etc/hosts
echo "127.0.0.1 app.example.com api.example.com" | sudo tee -a /etc/hosts
# Port-forward NGINX Controller (run in separate terminal)
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80
# Verify
kubectl get ingress host-based-ingress -n nginx-practice-apps
kubectl describe ingress host-based-ingress -n nginx-practice-apps
# Test with curl
curl -H "Host: app.example.com" http://localhost/
curl -H "Host: api.example.com" http://localhost/
curl -H "Host: api.example.com" http://localhost/stats
# Or test with browser (after adding /etc/hosts entries)
# http://app.example.com
# http://api.example.comYAML Manifest (Alternative)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: host-based-ingress
namespace: nginx-practice-apps
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 8080
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 3000Cleanup
kubectl delete ingress host-based-ingress -n nginx-practice-apps
sudo sed -i '/app\.example\.com\|api\.example\.com/d' /etc/hostsQuestion 2: Path Rewriting with NGINX Annotations
Solution
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-rewrite-ingress
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx
rules:
- host: services.company.com
http:
paths:
- path: /shop/(products.*)
pathType: ImplementationSpecific
backend:
service:
name: product-service
port:
number: 8080
- path: /shop/(cart.*)
pathType: ImplementationSpecific
backend:
service:
name: cart-service
port:
number: 9090
- path: /auth/(login.*)
pathType: ImplementationSpecific
backend:
service:
name: auth-service
port:
number: 7070Commands
# Apply the manifest
kubectl apply -f path-rewrite-ingress.yaml
# Add DNS record
echo "127.0.0.1 services.company.com" | sudo tee -a /etc/hosts
# Port-forward (separate terminal)
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80
# Test path rewriting
curl -H "Host: services.company.com" http://localhost/shop/products
curl -H "Host: services.company.com" http://localhost/shop/cart
curl -H "Host: services.company.com" http://localhost/auth/login
# Test with sub-paths
curl -H "Host: services.company.com" http://localhost/shop/products/1
curl -H "Host: services.company.com" http://localhost/shop/cart/checkoutExplanation
Pattern Breakdown
The regex /shop/(products.*) has ONE capture group:
- $1 =
products.*(captures everything:products,products/1,products/anything) - $2 = does NOT exist
Rewrite Target: /$1
Uses the first (and only) capture group:
/shop/products→ $1 =products→ rewrites to/products/shop/products/1→ $1 =products/1→ rewrites to/products/1/shop/cart/checkout→ $1 =cart/checkout→ rewrites to/cart/checkout
Actual Results (Tested)
curl -H "Host: service.company.com" http://localhost/shop/products
# Backend receives: /products ✓
curl -H "Host: service.company.com" http://localhost/shop/products/1
# Backend receives: /products/1 ✓
curl -H "Host: service.company.com" http://localhost/shop/cart/checkout
# Backend receives: /cart/checkout ✓
curl -H "Host: service.company.com" http://localhost/auth/login
# Backend receives: /login ✓Common Mistake
Using rewrite-target: /$2 with pattern /shop/(products.*) is WRONG because:
- Only ONE capture group exists ($1), so $2 is empty
- Results in backend receiving
/for all paths - Both
/shop/productsand/shop/products/1would return the same response (root endpoint)
Cleanup
kubectl delete ingress path-rewrite-ingress -n nginx-practice-apps
sudo sed -i '/services\.company\.com/d' /etc/hostsQuestion 3: HTTP Redirects - Permanent & Temporary
Solution
# ============================================
# Part 1: Permanent Redirects (301) - Service Migration
# ============================================
# 301: /users → external API
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-301-users
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: https://newapi.company.com/users
spec:
ingressClassName: nginx
rules:
- host: company.example.com
http:
paths:
- path: /users
pathType: Exact
backend:
service:
name: frontend-service # Won't reach - redirect intercepts
port:
number: 8080
---
# 301: /admin → internal path
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-301-admin
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: https://company.example.com/dashboard/admin
spec:
ingressClassName: nginx
rules:
- host: company.example.com
http:
paths:
- path: /admin
pathType: Exact
backend:
service:
name: frontend-service # Won't reach
port:
number: 8080
---
# 301: /old/products → catalog
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-301-products
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: https://company.example.com/catalog
spec:
ingressClassName: nginx
rules:
- host: company.example.com
http:
paths:
- path: /old/products
pathType: Exact
backend:
service:
name: frontend-service # Won't reach
port:
number: 8080
---
# ============================================
# Part 2: Temporary Redirects (302) - Maintenance/Testing
# ============================================
# 302: /maintenance → external status page
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-302-maintenance
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/temporal-redirect: https://status.company.com
spec:
ingressClassName: nginx
rules:
- host: company.example.com
http:
paths:
- path: /maintenance
pathType: Exact
backend:
service:
name: frontend-service # Won't reach
port:
number: 8080
---
# 302: /beta → internal experimental features
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-302-beta
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/temporal-redirect: https://company.example.com/experimental/features
spec:
ingressClassName: nginx
rules:
- host: company.example.com
http:
paths:
- path: /beta
pathType: Exact
backend:
service:
name: frontend-service # Won't reach
port:
number: 8080
---
# 302: /temp/checkout → cart process
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-302-checkout
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/temporal-redirect: https://company.example.com/cart/process
spec:
ingressClassName: nginx
rules:
- host: company.example.com
http:
paths:
- path: /temp/checkout
pathType: Exact
backend:
service:
name: frontend-service # Won't reach
port:
number: 8080
---
# ============================================
# Part 3: Actual Service Routes (Post-Redirect Destinations)
# ============================================
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: service-routes
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx
rules:
- host: company.example.com
http:
paths:
# Admin dashboard (destination for /admin redirect)
- path: /dashboard/(admin.*)
pathType: ImplementationSpecific
backend:
service:
name: admin-service
port:
number: 9000
# API users endpoint
- path: /api/(users.*)
pathType: ImplementationSpecific
backend:
service:
name: user-service
port:
number: 4000
# Catalog (destination for /old/products redirect)
- path: /catalog(.*)
pathType: ImplementationSpecific
backend:
service:
name: product-service
port:
number: 8080
# Experimental features (destination for /beta redirect)
- path: /experimental/(features.*)
pathType: ImplementationSpecific
backend:
service:
name: frontend-service
port:
number: 8080
# Cart process (destination for /temp/checkout redirect)
- path: /cart/(process.*)
pathType: ImplementationSpecific
backend:
service:
name: cart-service
port:
number: 9090
# Default route
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 8080Commands
# Apply all manifests
kubectl apply -f solution3.yaml
# Add DNS record
add_dns "127.0.0.1" "company.example.com"
# Port-forward
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 8089:80
# ============================================
# Test 301 Permanent Redirects
# ============================================
curl -I -H "Host: company.example.com" http://localhost:8089/users
# Expected: HTTP/1.1 301 Moved Permanently
# Location: https://newapi.company.com/users
curl -I -H "Host: company.example.com" http://localhost:8089/admin
# Expected: HTTP/1.1 301 Moved Permanently
# Location: https://company.example.com/dashboard/admin
curl -I -H "Host: company.example.com" http://localhost:8089/old/products
# Expected: HTTP/1.1 301 Moved Permanently
# Location: https://company.example.com/catalog
# ============================================
# Test 302 Temporary Redirects
# ============================================
curl -I -H "Host: company.example.com" http://localhost:8089/maintenance
# Expected: HTTP/1.1 302 Found
# Location: https://status.company.com
curl -I -H "Host: company.example.com" http://localhost:8089/beta
# Expected: HTTP/1.1 302 Found
# Location: https://company.example.com/experimental/features
curl -I -H "Host: company.example.com" http://localhost:8089/temp/checkout
# Expected: HTTP/1.1 302 Found
# Location: https://company.example.com/cart/process
# ============================================
# Test Actual Service Routes (Post-Redirect Destinations)
# ============================================
curl -H "Host: company.example.com" http://localhost:8089/dashboard/admin
# Expected: Admin panel HTML/JSON from admin-service
curl -H "Host: company.example.com" http://localhost:8089/api/users
# Expected: User data from user-service
curl -H "Host: company.example.com" http://localhost:8089/catalog
# Expected: Product catalog from product-service
curl -H "Host: company.example.com" http://localhost:8089/experimental/features
# Expected: Beta features from frontend-service
curl -H "Host: company.example.com" http://localhost:8089/cart/process
# Expected: Checkout flow from cart-service
curl -H "Host: company.example.com" http://localhost:8089/
# Expected: Frontend service homepageExplanation
HTTP Redirect Types
301 Moved Permanently:
- Used for permanent service migrations
- Search engines update their indexes
- Browsers cache the redirect
- Annotation:
nginx.ingress.kubernetes.io/permanent-redirect: <URL>
302 Found (Temporary):
- Used for maintenance mode, A/B testing, temporary changes
- Search engines don't update indexes
- Browsers don't cache the redirect
- Annotation:
nginx.ingress.kubernetes.io/temporal-redirect: <URL>
PathType Behavior with Redirects
Redirect annotations work with all pathType values but behave differently:
pathType: Exact (Used in this solution)
- Only exact path matches trigger redirect
- Example:
/userswith Exact → only/usersredirects,/users/123does NOT redirect
metadata:
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: https://newapi.company.com/users
spec:
rules:
- host: company.example.com
http:
paths:
- path: /users
pathType: Exact # Only /users redirectspathType: Prefix (Redirects all sub-paths)
- Path and all sub-paths trigger redirect
- Example:
/userswith Prefix →/users,/users/123,/users/profile/settingsall redirect
metadata:
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: https://newapi.company.com
spec:
rules:
- host: company.example.com
http:
paths:
- path: /users
pathType: Prefix # /users/* all redirect to same URLImportant: With Prefix pathType, ALL matching paths redirect to the SAME URL (the annotation URL). You cannot preserve the sub-path in the redirect automatically with this annotation alone.
To preserve paths dynamically, use configuration-snippet:
# Dynamic redirect preserving full request path
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redirect-preserve-path
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
return 301 https://newapi.company.com$request_uri;
spec:
ingressClassName: nginx
rules:
- host: company.example.com
http:
paths:
- path: /users
pathType: Prefix
backend:
service:
name: frontend-service # Won't reach
port:
number: 8080Result:
/users→https://newapi.company.com/users/users/123→https://newapi.company.com/users/123/users/profile/settings→https://newapi.company.com/users/profile/settings
Available NGINX variables for dynamic redirects:
$request_uri- Full original request URI with query string (/users/123?id=5)$uri- Normalized URI without query string (/users/123)$host- Hostname from request (company.example.com)$scheme- Request scheme (httporhttps)$args- Query string arguments (id=5&name=test)
Example: Redirect with path manipulation:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
# Remove /old prefix and redirect to new domain
rewrite ^/old/(.*)$ https://newapi.company.com/$1 permanent;Result:
/old/users/123→https://newapi.company.com/users/123/old/products→https://newapi.company.com/products
Redirect Strategy
Separate Ingress Resources:
- Each redirect gets its own Ingress resource for clarity
- Easier to manage, enable/disable individual redirects
- Avoids complex annotation conflicts
Path Precedence:
- Exact paths (redirects) are evaluated before Prefix paths
- Most specific patterns match first
- Service routes handle post-redirect destinations
Redirect Flow Examples:
- External Migration:
/users→ 301 →https://newapi.company.com/users(external service) - Internal Restructure:
/admin→ 301 →/dashboard/admin(same domain, new path) - Temporary Maintenance:
/beta→ 302 →/experimental/features(can revert later)
Path Rewriting for Active Routes
After redirects, actual service routes use path rewriting:
/dashboard/(admin.*)→ $1 =admin→ backend receives/admin/catalog(.*)→ $1 = empty or/subcategory→ backend receives/or/subcategory/cart/(process.*)→ $1 =process.*→ backend receives/process
Cleanup
kubectl delete ingress redirect-301-users redirect-301-admin redirect-301-products \\
redirect-302-maintenance redirect-302-beta redirect-302-checkout service-routes \\
-n nginx-practice-apps
remove_dns "company.example.com"remove_dns "company.example.com"
---
## Question 4: TLS Configuration with NGINX Ingress
### Solution
```bash
# Step 1: Generate self-signed TLS certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key \
-out tls.crt \
-subj "/CN=*.company.com/O=company" \
-addext "subjectAltName=DNS:*.company.com,DNS:app.company.com,DNS:api.company.com"
# Step 2: Create Kubernetes TLS secret
kubectl create secret tls wildcard-tls \
--cert=tls.crt \
--key=tls.key \
-n nginx-practice-apps
# Step 3: Verify secret
kubectl get secret wildcard-tls -n nginx-practice-apps
kubectl describe secret wildcard-tls -n nginx-practice-appsIngress Manifest
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3"
nginx.ingress.kubernetes.io/ssl-ciphers: "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.company.com
- api.company.com
secretName: wildcard-tls
rules:
- host: app.company.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 8080
- host: api.company.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 3000Testing Commands
# Apply the Ingress
kubectl apply -f tls-ingress.yaml
# Add DNS records
echo "127.0.0.1 app.company.com api.company.com" | sudo tee -a /etc/hosts
# Port-forward both HTTP and HTTPS (separate terminals)
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80 443:443
# Test HTTP redirect to HTTPS
curl -I -H "Host: app.company.com" http://localhost/
# Expected: HTTP/1.1 308 Permanent Redirect, Location: https://app.company.com/
# Test HTTPS (ignore self-signed cert warnings with -k)
curl -k -H "Host: app.company.com" https://localhost/
curl -k -H "Host: api.company.com" https://localhost/
# Test with verbose SSL info
curl -kv -H "Host: app.company.com" https://localhost/
# Verify TLS version
openssl s_client -connect localhost:443 -servername app.company.com </dev/null 2>/dev/null | grep "Protocol"Cleanup
kubectl delete ingress tls-ingress -n nginx-practice-apps
kubectl delete secret wildcard-tls -n nginx-practice-apps
sudo sed -i '/\.company\.com/d' /etc/hosts
rm tls.crt tls.keyQuestion 5: Exact vs Prefix Path Matching with NGINX
Solution
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-matching-ingress
namespace: nginx-practice-apps
spec:
ingressClassName: nginx
rules:
- host: mixed.example.com
http:
paths:
# Exact matches (highest priority)
- path: /admin/config
pathType: Exact
backend:
service:
name: config-service
port:
number: 4000
- path: /admin
pathType: Exact
backend:
service:
name: admin-panel
port:
number: 9000
- path: /api/health
pathType: Exact
backend:
service:
name: health-check
port:
number: 8080
# Prefix matches
- path: /api/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 3000
# Catch-all default (must be last)
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 8080Testing Commands
# Apply the manifest
kubectl apply -f path-matching-ingress.yaml
# Add DNS record
echo "127.0.0.1 mixed.example.com" | sudo tee -a /etc/hosts
# Port-forward
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80
# Test Exact matches
echo "=== Testing Exact Matches ==="
curl -H "Host: mixed.example.com" http://localhost/api/health
# Expected: health-check response
curl -H "Host: mixed.example.com" http://localhost/admin
# Expected: admin-panel response
curl -H "Host: mixed.example.com" http://localhost/admin/config
# Expected: config-service response
# Test Prefix match
echo "=== Testing Prefix Matches ==="
curl -H "Host: mixed.example.com" http://localhost/api/users
# Expected: user-service response
curl -H "Host: mixed.example.com" http://localhost/api/users/123
# Expected: user-service response (prefix match includes sub-paths)
curl -H "Host: mixed.example.com" http://localhost/api/users/123/profile
# Expected: user-service response
# Test non-exact matches (fall through to default)
echo "=== Testing Fall-through to Default ==="
curl -H "Host: mixed.example.com" http://localhost/api/health/check
# Expected: frontend-service response (no exact match for /api/health/check)
curl -H "Host: mixed.example.com" http://localhost/admin/other
# Expected: frontend-service response (no exact match for /admin/other)
curl -H "Host: mixed.example.com" http://localhost/random
# Expected: frontend-service response (default catch-all)
curl -H "Host: mixed.example.com" http://localhost/
# Expected: frontend-service responsePath Matching Behavior Summary
| Request Path | Match Type | Matched Rule | Service | Reason |
|---|---|---|---|---|
/api/health | Exact | /api/health | health-check | Exact match |
/api/health/check | Prefix | / (default) | frontend | No exact match, falls to default |
/admin | Exact | /admin | admin-panel | Exact match |
/admin/config | Exact | /admin/config | config-service | More specific exact match |
/admin/other | Prefix | / (default) | frontend | No exact match, falls to default |
/api/users | Prefix | /api/users | user-service | Prefix match |
/api/users/123 | Prefix | /api/users | user-service | Prefix includes sub-paths |
/random | Prefix | / (default) | frontend | Default catch-all |
Key Concepts
Exact Path Type: Matches only the exact path, no trailing segments
/adminmatches/adminonly/admindoes NOT match/admin/or/admin/config
Prefix Path Type: Matches the path and all sub-paths
/api/usersmatches/api/users,/api/users/,/api/users/123, etc.
Matching Priority:
- Exact matches have higher priority than Prefix matches
- More specific paths should be listed before less specific ones
- Catch-all
/with Prefix should be last
Best Practices:
- Order paths from most specific to least specific
- Use Exact for paths that shouldn't match sub-paths
- Use Prefix for API endpoints that need to handle sub-resources
- Always include a catch-all
/Prefix at the end for unmatched requests
Cleanup
kubectl delete ingress path-matching-ingress -n nginx-practice-apps
sudo sed -i '/mixed\.example\.com/d' /etc/hostsQuestion 6: Unified API Gateway with Multiple Backend Services
Solution
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway-ingress
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
spec:
ingressClassName: nginx
rules:
- host: gateway.api.io
http:
paths:
# Health endpoint (no rewrite)
- path: /health
pathType: Exact
backend:
service:
name: health-check
port:
number: 8080
# API v1 routes with prefix stripping
- path: /api/v1/(products.*)
pathType: ImplementationSpecific
backend:
service:
name: product-service
port:
number: 8080
- path: /api/v1/(cart.*)
pathType: ImplementationSpecific
backend:
service:
name: cart-service
port:
number: 9090
- path: /api/v1/(users.*)
pathType: ImplementationSpecific
backend:
service:
name: user-service
port:
number: 3000
- path: /api/v1/(config.*)
pathType: ImplementationSpecific
backend:
service:
name: config-service
port:
number: 4000Commands
# Apply the manifest
kubectl apply -f api-gateway-ingress.yaml
# Add DNS record
echo "127.0.0.1 gateway.api.io" | sudo tee -a /etc/hosts
# Port-forward
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80
# Test product endpoints
curl -H "Host: gateway.api.io" http://localhost/api/v1/products
curl -H "Host: gateway.api.io" http://localhost/api/v1/products/1
# Test cart endpoints
curl -H "Host: gateway.api.io" http://localhost/api/v1/cart
curl -H "Host: gateway.api.io" http://localhost/api/v1/cart/checkout
# Test user endpoints
curl -H "Host: gateway.api.io" http://localhost/api/v1/users
curl -H "Host: gateway.api.io" http://localhost/api/v1/users/1
# Test config endpoints
curl -H "Host: gateway.api.io" http://localhost/api/v1/config
curl -H "Host: gateway.api.io" http://localhost/api/v1/config/features
# Test health endpoint
curl -H "Host: gateway.api.io" http://localhost/health
# Verify CORS headers
curl -I -H "Host: gateway.api.io" -H "Origin: http://example.com" http://localhost/api/v1/productsPath Rewriting Explanation
Pattern: /api/v1/(products.*)
- Capture group 1:
products.*(everything after/api/v1/) - Capture group 2: Not used (actually $1 in this case since we only have one capture group)
- Rewrite target:
/$2should be/$1for correct rewriting
Corrected Annotation:
nginx.ingress.kubernetes.io/rewrite-target: /$1Cleanup
kubectl delete ingress api-gateway-ingress -n nginx-practice-apps
sudo sed -i '/gateway\.api\.io/d' /etc/hostsQuestion 7: Session Affinity and Custom Request Headers
Solution
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: session-ingress
namespace: nginx-practice-apps
annotations:
# Session affinity for auth service
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "auth-session"
nginx.ingress.kubernetes.io/session-cookie-max-age: "3600"
nginx.ingress.kubernetes.io/affinity-mode: "persistent"
# Custom headers for all requests
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header X-Forwarded-User "authenticated";
proxy_set_header X-Request-ID $request_id;
proxy_set_header X-Real-IP $remote_addr;
# Path rewriting
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: secure.app.io
http:
paths:
# Auth routes with session affinity (strip /auth prefix)
- path: /auth(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: auth-service
port:
number: 7070
# Admin routes (no rewrite - keep path intact)
- path: /admin(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: admin-panel
port:
number: 9000
# API routes (strip /api prefix)
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: backend-service
port:
number: 3000
# Default route
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 8080Alternative: Per-Path Session Affinity
For different session settings per path, create separate Ingress resources:
# Auth-specific Ingress with session affinity
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: session-auth-ingress
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "auth-session"
nginx.ingress.kubernetes.io/session-cookie-max-age: "3600"
spec:
ingressClassName: nginx
rules:
- host: secure.app.io
http:
paths:
- path: /auth
pathType: Prefix
backend:
service:
name: auth-service
port:
number: 7070
---
# Other routes without session affinity
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: session-general-ingress
namespace: nginx-practice-apps
spec:
ingressClassName: nginx
rules:
- host: secure.app.io
http:
paths:
- path: /admin
pathType: Prefix
backend:
service:
name: admin-panel
port:
number: 9000
- path: /api
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 3000Testing Commands
# Apply the manifest
kubectl apply -f session-ingress.yaml
# Add DNS
echo "127.0.0.1 secure.app.io" | sudo tee -a /etc/hosts
# Port-forward
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80
# Test session affinity
curl -c cookies.txt -v -H "Host: secure.app.io" http://localhost/auth/login
# Look for: Set-Cookie: auth-session=...
curl -b cookies.txt -H "Host: secure.app.io" http://localhost/auth/validate
curl -b cookies.txt -H "Host: secure.app.io" http://localhost/auth/validate
# Test admin panel
curl -H "Host: secure.app.io" http://localhost/admin/
curl -H "Host: secure.app.io" http://localhost/admin/api/stats
# Test API
curl -H "Host: secure.app.io" http://localhost/api/stats
# Verify session persistence (check pod logs)
kubectl get pods -n nginx-practice-apps -l app=auth -o name
for i in {1..5}; do
curl -b cookies.txt -s -H "Host: secure.app.io" http://localhost/auth/validate
sleep 1
doneCleanup
kubectl delete ingress session-ingress -n nginx-practice-apps
sudo sed -i '/secure\.app\.io/d' /etc/hosts
rm cookies.txtQuestion 8: Advanced Redirects for API Versioning and Migration
Solution
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: migration-redirects-ingress
namespace: nginx-practice-apps
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
# Complex redirect logic using configuration-snippet
nginx.ingress.kubernetes.io/configuration-snippet: |
# API v1 to v2 migration (301 permanent)
if ($request_uri ~ ^/api/v1/(.*)$) {
return 301 /api/v2/$1;
}
# Legacy catalog to products (301 permanent)
if ($request_uri ~ ^/catalog/(.*)$) {
return 301 /products/$1;
}
# Maintenance mode redirects (302 temporary)
if ($request_uri ~ ^/admin) {
return 302 /maintenance.html;
}
if ($request_uri ~ ^/checkout$) {
return 302 /maintenance.html;
}
# External blog redirect using server-snippet
nginx.ingress.kubernetes.io/server-snippet: |
location ~ ^/blog/(.*)$ {
return 301 https://blog.newshop.com/$1;
}
spec:
ingressClassName: nginx
rules:
- host: legacy.shop.io
http:
paths:
# New API v2 routes (after redirect)
- path: /api/v2(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: backend-service
port:
number: 3000
# New products routes (after redirect)
- path: /products(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: product-service
port:
number: 8080
# Maintenance page
- path: /maintenance.html
pathType: Exact
backend:
service:
name: frontend-service
port:
number: 8080
# Default route
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 8080Alternative: Using Permanent Redirect Annotation
For simpler 301 redirects, you can use the permanent-redirect annotation:
metadata:
annotations:
# This would redirect ALL requests to the new location
nginx.ingress.kubernetes.io/permanent-redirect: "https://newshop.com"
nginx.ingress.kubernetes.io/permanent-redirect-code: "301"Testing Commands
# Apply the manifest
kubectl apply -f migration-redirects-ingress.yaml
# Add DNS
echo "127.0.0.1 legacy.shop.io" | sudo tee -a /etc/hosts
# Port-forward
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80
# Test API v1 to v2 redirects (301)
curl -I -H "Host: legacy.shop.io" http://localhost/api/v1/products
# Expected: HTTP/1.1 301 Moved Permanently, Location: /api/v2/products
curl -L -H "Host: legacy.shop.io" http://localhost/api/v1/products
# Should follow redirect and get backend-service response
# Test catalog redirects (301)
curl -I -H "Host: legacy.shop.io" http://localhost/catalog/items
# Expected: HTTP/1.1 301 Moved Permanently, Location: /products/items
# Test maintenance redirects (302)
curl -I -H "Host: legacy.shop.io" http://localhost/admin/dashboard
# Expected: HTTP/1.1 302 Found, Location: /maintenance.html
curl -I -H "Host: legacy.shop.io" http://localhost/checkout
# Expected: HTTP/1.1 302 Found, Location: /maintenance.html
# Test blog redirect to external domain (301)
curl -I -H "Host: legacy.shop.io" http://localhost/blog/post-123
# Expected: HTTP/1.1 301 Moved Permanently, Location: https://blog.newshop.com/post-123
# Test direct routes (no redirect)
curl -H "Host: legacy.shop.io" http://localhost/api/v2/stats
curl -H "Host: legacy.shop.io" http://localhost/products
# Count redirect hops
curl -s -o /dev/null -w "Redirects: %{num_redirects}\nFinal URL: %{url_effective}\nHTTP Code: %{http_code}\n" \
-L -H "Host: legacy.shop.io" http://localhost/api/v1/products
# Verify no redirect loops
curl -L --max-redirs 10 -v -H "Host: legacy.shop.io" http://localhost/api/v1/products 2>&1 | grep -E "HTTP|Location"Debugging Redirects
# See all redirect steps
curl -Lv -H "Host: legacy.shop.io" http://localhost/api/v1/products 2>&1 | grep -E "> (GET|Host:|Location:)|< (HTTP|Location:)"
# Check NGINX config for redirect rules
kubectl exec -n ingress-nginx $(kubectl get pods -n ingress-nginx -l app.kubernetes.io/component=controller -o name | head -1) -- cat /etc/nginx/nginx.conf | grep -A 5 "legacy.shop.io"
# Test redirect performance
time curl -Ls -o /dev/null -H "Host: legacy.shop.io" http://localhost/api/v1/productsCleanup
kubectl delete ingress migration-redirects-ingress -n nginx-practice-apps
sudo sed -i '/legacy\.shop\.io/d' /etc/hostsAdditional Testing Tips
General Debugging Commands
# Check Ingress status
kubectl get ingress -n nginx-practice-apps
kubectl describe ingress <ingress-name> -n nginx-practice-apps
# Check NGINX Controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller -f
# Check backend service endpoints
kubectl get endpoints -n nginx-practice-apps
# Verify NGINX configuration
kubectl exec -n ingress-nginx <nginx-controller-pod> -- cat /etc/nginx/nginx.conf
# Test with verbose curl
curl -v -H "Host: example.com" http://localhost/path
# Follow redirects automatically
curl -L -H "Host: example.com" http://localhost/pathCommon Issues
- Ingress not working: Verify IngressClass is correct (
nginx) - 404 errors: Check service names and ports match backend services
- 503 errors: Backend pods may not be ready, check
kubectl get pods - Path rewriting not working: Verify regex patterns and capture groups
- TLS not working: Check secret exists and has correct format (tls.crt, tls.key)