Stackbook Logo
← Back to Tools

Envoy Proxy Guide

Understand Envoy, the cloud-native L4 and L7 proxy: listeners, routes, clusters, health checks, dynamic xDS configuration and the admin interface.

4 min read

What it is and when to use it

Envoy is a high-performance, open source edge and service proxy originally built at Lyft and now a CNCF graduated project. It handles TCP and HTTP traffic, speaks HTTP/2 and gRPC natively, and exposes detailed metrics, access logs and tracing out of the box. Its defining feature is dynamic configuration: control planes can push changes through the xDS APIs without restarts.

Use Envoy as an API gateway or edge proxy, as a sidecar in a service mesh, or as a building block inside other products. It underlies Istio, Contour, Emissary and Envoy Gateway. For a simple static site or a single backend, Nginx or HAProxy are often easier to operate.

Quick start

Run the official image with a static configuration file.

docker run --rm -p 8080:8080 -p 9901:9901 \
  -v "$PWD/envoy.yaml:/etc/envoy/envoy.yaml:ro" \
  envoyproxy/envoy:v1.31-latest

A minimal envoy.yaml that proxies everything to a backend on port 3000:

static_resources:
  listeners:
    - name: main
      address:
        socket_address: { address: 0.0.0.0, port_value: 8080 }
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: app
                      domains: ["*"]
                      routes:
                        - match: { prefix: "/" }
                          route: { cluster: app_service }
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
    - name: app_service
      type: STRICT_DNS
      connect_timeout: 2s
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: app_service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address: { address: host.docker.internal, port_value: 3000 }

admin:
  address:
    socket_address: { address: 127.0.0.1, port_value: 9901 }

Validate before running, and inspect the live proxy through the admin port.

envoy --mode validate -c envoy.yaml
curl -s localhost:9901/clusters
curl -s localhost:9901/stats | grep upstream_rq
curl -s localhost:9901/config_dump | head

Core concepts

Listeners bind an address and port and own a chain of filters. Filter chains process connections; the HTTP connection manager is the main network filter, running HTTP filters such as router, rate limit, JWT authentication and external authorization in order. The router must be last.

Routes match on host, path, headers or query parameters, then send traffic to a cluster. They can also rewrite paths, split traffic by weight, retry, mirror and apply timeouts.

routes:
  - match: { prefix: "/api/" }
    route:
      weighted_clusters:
        clusters:
          - { name: api_v1, weight: 90 }
          - { name: api_v2, weight: 10 }
      timeout: 5s
      retry_policy:
        retry_on: "5xx,connect-failure"
        num_retries: 2

Clusters are groups of upstream endpoints with a load balancing policy, connection pool limits, circuit breaker thresholds, outlier detection and health checks. Discovery types include STATIC, STRICT_DNS and EDS, the dynamic endpoint API.

xDS is the family of discovery services: LDS for listeners, RDS for routes, CDS for clusters, EDS for endpoints and SDS for secrets. A control plane serves them over gRPC so Envoy updates live. You rarely write a control plane yourself; projects like Istio or Envoy Gateway do.

Observability. Envoy emits per-cluster and per-route counters, histograms for latency, structured access logs and trace spans, which Prometheus, Grafana and Jaeger can consume. Scrape the admin endpoint with the prometheus path under stats.

Pitfalls

  • Raw YAML is verbose and strict. Mistyped type URLs cause load failures, so always validate with the validate mode.
  • Listener order inside HTTP filters matters, and a missing router filter yields confusing behavior.
  • Do not expose the admin interface publicly. It can drain, quit and dump configuration. Bind it to localhost or restrict access.
  • Default timeouts of 15 seconds for routes surprise long-polling and streaming clients. Set timeout and idle_timeout explicitly.
  • Retries can multiply load during outages. Combine them with circuit breakers, retry budgets and sensible limits.
  • Hot restart and drain behavior must be tuned if you run Envoy outside Kubernetes; use drain-time settings for graceful shutdown.
  • For TLS, remember to configure both downstream (client facing) and upstream contexts separately.

How it fits an architecture

At the edge, Envoy acts as an ingress gateway terminating TLS and routing to services. Inside a mesh, a sidecar Envoy beside every workload provides mutual TLS, retries, timeouts and telemetry transparently, programmed by a control plane such as Istio. In a Kubernetes setup managed with Argo CD and Helm, you typically deploy Envoy through Gateway API based projects rather than hand-writing bootstrap files.

Key takeaways

  • Envoy is a programmable L4 and L7 proxy with first-class gRPC, HTTP/2 and observability.
  • Core objects are listeners, routes, clusters and endpoints.
  • xDS enables dynamic, restart-free configuration from a control plane.
  • Validate configs, protect the admin port, and set timeouts and retries explicitly.
  • Choose Envoy where dynamic routing and telemetry matter, and simpler proxies elsewhere.