How to Install and Configure Envoy Proxy on RHEL 7
Envoy Proxy has become a cornerstone of modern service mesh architectures, used as the data plane in Istio, the sidecar in Consul Connect, and the edge proxy behind many large-scale APIs. Written in C++ and designed for cloud-native workloads, Envoy provides L4/L7 load balancing, health checking, circuit breaking, retries, observability, and gRPC support in a single binary. While Envoy is typically discussed in the context of Kubernetes and containers, it runs perfectly well on bare-metal RHEL 7 hosts as a forward proxy, reverse proxy, or API gateway. This tutorial installs Envoy on RHEL 7 using a pre-built binary, configures it as a reverse proxy via static bootstrap YAML, and wraps it in a systemd service.
Prerequisites
- RHEL 7 server with glibc 2.17 or later (the default on RHEL 7 is sufficient).
- Root or
sudoaccess. - At least one upstream application running locally (e.g., a web server on port 8080) to proxy to.
- Internet access or a local mirror to download the Envoy binary (~140 MB).
curlinstalled (sudo yum install -y curl).
Step 1: Download the Envoy Binary
Envoy does not ship in standard RHEL 7 repositories. The easiest distribution mechanism for bare-metal Linux is the func-e installer from Tetrate or a pre-built static binary from the Envoy GitHub releases. For RHEL 7, we use func-e, which manages Envoy versions and is itself a single static binary:
# Download the func-e installer
curl -L https://func-e.io/install.sh | sudo bash -s -- -b /usr/local/bin
If your server has no internet access, download the Envoy binary directly from Tetrate builds (RHEL 7 compatible, built against glibc 2.17):
# Find the latest Linux x86_64 release from:
# https://github.com/tetratelabs/envoy-builds/releases
# Example for Envoy 1.29.x:
curl -Lo /tmp/envoy
https://github.com/tetratelabs/envoy-builds/releases/download/v1.29.2/envoy-1.29.2-linux-amd64
sudo install -m 755 /tmp/envoy /usr/local/bin/envoy
envoy --version
Expected output:
envoy version: 8ec5db97-1ad5-4f54-9e27-3c/RELEASE/BoringSSL
Step 2: Create the Envoy Bootstrap Configuration
Envoy is configured entirely through a bootstrap YAML or JSON file passed at startup. Unlike Nginx or HAProxy, there are no include directives — the entire configuration lives in one structured file. Create the directory and configuration:
sudo mkdir -p /etc/envoy
sudo vi /etc/envoy/envoy.yaml
The following configuration sets up a reverse proxy that listens on port 10000 and routes all traffic to an upstream application on localhost:8080, with an admin interface on port 9901:
admin:
address:
socket_address:
address: 127.0.0.1
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 10000
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
codec_type: AUTO
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: upstream_app
timeout: 30s
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: upstream_app
connect_timeout: 5s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: upstream_app
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 3
healthy_threshold: 2
http_health_check:
path: "/health"
Step 3: Validate the Configuration
Envoy can validate a configuration file without starting:
envoy --mode validate -c /etc/envoy/envoy.yaml
Expected output: configuration '/etc/envoy/envoy.yaml' OK. Fix any YAML syntax errors before proceeding.
Step 4: Create a systemd Service Unit
Create a dedicated system user for Envoy and a systemd unit file:
sudo useradd -r -s /sbin/nologin envoy
sudo vi /etc/systemd/system/envoy.service
[Unit]
Description=Envoy Proxy
Documentation=https://www.envoyproxy.io/docs
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=envoy
Group=envoy
ExecStart=/usr/local/bin/envoy
--config-path /etc/envoy/envoy.yaml
--log-level warn
--log-format "[%Y-%m-%d %T.%e][%t][%l][%n] %v"
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
LimitNOFILE=65536
LimitNPROC=65536
[Install]
WantedBy=multi-user.target
Grant the envoy user read access to the configuration:
sudo chown -R root:envoy /etc/envoy
sudo chmod 640 /etc/envoy/envoy.yaml
Reload systemd and start the service:
sudo systemctl daemon-reload
sudo systemctl enable envoy
sudo systemctl start envoy
sudo systemctl status envoy
Step 5: Configure Load Balancing Across Multiple Upstream Instances
To distribute traffic across multiple backend instances (e.g., three application servers), expand the cluster’s lb_endpoints section:
clusters:
- name: upstream_app
connect_timeout: 5s
type: STATIC
lb_policy: LEAST_REQUEST # or ROUND_ROBIN, RANDOM, RING_HASH
load_assignment:
cluster_name: upstream_app
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.10.10
port_value: 8080
- endpoint:
address:
socket_address:
address: 192.168.10.11
port_value: 8080
- endpoint:
address:
socket_address:
address: 192.168.10.12
port_value: 8080
Available lb_policy values: ROUND_ROBIN, LEAST_REQUEST, RANDOM, RING_HASH, MAGLEV. RING_HASH and MAGLEV provide consistent hashing suitable for session-aware backends.
Step 6: Access Logging and the Admin Interface
The admin interface (port 9901) exposes runtime statistics, cluster health, and configuration dumps. Access it from localhost:
# View all statistics
curl http://127.0.0.1:9901/stats
# View cluster health
curl http://127.0.0.1:9901/clusters
# Dump the current config as JSON
curl http://127.0.0.1:9901/config_dump | python -m json.tool | head -60
# View live access logs
sudo journalctl -u envoy -f
Step 7: Configure gRPC Proxying
Envoy understands HTTP/2 and gRPC natively. To proxy gRPC traffic, set codec_type: HTTP2 on the listener and http2_protocol_options: {} on the cluster:
clusters:
- name: grpc_upstream
connect_timeout: 5s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
http2_protocol_options: {} # Force HTTP/2 (required for gRPC)
load_assignment:
cluster_name: grpc_upstream
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 9090
Step 8: Open the Firewall
sudo firewall-cmd --permanent --add-port=10000/tcp
sudo firewall-cmd --reload
Do not open port 9901 externally — the admin interface has no authentication and must remain on localhost only.
Comparing Envoy with Nginx and HAProxy
All three are capable reverse proxies, but they serve different use cases:
- Nginx: Mature, file-based configuration, excellent static file serving, low learning curve. No native gRPC, no dynamic xDS configuration.
- HAProxy: Best-in-class L4 TCP load balancing, excellent health checking. Limited HTTP/2 and no native gRPC proxying. Configuration is not hot-reloadable without process replacement.
- Envoy: Designed for dynamic service-to-service communication. Supports xDS APIs for live configuration updates, native gRPC, HTTP/3 (QUIC), distributed tracing, and circuit breaking. Higher initial complexity but unmatched extensibility for microservice environments.
Conclusion
You have installed Envoy Proxy on RHEL 7 using a pre-built binary, written a static bootstrap YAML configuring a listener, an upstream cluster with health checks, and access logging to stdout, and managed it as a systemd service under a dedicated user account. You explored multiple load balancing policies, the admin API, gRPC proxying requirements, and compared Envoy with Nginx and HAProxy. For production deployments, consider adding TLS termination on the listener using a transport_socket with DownstreamTlsContext, and integrating with your secrets management system to rotate certificates without restarting the proxy.