Ingress controller - proxy pass based on user agent
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Routing traffic by User-Agent is possible in Kubernetes, but the answer depends on which ingress controller you run. The standard Ingress API only understands hosts and paths. If you want request routing based on headers such as User-Agent, you are already in controller-specific territory, and with NGINX that usually means snippets, rewrites, or a dedicated proxy configuration.
Understand the boundary of standard Ingress
A normal Ingress resource does not have a field for "send iPhone clients to service A and desktop clients to service B." It describes HTTP routing at a higher level:
- host matching
- path matching
- TLS configuration
- backend services
That means raw proxy_pass logic is not something the Kubernetes API models directly. The ingress controller generates its own NGINX configuration from your resource, and direct low-level routing tricks may or may not fit cleanly into that generated config.
A practical ingress-nginx pattern
With ingress-nginx, a common pattern is to rewrite matching requests to an internal path and let normal path-based routing choose the backend service. That keeps you closer to supported behavior than trying to override the controller's generated proxy_pass line.
Here the request still arrives at one host. Mobile-style user agents are rewritten to /mobile..., and the generated NGINX locations for the Ingress send them to mobile-backend. Everyone else stays on the default path and reaches web-backend.
This is usually easier to reason about than injecting your own upstream selection logic into the controller's internals.
If you truly need raw proxy_pass
Sometimes you want exact NGINX behavior, not just ingress-nginx annotations. In that case, a dedicated NGINX deployment or a controller-specific custom resource may be the better tool.
A plain NGINX example looks like this:
That config is real NGINX and does true upstream selection by user agent. The tradeoff is that you are no longer relying only on the portable Ingress abstraction.
Operational concerns matter here
Before reaching for user-agent routing, ask whether it belongs at the edge at all. If mobile and desktop clients can share the same endpoint with capability negotiation inside the application, that is often simpler.
If you still need edge routing, verify these details:
- snippet annotations may be disabled by cluster policy
- controller upgrades can affect custom snippets
- regex matching should be tested against actual user-agent strings
- rewrite-based routing needs the backend services to understand the rewritten paths
Also remember that User-Agent is easy to spoof. It is fine for product segmentation or gradual migration, but it is not a security boundary.
Common Pitfalls
The most common mistake is assuming the Ingress spec itself supports header-based backend selection. It does not.
Another mistake is dropping a raw proxy_pass into a snippet without understanding that ingress-nginx already generates its own locations and upstreams. That can produce invalid or fragile NGINX configs.
Teams also forget that snippets are often turned off for security reasons, especially in multi-tenant clusters.
Finally, do not rely on User-Agent for authentication, authorization, or bot protection. It is a hint, not a trustworthy identity signal.
Summary
- Standard Kubernetes Ingress does not directly express user-agent-based backend routing.
- In
ingress-nginx, a rewrite-to-path pattern is often safer than forcing customproxy_passlogic. - If you need exact NGINX behavior, use a dedicated proxy config or controller-specific extension.
- Test cluster policy, regex behavior, and rewritten paths before rollout.
- Treat
User-Agentas a routing hint, not a security control.
Related reading
- Ingress controller to route TCP traffic
- Ingress controller vs api gateway
- Ingress not working in google kubernetes engine for multiple services Spring Boot
- Ingress routing rules to access prometheus server
- Ingress vs Load Balancer
- Ingress with IP address instead of host
- InitContainer not idempotent, how to prevent it from running twice?
- Inject code/files directly into a container in Kubernetes on Google Cloud Engine

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.