Skip to content

NGINX Ingress Controller - Solutions

Question 1: Simple Host-Based Routing with NGINX Ingress

Solution

bash
# 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.com

YAML Manifest (Alternative)

yaml
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: 3000

Cleanup

bash
kubectl delete ingress host-based-ingress -n nginx-practice-apps
sudo sed -i '/app\.example\.com\|api\.example\.com/d' /etc/hosts

Question 2: Path Rewriting with NGINX Annotations

Solution

yaml
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: 7070

Commands

bash
# 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/checkout

Explanation

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)

bash
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/products and /shop/products/1 would return the same response (root endpoint)

Cleanup

bash
kubectl delete ingress path-rewrite-ingress -n nginx-practice-apps
sudo sed -i '/services\.company\.com/d' /etc/hosts

Question 3: HTTP Redirects - Permanent & Temporary

Solution

yaml
# ============================================
# 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: 8080

Commands

bash
# 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 homepage

Explanation

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: /users with Exact → only /users redirects, /users/123 does NOT redirect
yaml
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 redirects

pathType: Prefix (Redirects all sub-paths)

  • Path and all sub-paths trigger redirect
  • Example: /users with Prefix → /users, /users/123, /users/profile/settings all redirect
yaml
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 URL

Important: 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:

yaml
# 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: 8080

Result:

  • /usershttps://newapi.company.com/users
  • /users/123https://newapi.company.com/users/123
  • /users/profile/settingshttps://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 (http or https)
  • $args - Query string arguments (id=5&name=test)

Example: Redirect with path manipulation:

yaml
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/123https://newapi.company.com/users/123
  • /old/productshttps://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:

  1. External Migration: /users → 301 → https://newapi.company.com/users (external service)
  2. Internal Restructure: /admin → 301 → /dashboard/admin (same domain, new path)
  3. 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

bash
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-apps

Ingress Manifest

yaml
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: 3000

Testing Commands

bash
# 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

bash
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.key

Question 5: Exact vs Prefix Path Matching with NGINX

Solution

yaml
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: 8080

Testing Commands

bash
# 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 response

Path Matching Behavior Summary

Request PathMatch TypeMatched RuleServiceReason
/api/healthExact/api/healthhealth-checkExact match
/api/health/checkPrefix/ (default)frontendNo exact match, falls to default
/adminExact/adminadmin-panelExact match
/admin/configExact/admin/configconfig-serviceMore specific exact match
/admin/otherPrefix/ (default)frontendNo exact match, falls to default
/api/usersPrefix/api/usersuser-servicePrefix match
/api/users/123Prefix/api/usersuser-servicePrefix includes sub-paths
/randomPrefix/ (default)frontendDefault catch-all

Key Concepts

  1. Exact Path Type: Matches only the exact path, no trailing segments

    • /admin matches /admin only
    • /admin does NOT match /admin/ or /admin/config
  2. Prefix Path Type: Matches the path and all sub-paths

    • /api/users matches /api/users, /api/users/, /api/users/123, etc.
  3. 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
  4. 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

bash
kubectl delete ingress path-matching-ingress -n nginx-practice-apps
sudo sed -i '/mixed\.example\.com/d' /etc/hosts

Question 6: Unified API Gateway with Multiple Backend Services

Solution

yaml
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: 4000

Commands

bash
# 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/products

Path 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: /$2 should be /$1 for correct rewriting

Corrected Annotation:

yaml
nginx.ingress.kubernetes.io/rewrite-target: /$1

Cleanup

bash
kubectl delete ingress api-gateway-ingress -n nginx-practice-apps
sudo sed -i '/gateway\.api\.io/d' /etc/hosts

Question 7: Session Affinity and Custom Request Headers

Solution

yaml
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: 8080

Alternative: Per-Path Session Affinity

For different session settings per path, create separate Ingress resources:

yaml
# 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: 3000

Testing Commands

bash
# 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
done

Cleanup

bash
kubectl delete ingress session-ingress -n nginx-practice-apps
sudo sed -i '/secure\.app\.io/d' /etc/hosts
rm cookies.txt

Question 8: Advanced Redirects for API Versioning and Migration

Solution

yaml
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: 8080

Alternative: Using Permanent Redirect Annotation

For simpler 301 redirects, you can use the permanent-redirect annotation:

yaml
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

bash
# 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

bash
# 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/products

Cleanup

bash
kubectl delete ingress migration-redirects-ingress -n nginx-practice-apps
sudo sed -i '/legacy\.shop\.io/d' /etc/hosts

Additional Testing Tips

General Debugging Commands

bash
# 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/path

Common Issues

  1. Ingress not working: Verify IngressClass is correct (nginx)
  2. 404 errors: Check service names and ports match backend services
  3. 503 errors: Backend pods may not be ready, check kubectl get pods
  4. Path rewriting not working: Verify regex patterns and capture groups
  5. TLS not working: Check secret exists and has correct format (tls.crt, tls.key)

Released under the MIT License.