Contour is a Kubernetes ingress controller built on Envoy Proxy that introduces HTTPProxy objects for safer, multi-team ingress configuration. It replaces the limitations of the Ingress resource with namespace delegation, per-route TLS, and fine-grained traffic policies. But Contour doesn't monitor itself — when the Envoy data plane crashes, when Contour's control plane stops reconciling, or when a TLS certificate expires, your team finds out from users. Vigilmon adds the external uptime layer that catches ingress failures from the outside: HTTP checks for routed services, SSL expiry alerts, and heartbeat monitors for certificate renewal pipelines.
What You'll Set Up
- External HTTP uptime monitors for services routed through Contour
- SSL certificate expiry alerts for Contour TLS termination
- Heartbeat monitoring for cert-manager certificate renewals
- TCP port monitoring for the Envoy proxy LoadBalancer
Prerequisites
- Contour 1.27+ installed on a Kubernetes cluster (
kubectl get httpproxies) - At least one
HTTPProxyrouting traffic to a backend service - A free Vigilmon account
Step 1: Monitor Your HTTPProxy Endpoints
Contour's HTTPProxy objects define how external traffic reaches your services. Monitor the external URL of each critical HTTPProxy to confirm the full path — DNS, LoadBalancer, Envoy, and backend — is working:
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter the external URL of your service:
https://api.example.com/health. - Set Check interval to
1 minute. - Set Expected HTTP status to
200. - Click Save.
This external check catches failures that Kubernetes readiness probes miss: a misconfigured HTTPProxy, a broken certificate, a LoadBalancer IP that changed, or an Envoy worker that stopped routing.
Repeat for each HTTPProxy that serves production traffic.
Step 2: Add Health Endpoints to Backend Services
For Vigilmon to verify the backend and not just the Envoy layer, expose a /health route in each service and route it through Contour:
# HTTPProxy with health check route
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: api-proxy
namespace: production
spec:
virtualhost:
fqdn: api.example.com
tls:
secretName: api-tls
routes:
- conditions:
- prefix: /health
services:
- name: api-service
port: 8080
- conditions:
- prefix: /
services:
- name: api-service
port: 8080
Add a minimal health handler to your service:
# FastAPI example
@app.get("/health")
def health():
return {"status": "ok", "uptime": time.monotonic()}
// Go example
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ok"}`))
})
Now the Vigilmon probe at https://api.example.com/health traverses Contour's full data path and verifies the backend in one check.
Step 3: TCP Port Monitoring for the Envoy LoadBalancer
Contour deploys Envoy as a LoadBalancer service (or a NodePort if you're using a bare-metal setup). Monitor the underlying TCP port to detect failures before HTTP-level checks fire:
- Click Add Monitor in Vigilmon.
- Set Type to
TCP. - Enter the LoadBalancer IP or hostname and port:
<EXTERNAL-IP>:443. - Set Check interval to
1 minute. - Click Save.
Get the external IP:
kubectl get svc envoy -n projectcontour
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# envoy LoadBalancer 10.96.1.1 203.0.113.10 80:31234/TCP,443:31235/TCP
Add monitors for both port 80 and port 443. A TCP failure when HTTP is responding usually means a LoadBalancer health check misconfiguration. A TCP failure when HTTP is also failing confirms the Envoy Pod is down.
Step 4: SSL Certificate Expiry Alerts
Contour supports TLS termination using Kubernetes Secrets referenced in HTTPProxy virtualhost.tls sections. Add SSL monitoring for each TLS-enabled virtual host:
- Open the HTTP / HTTPS monitor for your endpoint (from Step 1).
- Enable Monitor SSL certificate.
- Set Alert when certificate expires in less than
21 days. - Click Save.
For virtual hosts that use Contour's TLSCertificateDelegation to share certificates across namespaces, verify that each namespace's monitors cover the delegated certificate:
# TLSCertificateDelegation sharing a cert across namespaces
apiVersion: projectcontour.io/v1
kind: TLSCertificateDelegation
metadata:
name: tls-delegation
namespace: cert-team
spec:
delegations:
- secretName: wildcard-tls
targetNamespaces:
- production
- staging
Add one Vigilmon SSL monitor for each hostname that uses the delegated certificate so expiry is caught regardless of which namespace triggers it.
Step 5: Heartbeat Monitor for cert-manager Renewals
Contour integrates tightly with cert-manager for automatic certificate provisioning. Monitor the renewal pipeline with a Kubernetes CronJob that pings Vigilmon after confirming certificate freshness:
apiVersion: batch/v1
kind: CronJob
metadata:
name: contour-cert-heartbeat
namespace: production
spec:
schedule: "0 */6 * * *"
jobTemplate:
spec:
template:
spec:
serviceAccountName: cert-checker
containers:
- name: check
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
# Verify the TLS secret exists and is recent
kubectl get secret api-tls -n production -o name || exit 1
# Confirm certificate is not expiring within 30 days
EXPIRY=$(kubectl get secret api-tls -n production \
-o jsonpath='{.data.tls\.crt}' \
| base64 -d \
| openssl x509 -noout -checkend 2592000 2>&1)
echo "$EXPIRY"
# Ping Vigilmon heartbeat
wget -q -O- https://vigilmon.online/heartbeat/abc123
restartPolicy: OnFailure
Set the Vigilmon heartbeat interval to 7 hours. Two missed runs (14 hours) trigger an alert — enough lead time to investigate before a certificate expires.
Step 6: Monitor Contour's Status API
Contour exposes a status API on each HTTPProxy object. While you can't hit this from Vigilmon directly, you can build a lightweight probe service that checks proxy status and exposes a public health endpoint:
#!/bin/bash
# Check all HTTPProxy resources are valid (not in error state)
INVALID=$(kubectl get httpproxies --all-namespaces -o json \
| jq '[.items[] | select(.status.currentStatus != "valid")] | length')
if [ "$INVALID" -gt 0 ]; then
echo "ERROR: $INVALID HTTPProxy resources are not valid"
exit 1
fi
echo "All HTTPProxy resources are valid"
curl -s https://vigilmon.online/heartbeat/def456
Run this as a Kubernetes CronJob every 5 minutes with a Vigilmon heartbeat interval of 10 minutes. An invalid HTTPProxy — caused by a missing backend service, a TLS reference error, or a conflicting route — gets caught before it causes visible downtime.
Step 7: Configure Alert Channels
- Go to Alert Channels in Vigilmon and add Slack, email, or a webhook.
- For external endpoint monitors, set Consecutive failures before alert to
2— Contour rolling restarts can cause a single probe to fail. - For SSL monitors, set it to
1— a failed TLS handshake is always actionable. - For heartbeat monitors, set it to
1— a missed cert check warrants immediate investigation. - Use Maintenance windows in Vigilmon during Contour upgrades to suppress expected restart noise.
Summary
| Monitor | Target | What It Catches |
|---|---|---|
| HTTPProxy endpoint | https://api.example.com/health | Data plane failure, route misconfiguration |
| TCP port | <LB-IP>:443 | Envoy Pod down, LoadBalancer failure |
| SSL certificate | Each virtual host hostname | cert-manager failure, manual cert expiry |
| cert-manager heartbeat | CronJob ping | Renewal pipeline failure, ACME challenge issue |
| HTTPProxy status | CronJob + Vigilmon heartbeat | Invalid proxy objects causing silent routing errors |
Contour gives you expressive, namespace-safe ingress routing — Vigilmon gives you the external perspective that confirms it's working from your users' point of view. Together they close the gap between "the HTTPProxy is valid" and "requests are actually getting through."