Proxies and Gateways
Proxies are intermediaries that sit between clients and servers: forward proxies act on behalf of clients, reverse proxies on behalf of servers, and modern variants like API gateways and service-mesh sidecars centralize cross-cutting concerns.
Forward Proxies
A forward proxy sits in front of clients and makes requests to the internet on their behalf; the destination server sees the proxy's IP, not the client's. Classic uses are corporate egress control (filter and log which sites employees reach), anonymity, and shared caching of outbound requests, Squid is the traditional example.
In backend systems the same pattern appears as an egress proxy: all outbound calls from your services to third-party APIs flow through one layer that centralizes TLS policy, credential injection, per-vendor rate limiting, and audit logging. This also gives you one place to add retries and circuit breakers for flaky external dependencies, and a stable set of source IPs that partners can allowlist.
The distinguishing question is who the proxy serves: a forward proxy is configured by and represents the client side; the server on the far end may not even know a proxy is involved.
Reverse Proxies
A reverse proxy sits in front of servers and receives client traffic on their behalf; clients see one endpoint and never talk to backends directly. Nginx, HAProxy, Envoy, and Caddy are the standard tools, and every L7 load balancer is a reverse proxy. Typical responsibilities: TLS termination (decrypt once at the edge instead of on every app server), load balancing across backends, response caching and compression (gzip or brotli), serving static files, request buffering to insulate app servers from slow clients (the slowloris problem), and a first line of security including IP filtering, WAF rules, and basic rate limiting.
A canonical deployment: Nginx terminates TLS on port 443, serves /static from local disk, and proxies /api to a pool of application servers over plain HTTP on a private network, adding X-Forwarded-For headers so apps still see real client IPs. Nginx handles tens of thousands of concurrent connections per node with its event-driven model, which is why a thin proxy tier in front of heavier app runtimes (Rails, Django, Node) is near-universal.
For interviews, keep the two directions straight: forward proxy hides and serves clients, reverse proxy hides and serves servers. CDN edges are effectively globally distributed reverse proxies.
API Gateways
An API gateway is a reverse proxy specialized for API traffic, and it is the standard front door of a microservices architecture. Beyond routing (/orders to the order service, /users to the user service), it centralizes cross-cutting concerns: authentication and authorization (validate JWTs or API keys once, so 30 services do not each reimplement it), rate limiting and quotas per API key, request and response transformation, response caching, canary routing, and per-endpoint metrics and logging. Kong, AWS API Gateway, Apigee, and Envoy-based gateways like Ambassador are common implementations.
Gateways also decouple your public API shape from internal service topology: you can split a monolith behind a stable external contract, aggregate several internal calls into one client-facing endpoint, or translate external REST to internal gRPC. The backends-for-frontends (BFF) pattern takes this further with a gateway per client type, one shaped for mobile, one for web, each aggregating and trimming responses for its client.
The risks to name: the gateway can become a single point of failure (run it as a horizontally scaled fleet), a latency tax (usually 1-10 ms, acceptable), and an organizational bottleneck if every route change funnels through one team, teams mitigate that with declarative, self-service route configuration.
Sidecars and Service Mesh
Once you have many services calling each other, the same concerns, mutual TLS, retries, timeouts, circuit breaking, observability, reappear on every internal hop. A service mesh solves this by deploying a sidecar proxy (almost always Envoy) next to every service instance; all traffic in and out of the service transparently passes through its sidecar. The mesh control plane, Istio and Linkerd being the leading examples, pushes configuration to all sidecars: certificates for automatic mTLS between every pair of services, traffic-split rules for canaries (shift 1 percent, then 10, then 100), retry and timeout policies, and uniform metrics, so you get latency and error-rate dashboards for every service-to-service edge without touching application code.
The sidecar pattern's core win is language independence: your polyglot fleet of Go, Java, and Python services all get identical networking behavior because it lives in the proxy, not in per-language libraries. This replaced the earlier library approach (Netflix Hystrix and Ribbon) that required every service to embed and upgrade fat clients.
The honest costs: every hop gains two proxy traversals (typically adding single-digit milliseconds), each sidecar consumes memory and CPU across thousands of pods, and the operational complexity of the mesh itself is substantial. A good senior answer is that a mesh earns its keep at dozens-to-hundreds of services with strict mTLS or traffic-management needs, while smaller systems do fine with an API gateway plus sensible client libraries. Newer designs like Istio ambient mode move proxying to a per-node layer to cut the per-pod cost.
Key points
- ▸Forward proxies represent clients (egress control, anonymity, outbound policy); reverse proxies represent servers (TLS termination, load balancing, caching, buffering).
- ▸Nginx, HAProxy, and Envoy are the standard reverse proxies; a thin event-driven proxy tier in front of app servers is near-universal.
- ▸API gateways centralize auth, rate limiting, routing, and transformation at the edge of a microservices system, and decouple public API shape from internal topology.
- ▸The BFF pattern uses a gateway per client type to aggregate and tailor responses for mobile vs web.
- ▸Service meshes put an Envoy sidecar next to every instance for automatic mTLS, retries, canary traffic splits, and uniform telemetry, independent of language.
- ▸Every proxy layer adds latency and operational burden; justify each hop, and scale gateways horizontally so they are not single points of failure.
Tradeoffs
API gateway at the edge
Pros
- + One place for auth, rate limiting, and API metrics instead of N implementations
- + Stable public contract while internal services evolve or split
Cons
- − Added hop latency and a critical component to operate and scale
- − Can become an organizational bottleneck if route changes are centralized
Service mesh sidecars
Pros
- + Automatic mTLS, retries, and observability for all internal traffic with zero app code changes
- + Language-agnostic; replaces per-language resilience libraries
Cons
- − Per-pod CPU/memory overhead and extra milliseconds on every hop
- − Significant operational complexity; overkill below dozens of services
Resilience in libraries instead of proxies
Pros
- + No extra network hops or sidecar resource cost
- + Fine-grained, application-aware behavior
Cons
- − Must be reimplemented and kept current in every language and service
- − Inconsistent behavior and upgrade drift across the fleet
In the interview
- ★Get the direction right instantly: forward proxy serves the client side, reverse proxy serves the server side, and say it out loud when you draw one.
- ★In any microservices design, place an API gateway at the edge and enumerate exactly what it does (auth, rate limiting, routing) so it is not a magic box.
- ★Bring up a service mesh only when the design has many internal services and needs mTLS or canary traffic control, and acknowledge its overhead unprompted.
- ★Cite real tools, Nginx for TLS termination and static files, Envoy as the modern proxy engine, Kong or AWS API Gateway at the edge, Istio for mesh.