Introduction
Envoy is a high-performance L7 proxy designed for microservices architectures. It powers service meshes like Istio and is widely used as an API gateway, sidecar proxy, and edge proxy. Deploying Envoy with Ansible gives you repeatable, version-controlled proxy configuration across your infrastructure.
Install Envoy
---
- name: Deploy Envoy Proxy
hosts: proxy_servers
become: true
vars:
envoy_version: "1.32.0"
tasks:
- name: Install dependencies
ansible.builtin.apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
state: present
update_cache: true
- name: Add Envoy GPG key
ansible.builtin.apt_key:
url: "https://deb.dl.getenvoy.io/public/gpg.8115BA8E629CC074.key"
state: present
- name: Add Envoy repository
ansible.builtin.apt_repository:
repo: "deb https://deb.dl.getenvoy.io/public/deb/ubuntu {{ ansible_distribution_release }} main"
state: present
- name: Install Envoy
ansible.builtin.apt:
name: "getenvoy-envoy={{ envoy_version }}*"
state: present
- name: Create Envoy config directory
ansible.builtin.file:
path: /etc/envoy
state: directory
owner: envoy
group: envoy
mode: "0755"
- name: Deploy Envoy configuration
ansible.builtin.template:
src: envoy.yaml.j2
dest: /etc/envoy/envoy.yaml
owner: envoy
group: envoy
mode: "0644"
validate: "envoy --mode validate -c %s"
notify: restart envoy
- name: Create systemd service
ansible.builtin.copy:
dest: /etc/systemd/system/envoy.service
mode: "0644"
content: |
[Unit]
Description=Envoy Proxy
After=network.target
[Service]
Type=simple
User=envoy
ExecStart=/usr/bin/envoy -c /etc/envoy/envoy.yaml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
notify:
- reload systemd
- restart envoy
- name: Enable and start Envoy
ansible.builtin.systemd:
name: envoy
enabled: true
state: started
handlers:
- name: reload systemd
ansible.builtin.systemd:
daemon_reload: true
- name: restart envoy
ansible.builtin.systemd:
name: envoy
state: restarted
Envoy Configuration Template
# templates/envoy.yaml.j2
static_resources:
listeners:
- name: http_listener
address:
socket_address:
address: 0.0.0.0
port_value: {{ envoy_http_port | default(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
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
{% for vhost in envoy_virtual_hosts %}
- name: {{ vhost.name }}
domains: {{ vhost.domains | to_json }}
routes:
{% for route in vhost.routes %}
- match:
prefix: "{{ route.prefix }}"
route:
cluster: {{ route.cluster }}
timeout: {{ route.timeout | default('30s') }}
{% endfor %}
{% endfor %}
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
{% for cluster in envoy_clusters %}
- name: {{ cluster.name }}
connect_timeout: {{ cluster.connect_timeout | default('5s') }}
type: {{ cluster.discovery_type | default('STRICT_DNS') }}
lb_policy: {{ cluster.lb_policy | default('ROUND_ROBIN') }}
load_assignment:
cluster_name: {{ cluster.name }}
endpoints:
- lb_endpoints:
{% for endpoint in cluster.endpoints %}
- endpoint:
address:
socket_address:
address: {{ endpoint.address }}
port_value: {{ endpoint.port }}
{% endfor %}
{% if cluster.health_check is defined %}
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 3
healthy_threshold: 2
http_health_check:
path: "{{ cluster.health_check.path }}"
{% endif %}
{% endfor %}
admin:
address:
socket_address:
address: 127.0.0.1
port_value: {{ envoy_admin_port | default(9901) }}
TLS Termination
# host_vars/proxy1.yml
envoy_tls_enabled: true
envoy_tls_cert: /etc/envoy/tls/server.crt
envoy_tls_key: /etc/envoy/tls/server.key
envoy_virtual_hosts:
- name: api
domains: ["api.example.com"]
routes:
- prefix: "/v1/"
cluster: api_v1
- prefix: "/v2/"
cluster: api_v2
envoy_clusters:
- name: api_v1
endpoints:
- address: 10.0.1.10
port: 8080
- address: 10.0.1.11
port: 8080
health_check:
path: /health
- name: api_v2
endpoints:
- address: 10.0.2.10
port: 8080
lb_policy: LEAST_REQUEST
Troubleshooting
# Validate configuration
envoy --mode validate -c /etc/envoy/envoy.yaml
# Check admin interface
curl http://localhost:9901/clusters
curl http://localhost:9901/stats
curl http://localhost:9901/config_dump
# Check listeners
curl http://localhost:9901/listeners
# Hot restart
kill -HUP $(pgrep envoy)
Related Articles
- Ansible Traefik Reverse Proxy
- Ansible HAProxy Load Balancer
- Ansible Nginx Web Server
- Ansible Istio Service Mesh
- Ansible Let's Encrypt TLS
Conclusion
Envoy's powerful L7 proxy features — routing, load balancing, TLS, health checking, and observability — become fully automated with Ansible. Use Jinja2 templates for dynamic configuration, handlers for zero-downtime reloads, and the admin API for health verification. This pattern scales from a single edge proxy to a fleet of sidecar proxies.