2026年11月14日

2026年11月14日

Envoy vs Nginx for WordPress: Differences and Which to Choose

This article is a localized edition of the Japanese original. Read the Japanese original

Envoy and Nginx can both be used as reverse proxies, but their strengths are clearly different. In short, if you run WordPress on one to a few servers, Nginx is the straightforward choice; if you dynamically tie together many services on a container platform or a service mesh, Envoy is the better fit. This article sorts out the differences in design philosophy, configuration style and operation, and compares the same setup written in both, so you can decide which to choose for your own environment.

How Envoy and Nginx differ

Background and design philosophy

Nginx was born as a fast web server and handles static file delivery, FastCGI connections to PHP-FPM, reverse proxying and even caching in a single process. It assumes a server-by-server operating model: you write a configuration file (nginx.conf) and apply it with a reload.

Envoy is a proxy developed by Lyft for its internal microservice communication, and it is now developed as a project of the CNCF (Cloud Native Computing Foundation). It is designed not as a web server but as a "proxy for service-to-service communication," and its biggest feature is that configuration can be delivered dynamically from outside through an API (a mechanism called xDS). This is also why it is used as the data plane in service meshes such as Istio.

Differences in features

Comparing the main differences gives the following. Whether a feature exists varies by version and edition, so take this as a general tendency as of October 2026.

Aspect Nginx (open source edition) Envoy
Main role Web server + reverse proxy L4/L7 proxy (service-to-service communication)
Static file delivery and PHP-FPM connection Strong Not the main purpose
Applying configuration Edit the configuration file + reload Static file, or dynamic updates through the xDS API
Active health checks A feature of the commercial edition (NGINX Plus) Built in
Retries and circuit breakers Limited (mainly passive removal) Finely configurable
Observability Mainly access logs Detailed statistics and distributed tracing integration
Learning cost Low, with plenty of information High, with verbose configuration

The open source edition of Nginx can also remove a backend, but it uses a passive method based on max_fails and fail_timeout: "if it fails, take it out for a set time." Envoy has built in active health checks that send requests to backends periodically, outlier detection that automatically removes unhealthy hosts, and circuit breakers that set an upper limit on concurrent connections.

Writing the same setup in both

The quickest way to feel the difference is to write the same setup, "just pass the received requests to a WordPress backend," in both. Here the backend is wordpress-app:80.

With Nginx

upstream wordpress_backend {
    server wordpress-app:80 max_fails=3 fail_timeout=30s;
}

server {
    listen 8080;
    server_name example.com;

    location / {
        proxy_pass http://wordpress_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Nginx's strength is that it is short and easy to read. Be aware that if you do not pass the Host header explicitly, it is easy to run into problems such as WordPress returning redirects using the backend's host name.

With Envoy

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

static_resources:
  listeners:
  - name: listener_http
    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
          use_remote_address: true
          route_config:
            name: local_route
            virtual_hosts:
            - name: wordpress
              domains: ["example.com"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: wordpress_backend }
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: wordpress_backend
    connect_timeout: 5s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: wordpress_backend
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: wordpress-app, port_value: 80 }

It takes several times as much to write for the same result. Envoy is designed by combining components of "listener → filter chain → route → cluster," and each component's type is stated explicitly with @type. It looks verbose, but it is this structure that makes it possible to deliver the same configuration dynamically through an API and to add features by inserting filters. use_remote_address: true is the setting that makes Envoy append the connection source's IP address to X-Forwarded-For.

The admin interface (port 9901 in the example above) is a powerful entry point that lets you view statistics and dump the configuration, so do not expose it externally; restrict it to 127.0.0.1 or similar.

How to validate the configuration

With either one, getting into the habit of running a syntax check before applying changes reduces trouble.

# Nginx
sudo nginx -t
sudo systemctl reload nginx

# Envoy (only validates the configuration file, does not start)
envoy --mode validate -c /etc/envoy/envoy.yaml

With Envoy you can check the backend status at /clusters on the admin interface, and the request and error counts at /stats. To get equivalent information with Nginx, you combine access log analysis, the stub_status module and so on.

Cautions when putting either in front of WordPress

Whichever you use, WordPress behind the proxy cannot directly know whether "it is being viewed over HTTPS." In a setup where TLS is terminated at the proxy and passed to the backend over HTTP, WordPress may decide it is HTTP and cause redirect loops or mixed content.

In that case, add processing like the following to wp-config.php before require_once ABSPATH . 'wp-settings.php';.

// Use only in setups where access comes solely through a trusted proxy
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
    $_SERVER['HTTPS'] = 'on';
}

X-Forwarded-Proto is a header that clients can forge freely. If you add this processing while the backend can be reached directly from somewhere other than the proxy, it leaves room for the check to be forged. Use it only after restricting the connection sources to the backend to the proxy in the firewall.

Also, the connection source IP as seen from WordPress becomes the proxy's address. If you need the real client IP for login attempt limits or comment spam detection, the safe method is to specify the trusted proxy on the web server side (Apache's mod_remoteip or Nginx's realip module) and restore it from X-Forwarded-For.

Before you start, back up the configuration files and WordPress, and check the behavior in a staging environment before applying to production.

Which one should you choose

When Nginx suits you

  • You run WordPress on one to a few VPS or cloud servers
  • You want the same software to handle static file delivery and the connection to PHP-FPM too
  • Configuration changes are infrequent, and editing files and reloading is enough
  • Your team has Nginx operating experience, and you value being able to find information easily when trouble occurs

For an ordinary WordPress site, a single Nginx can serve as both the web server and the reverse proxy, so there are fewer components and fewer points of failure.

When Envoy suits you

  • You dynamically add and remove many services on a container platform such as Kubernetes
  • You have adopted a service mesh (such as Istio) or a Gateway API implementation (such as Envoy Gateway)
  • You want to manage retries, circuit breakers and detailed metrics centrally at the proxy layer
  • You want to handle multiple protocols, including gRPC, with the same proxy

Even in this case, it is common to have a two-tier setup in which Nginx or Apache handles WordPress's own PHP execution and Envoy sits in front of it. Keeping in mind that Envoy alone does not run WordPress will keep you from getting lost when drawing the architecture diagram.

Decision criteria when in doubt

The dividing line comes down to two points: "Do you want to change configuration dynamically through an API?" and "Do you need advanced traffic control or measurement at the proxy layer?" If you need neither, choosing Nginx lowers the operational load. For Ingress controllers on Kubernetes, a project's maintenance status can change (for example, ingress-nginx has been announced to be retiring), so check the current status in each project's official information before adopting one.

Summary

  • Nginx is a web server and reverse proxy, suited to running WordPress on a small number of servers
  • Envoy is a proxy for service-to-service communication, with dynamic configuration through xDS, active health checks and detailed statistics as its strengths
  • Even for the same setup, Envoy's configuration is verbose, but that structure supports dynamic delivery and extension
  • Whichever you put in front, you need to correctly tell WordPress about X-Forwarded-Proto and the real client IP
  • If you do not need "dynamic configuration changes" and "advanced control at the proxy layer," consider Nginx; if you do, consider Envoy

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲