envoyctl is a configuration management tool for Envoy Proxy.
Manage complex Envoy configurations using small, focused YAML fragments, validate with Envoy itself, and deploy with confidence.
- Installation
- Quick Start
- What is Envoy?
- Why envoyctl?
- Features
- Workspace Layout
- Configuration Examples
- Commands
- Validation Modes
- TLS Behavior
- Docker Deployment
- Contributing
- License
# 1. Download and install the GPG signing key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://boniface.github.io/envoyctl/public.gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/envoyctl.gpg
# 2. Add the APT repository
echo "deb [signed-by=/etc/apt/keyrings/envoyctl.gpg] https://boniface.github.io/envoyctl stable main" \
| sudo tee /etc/apt/sources.list.d/envoyctl.list
# 3. Update and install
sudo apt update
sudo apt install envoyctl
# 4. Verify installation
envoyctl --version# Clone the repository
git clone https://github.com/boniface/envoyctl.git
cd envoyctl
# Build release binary
cargo build --release
# Install to system
sudo cp target/release/envoyctl /usr/local/bin/
# Verify installation
envoyctl --versionDownload the .deb package directly from GitHub Releases:
# Download the latest release
curl -LO https://github.com/boniface/envoyctl/releases/latest/download/envoyctl_0.1.0_amd64.deb
# Install
sudo dpkg -i envoyctl_*.deb
# Verify
envoyctl --versionenvoyctl init --dir ./my-envoy-config
cd ./my-envoy-config# Edit the example domain
vim config/domains/example.com.yaml
# Edit backend upstreams
vim config/upstreams/api_backend.yaml
vim config/upstreams/web_frontend.yaml
# Configure validation mode
vim config/common/runtime.yamlenvoyctl --config-dir ./config --out-dir ./out buildenvoyctl --config-dir ./config --out-dir ./out validateThe generated configuration will be at ./out/envoy.generated.yaml.
Envoy is a high-performance, open-source edge and service proxy designed for cloud-native applications. Originally built at Lyft, it's now a graduated CNCF project.
| Capability | Description |
|---|---|
| Load Balancing | Distributes traffic across backend services |
| TLS Termination | Handles HTTPS at the edge |
| TLS Passthrough | Routes encrypted traffic via SNI |
| Reverse Proxy | Routes HTTP/HTTPS to backends |
| Rate Limiting | Protects services from abuse |
| Health Checking | Monitors backend health |
| Observability | Metrics, logging, and tracing |
Envoy is powerful but verbose. A simple route requires 50+ lines of YAML:
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 443
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/...
# ... continues for many more linesenvoyctl solves this by generating complete Envoy configurations from simple fragments.
| Problem | envoyctl Solution |
|---|---|
| Giant, unwieldy config files | Small, focused YAML fragments |
| Hard to make changes safely | One file per domain/upstream |
| Late or no validation | Always validated before use |
| Risky deployments | Atomic config generation |
| Difficult to audit | Deterministic, commented output |
Instead of hundreds of lines, write this:
# config/domains/example.com.yaml
domain: example.com
mode: terminate_https_443
tls:
cert_chain: /etc/envoy/certs/example.com/fullchain.pem
private_key: /etc/envoy/certs/example.com/privkey.pem
routes:
- match: { prefix: "/api/" }
to_upstream: api_backend
- match: { prefix: "/" }
to_upstream: web_frontend# config/upstreams/api_backend.yaml
name: api_backend
connect_timeout: 2s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
endpoints:
- { address: "api-service", port: 8080 }Then generate:
envoyctl --config-dir ./config --out-dir ./out build- ✅ Fragment-based configuration — Organize by domain, upstream, policy
- ✅ Envoy v3 static configuration — Full compatibility
- ✅ TLS termination & passthrough — Flexible HTTPS handling
- ✅ Built-in validation — Validate with Docker or native Envoy
- ✅ Section comments — Generated YAML includes helpful comments
- ✅ Timestamps — Know when config was generated
- ✅ APT repository — Easy installation on Debian/Ubuntu
my-envoy-config/
├── config/
│ ├── common/
│ │ ├── admin.yaml # Envoy admin interface
│ │ ├── defaults.yaml # Global defaults
│ │ ├── runtime.yaml # Validation settings
│ │ ├── access_log.yaml # Logging configuration
│ │ ├── default_http_backend.yaml
│ │ └── default_tls_backend.yaml
│ ├── domains/
│ │ └── example.com.yaml # One file per domain
│ ├── upstreams/
│ │ ├── api_backend.yaml # One file per backend
│ │ └── web_frontend.yaml
│ └── policies/
│ ├── headers.yaml # Header manipulation
│ ├── ratelimits.yaml # Rate limiting
│ ├── retries.yaml # Retry policies
│ └── timeouts.yaml # Timeout configs
└── out/
└── envoy.generated.yaml # Generated config (don't edit!)
Create config/domains/api.example.com.yaml:
domain: api.example.com
mode: terminate_https_443
tls:
cert_chain: /etc/envoy/certs/api.example.com/fullchain.pem
private_key: /etc/envoy/certs/api.example.com/privkey.pem
routes:
- match: { prefix: "/v1/" }
to_upstream: api_v1
timeout: 30s
- match: { prefix: "/" }
to_upstream: web_frontend
timeout: 60sCreate config/upstreams/api_v1.yaml:
name: api_v1
connect_timeout: 2s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
http2: true
endpoints:
- { address: "api-v1-service", port: 8080 }
- { address: "api-v1-backup", port: 8080 }In config/policies/ratelimits.yaml:
local_ratelimits:
strict:
max_tokens: 30
tokens_per_fill: 30
fill_interval: 1sReference in domain routes:
routes:
- match: { prefix: "/login" }
to_upstream: auth_service
per_filter_config:
local_ratelimit: strict| Command | Description |
|---|---|
envoyctl init --dir <path> |
Create a new workspace from templates |
envoyctl build |
Generate Envoy config from fragments |
envoyctl validate |
Build + validate with Envoy |
envoyctl [OPTIONS] <COMMAND>
Options:
--config-dir <PATH> Config directory [default: config]
--out-dir <PATH> Output directory [default: out]
--install-path <PATH> Install target [default: /etc/envoy/envoy.yaml]
--envoy-bin <PATH> Envoy binary path (for native validation)
-h, --help Print help
-V, --version Print version# Build with default paths
envoyctl build
# Build with custom paths
envoyctl --config-dir ./my-config --out-dir ./my-output build
# Validate configuration
envoyctl --config-dir ./config --out-dir ./out validateConfigure in config/common/runtime.yaml:
Validates inside a running Envoy container:
validate:
type: docker_exec
container: envoy # Container name
config_path: /etc/envoy/envoy.yaml # Path inside containerValidates using local Envoy binary with sudo:
validate:
type: native
user: envoy # User to run as
bin: envoy # Envoy binary path
config_path: /etc/envoy/envoy.yaml # Config pathValidates using a fresh container:
validate:
type: docker_image
image: envoyproxy/envoy:v1.31-latest| Mode | Port | Description |
|---|---|---|
terminate_https_443 |
443 | Envoy terminates TLS (requires cert/key) |
passthrough_443 |
443 | TLS passed through unchanged (SNI routing) |
http_80 |
80 | Plain HTTP |
Default for unknown domains on :443: TLS passthrough to default_tls_backend.
See the full Docker Deployment Tutorial.
# Generate configuration
envoyctl --config-dir ./config --out-dir ./out build
# Run Envoy with generated config
docker run -d \
--name envoy \
-p 80:80 -p 443:443 -p 9901:9901 \
-v $(pwd)/out/envoy.generated.yaml:/etc/envoy/envoy.yaml:ro \
-v /etc/envoy/certs:/etc/envoy/certs:ro \
envoyproxy/envoy:v1.31-latestversion: '3.8'
services:
envoy:
image: envoyproxy/envoy:v1.31-latest
ports:
- "80:80"
- "443:443"
- "127.0.0.1:9901:9901"
volumes:
- ./out/envoy.generated.yaml:/etc/envoy/envoy.yaml:ro
- /etc/letsencrypt:/etc/envoy/certs:ro
restart: unless-stoppedContributions are welcome! See CONTRIBUTING.md for guidelines.
# Clone
git clone https://github.com/boniface/envoyctl.git
cd envoyctl
# Build
cargo build
# Run tests
cargo test
# Check formatting
cargo fmt -- --check
# Run lints
cargo clippy -- -D warningsMIT License — Copyright (c) 2025 Boniface Kabaso
See LICENSE for full text.
- Repository: github.com/boniface/envoyctl
- APT Repository: boniface.github.io/envoyctl
- Documentation: docs/
- Envoy Proxy: envoyproxy.io