Files
2026-11-05 11:15:22 +01:00

5.3 KiB

Envoy RPM Package

Envoy proxy packaged from the upstream release binaries (envoy-<version>-linux-x86_64 / -linux-aarch_64, standard build, not contrib). Intended to sit behind angie/nginx (TLS termination) and route to containers on the same host.

client → angie :443 (TLS) → envoy 127.0.0.1:10000 → containers 127.0.0.1:<port>

Package structure

Package Contents
envoy envoy user (128:128), /etc/envoy/{envoy,lds,cds}.yaml, LICENSE/NOTICE
envoy-service /usr/libexec/envoy binary, envoy.service, /usr/bin/envoy symlink
envoy-container envoy.container quadlet (Network=host), /usr/bin/envoy shim (noarch)

envoy-service and envoy-container conflict; install one of them. Both restart envoy.service on upgrade.

Configuration

File Content Applied
/etc/envoy/envoy.yaml bootstrap: admin, xDS paths systemctl restart envoy
/etc/envoy/lds.yaml listeners and routes live, polled every 5s
/etc/envoy/cds.yaml clusters (upstreams) live, polled every 5s

Defaults: listener http on 127.0.0.1:10000 (404 for everything), admin on 127.0.0.1:9901, WebSocket upgrades enabled, access log to stdout (journal).

One trusted proxy hop (use_remote_address: true, xff_num_trusted_hops: 1): the client address is the last X-Forwarded-For entry set by angie, passed upstream as x-envoy-external-address. X-Forwarded-Proto from angie is kept. Client-sent x-envoy-* headers are stripped from external requests. Since angie connects over loopback, Envoy appends the host's own address (not 127.0.0.1) to X-Forwarded-For.

LDS/CDS use path_config_source.poll_interval, so files can be edited in place (no atomic mv needed). Only changed content is applied.

  • An invalid lds.yaml/cds.yaml is rejected; the last good configuration stays active. Check journalctl -u envoy.
  • envoy --mode validate -c /etc/envoy/envoy.yaml checks only the bootstrap, not lds.yaml/cds.yaml.
  • A route referencing a cluster not yet in cds.yaml is rejected (unknown cluster). When adding both, save cds.yaml first; otherwise one warning is logged and the listener is applied on the next poll.
  • Admin state: curl -s localhost:9901/ready, /clusters, /listeners, /config_dump.

Adding a container backend

cds.yaml:

resources:
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
  name: app
  type: STATIC
  connect_timeout: 5s
  load_assignment:
    cluster_name: app
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address: { address: 127.0.0.1, port_value: 8080 }

lds.yaml, add a virtual host before default:

          - name: app
            domains: ["app.example.com"]
            routes:
            - match: { prefix: "/" }
              route: { cluster: app }

angie/nginx in front

location / {
    proxy_pass http://127.0.0.1:10000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
}

Service (envoy-service)

  • Type=simple; Envoy has no sd_notify support.
  • ExecStartPre validates the bootstrap; runs as envoy with CAP_NET_BIND_SERVICE (ports < 1024 allowed).
  • --disable-hot-restart: single instance, restarts are plain restarts.
dnf install envoy-service
systemctl enable --now envoy

Container (envoy-container)

  • Image docker.io/envoyproxy/envoy:v<version> (Ubuntu based), Network=host.
  • /etc/envoy mounted read-only. The image entrypoint remaps its envoy user to ENVOY_UID/ENVOY_GID=128, matching the host user, and drops root. Ports < 1024 are therefore not bindable in the container variant.
  • Health: bash /dev/tcp request to admin /ready (image has no curl), Notify=healthy, HealthOnFailure=kill.
  • Enabled at boot via /etc/containers/systemd/envoy.container.d/enable.conf.
  • /usr/bin/envoy shim runs podman run --rm of the same image, so envoy --mode validate -c /etc/envoy/envoy.yaml works while the container is stopped. Run as root.
dnf install envoy-container
systemctl daemon-reload
systemctl start envoy

Updating

  1. Bump Version: in envoy.spec. The image tag in envoy.container and the shim follows automatically (@VERSION@ substituted in %install).
  2. Download and verify the release binaries:
v=1.40.2
base=https://github.com/envoyproxy/envoy/releases/download/v$v
for f in envoy-$v-linux-x86_64 envoy-$v-linux-aarch_64 checksums.txt.asc; do
    curl -sSfLO "$base/$f"
done
grep -E "envoy-$v-linux-(x86_64|aarch_64)$" checksums.txt.asc | sha256sum -c
gpg --verify checksums.txt.asc   # key: thirdparty/envoy/envoy-maintainers-public.key
  1. Refresh LICENSE/NOTICE from thirdparty/envoy if changed, add a %changelog entry.