HashiCorp Consul Connect is the service mesh layer built into Consul, enabling automatic mTLS encryption and authorization between microservices. It uses sidecar proxies (typically Envoy) to intercept and secure all service-to-service traffic without requiring application code changes. For teams running microservices on-premise or across multi-cloud deployments, Consul Connect provides a production-grade alternative to cloud-native service meshes like AWS App Mesh or Istio.
But a service mesh adds layers — Consul servers, sidecar proxies, certificate authorities, intentions (authorization policies), and the services themselves — and each layer can fail independently. This tutorial shows you how to monitor your entire Consul Connect deployment end-to-end with Vigilmon.
Why Consul Connect needs external monitoring
Consul Connect's production failure modes span multiple layers:
- Consul server quorum loss — Consul uses Raft consensus. If a majority of servers are unavailable, the cluster stops accepting writes. Service registration, health checks, and intention updates all fail silently from the service's perspective.
- sidecar proxy crashes — if an Envoy sidecar crashes without the pod restarting (especially in non-Kubernetes deployments), the service is still running but all mTLS-gated traffic to it is blocked. No Consul alert fires.
- Certificate rotation failure — Consul's built-in CA (or an external Vault-backed CA) issues leaf certificates to sidecars with short TTLs (72 hours by default). If the rotation job fails or the CA is unreachable, expired certs block all mTLS connections mesh-wide.
- Intention misconfigurations — a policy push that creates an unintended
denyrule between critical services silently breaks communication. Consul applies intentions immediately; there's no rollout and no automatic revert. - DNS resolution degradation — services discover each other through Consul DNS (
service.consuladdresses). If the Consul DNS server becomes overloaded or partitioned, service discovery fails even when the services themselves are healthy.
Vigilmon monitors cover the Consul control plane, sidecar health, certificate validity, and end-to-end service connectivity.
What you'll need
- A running Consul cluster (3+ servers recommended for production)
- Services registered in Consul with Connect enabled
- A free Vigilmon account
Step 1: Expose health endpoints on Consul-registered services
Every service in the mesh should have a health endpoint registered with Consul. Add a /health route to each service:
Go (net/http):
package main
import (
"encoding/json"
"net/http"
)
func main() {
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "ok",
"service": "api",
})
})
http.ListenAndServe(":8080", nil)
}
Register the service and its Connect sidecar in Consul with the health check:
# consul-service.hcl
service {
name = "api"
port = 8080
connect {
sidecar_service {
proxy {
upstreams = [
{
destination_name = "database"
local_bind_port = 5432
}
]
}
}
}
check {
http = "http://localhost:8080/health"
interval = "10s"
timeout = "3s"
}
}
Step 2: Monitor Consul server cluster health
The Consul HTTP API provides a /v1/status/leader endpoint that returns the current Raft leader. No leader = quorum failure. Monitor it externally:
In Vigilmon: Monitors → New Monitor → HTTP
- URL:
http://consul.yourdomain.com:8500/v1/status/leader - Expected status:
200 - Expected body contains:
"(a non-empty response = a leader exists; empty string = no leader) - Name:
Consul Leader Health - Interval: 1 minute
For the peer list (all servers must be reachable):
#!/bin/bash
# consul-cluster-probe.sh
HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_CLUSTER_HEARTBEAT"
CONSUL_ADDR="http://localhost:8500"
EXPECTED_PEERS=3 # adjust to your cluster size
# Check leader exists
leader=$(curl -s --max-time 5 "$CONSUL_ADDR/v1/status/leader")
if [ -z "$leader" ] || [ "$leader" = '""' ]; then
echo "$(date): No Consul leader" >> /var/log/consul-probe.log
exit 1
fi
# Check all peers are present
peer_count=$(curl -s --max-time 5 "$CONSUL_ADDR/v1/status/peers" | \
python3 -c "import json,sys; print(len(json.load(sys.stdin)))" 2>/dev/null)
if [ "${peer_count:-0}" -lt "$EXPECTED_PEERS" ]; then
echo "$(date): Only $peer_count/$EXPECTED_PEERS peers in Raft" >> /var/log/consul-probe.log
exit 1
fi
curl -s "$HEARTBEAT_URL" --max-time 10 --retry 2
Create a Heartbeat monitor with 2-minute interval, name Consul Cluster Health.
Step 3: Monitor service health via the Consul catalog
Use the Consul health API to check that critical services have passing checks. This catches sidecar crashes and failed application health checks:
#!/bin/bash
# consul-service-health-probe.sh
HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_SERVICE_HEALTH_HEARTBEAT"
CONSUL_ADDR="http://localhost:8500"
# Critical services to verify
SERVICES=("api" "database" "worker" "gateway")
all_ok=true
for svc in "${SERVICES[@]}"; do
# Query service health — returns instances with their check status
critical=$(curl -s --max-time 5 \
"$CONSUL_ADDR/v1/health/service/$svc?passing=false" | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
critical = [
i['Service']['ID']
for i in data
for check in i['Checks']
if check['Status'] == 'critical'
]
print(len(critical))
" 2>/dev/null)
if [ "${critical:-0}" -gt 0 ]; then
echo "$(date): Service $svc has $critical critical instances" >> /var/log/consul-service-health.log
all_ok=false
fi
done
$all_ok && curl -s "$HEARTBEAT_URL" --max-time 10
Schedule every 2 minutes. Create a Heartbeat monitor with 5-minute interval.
Step 4: Monitor Connect mTLS certificate expiry
Consul's Connect CA issues leaf certificates with short TTLs. Monitor the CA itself and certificate rotation:
#!/bin/bash
# consul-cert-probe.sh
HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_CERT_HEARTBEAT"
CONSUL_ADDR="http://localhost:8500"
WARN_DAYS=7 # Alert if root CA expires within 7 days
# Check the Connect CA status
ca_status=$(curl -s --max-time 5 "$CONSUL_ADDR/v1/connect/ca/roots")
if [ -z "$ca_status" ]; then
echo "$(date): Could not retrieve CA roots" >> /var/log/consul-cert.log
exit 1
fi
# Extract expiry of the active root certificate
expiry_date=$(echo "$ca_status" | python3 -c "
import json, sys
from datetime import datetime
data = json.load(sys.stdin)
roots = data.get('Roots', [])
active = [r for r in roots if r.get('Active')]
if not active:
print('')
else:
# NotAfter is in RFC3339 format
print(active[0].get('NotAfter', ''))
" 2>/dev/null)
if [ -z "$expiry_date" ]; then
echo "$(date): No active CA root found" >> /var/log/consul-cert.log
exit 1
fi
# Parse and compare dates
days_left=$(python3 -c "
from datetime import datetime, timezone
expiry = datetime.fromisoformat('$expiry_date'.replace('Z', '+00:00'))
now = datetime.now(timezone.utc)
print((expiry - now).days)
" 2>/dev/null)
if [ "${days_left:-0}" -lt "$WARN_DAYS" ]; then
echo "$(date): CA root expires in ${days_left} days" >> /var/log/consul-cert.log
exit 1
fi
curl -s "$HEARTBEAT_URL" --max-time 10
Run daily. Create a Heartbeat monitor with 25-hour interval, name Consul Connect CA Health.
Step 5: Monitor end-to-end Connect proxy connectivity
Verify that services can actually talk to each other through the Connect sidecar proxies — not just that Consul thinks they're healthy:
#!/bin/bash
# consul-connect-e2e-probe.sh
# Run from a service that has Connect upstreams configured
HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_E2E_HEARTBEAT"
# Test connectivity through Connect sidecar upstreams
# These ports are the local_bind_port values in upstream config
UPSTREAM_CHECKS=(
"http://127.0.0.1:5432" # database upstream through Connect
"http://127.0.0.1:6379" # cache upstream through Connect
"http://127.0.0.1:9090/health" # internal API upstream
)
all_ok=true
for upstream in "${UPSTREAM_CHECKS[@]}"; do
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$upstream")
if [ "$code" = "000" ]; then
echo "$(date): Cannot reach upstream $upstream (connection refused — sidecar down?)" >> /var/log/consul-e2e.log
all_ok=false
fi
done
$all_ok && curl -s "$HEARTBEAT_URL" --max-time 10
A connection refused on a local upstream port means the Envoy sidecar for that service has crashed. Create a Heartbeat monitor with 2-minute interval.
Step 6: Monitor Consul DNS resolution
Service discovery depends on Consul DNS. Test that .consul addresses resolve correctly:
#!/bin/bash
# consul-dns-probe.sh
HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_DNS_HEARTBEAT"
# Critical services to resolve via Consul DNS
SERVICES=(
"api.service.consul"
"database.service.consul"
"worker.service.consul"
)
all_ok=true
for svc in "${SERVICES[@]}"; do
if ! dig @127.0.0.1 -p 8600 "$svc" +short +time=3 | grep -q '^[0-9]'; then
echo "$(date): DNS resolution failed for $svc" >> /var/log/consul-dns.log
all_ok=false
fi
done
$all_ok && curl -s "$HEARTBEAT_URL" --max-time 10
Schedule every 2 minutes. Name the heartbeat monitor Consul DNS Health.
Step 7: Configure alerting and escalation
Structure Consul Connect alerts by layer:
- Consul Leader (HTTP monitor) — immediate; no leader blocks all control-plane operations
- Cluster Health (Heartbeat) — immediate; peer loss risks quorum failure
- Service Health (Heartbeat) — 2-minute delay; transient check failures are normal during deploys
- CA Health (Heartbeat) — 1-hour delay; cert expiry warning has lead time
- E2E Connect Proxy — immediate; sidecar down = mTLS broken for that service
- DNS Health — 5-minute delay; brief DNS hiccups are tolerable
In Vigilmon: Alert Channels → Add Channel → PagerDuty for Consul Leader and E2E Proxy monitors. Slack (#consul-ops) for service health and DNS.
Step 8: Build a service mesh status page
Give your platform team a consolidated view of mesh health:
- Status Pages → New Status Page
- Name:
Consul Connect Service Mesh - Add: Consul Leader, Cluster Health, Service Health, CA Health, E2E Connect Proxy, DNS Health
- Organize into component groups:
Control Plane,Services,mTLS - Share with your on-call rotation
Complete monitoring reference
| Monitor | Type | What it catches | |---------|------|-----------------| | Consul Leader | HTTP | No Raft leader, quorum failure | | Cluster Health | Heartbeat | Peer count below threshold | | Service Health | Heartbeat | Critical Consul health checks | | CA Health | Heartbeat | Root CA expiry, rotation failure | | E2E Connect Proxy | Heartbeat | Envoy sidecar crashes | | DNS Health | Heartbeat | Consul DNS resolution failure |
Troubleshooting common Consul Connect failures
- No Raft leader — run
consul operator raft list-peerson each server; identify which servers can't reach the others. Check network partitioning and firewall rules between server nodes. Common fix: restart the minority partition's Consul servers. - Service health check critical — run
consul health service <name>to see which instances and which checks are failing; then inspect the specific service's logs and the Envoy sidecar logs (journalctl -u consul-envoy-<service>ordocker logs). - mTLS connection refused on upstream port — the Envoy sidecar for that upstream crashed; restart it:
systemctl restart consul-envoy-<service>. If it keeps crashing, check the xDS configuration:consul connect proxy -service <name> -log-level debug. - DNS resolution failing — verify Consul DNS is listening:
dig @127.0.0.1 -p 8600 consul.service.consul; if that fails, the Consul agent on that host is down or the DNS port is blocked. Checkconsul membersto verify the local agent is in the cluster. - CA rotation failure — if leaf cert TTLs expire before rotation, all mTLS traffic fails. Force rotation via the API:
curl -X PUT http://localhost:8500/v1/connect/ca/configuration -d '{"Provider":"consul","Config":{}}'. This triggers immediate re-issuance of all leaf certs.
Next steps
- Prometheus integration — Consul exposes metrics at
/v1/agent/metrics?format=prometheus; pair with Grafana for trend analysis alongside your Vigilmon uptime checks - Intention audit — script a periodic export of
consul intention listand diff against a known-good baseline to detect unauthorized policy changes
Start monitoring your Consul Connect service mesh today at vigilmon.online — free, no credit card required.