HAProxy config,
rendered from your templates.
HAPTIC — the HAProxy Template Ingress Controller — is an open-source Kubernetes controller that builds your HAProxy config from templates you control. Watch Ingress, the Gateway API, or any custom resource, and shape the generated config exactly the way you want it.
{% for _, ingress := range resources.ingresses.List() %} backend {{ ingress.metadata.name }} balance roundrobin {{ render "servers" }} {% end %}
backend echo balance roundrobin server ep-0 10.42.0.7:8080 check server ep-1 10.42.0.9:8080 check
$ haptic --features
No Upstream Waiting
Add an annotation, a header rewrite, or support for a new API by editing a template — not by forking the controller or waiting for an upstream release.
You Own Every Line
Scriggo — a fast, Go-native template engine — renders the exact
haproxy.cfg you want. No magic translation layer; every
line is yours to tune, extend, or override.
Watch Any Resource
Resource-agnostic by design: point HAPTIC at any Kubernetes kind — even a CRD you defined — with no per-resource controller code.
Validated Before Rollout
A validating webhook and CI-runnable template tests catch bad config before it ships — then it's applied via the Dataplane API with hitless reloads.
If you own every line, are you maintaining a config fork forever?
No — you don't start from a blank file. Bundled libraries render classic Ingress and the Gateway API out of the box, and read existing annotations from ingress-nginx, HAProxy Technologies' kubernetes-ingress, and the community haproxy-ingress. Much of a current setup migrates by pointing HAPTIC at the Ingresses you already run — you only template the gap, a few lines in HAPTIC's config, not a fork you rebase.
$ haptic --extend
Need something the bundled libraries don't ship — say an
X-Request-ID header your platform users opt into per Ingress? Drop a
snippet into the HAProxyTemplateConfig
HAPTIC watches. No controller fork, no waiting for a release.
apiVersion: haproxy-haptic.org/v1alpha1
kind: HAProxyTemplateConfig
metadata:
name: haptic
spec:
# bundled libraries already cover Ingress and the Gateway API — you add:
templateSnippets:
frontend-filters-300-request-id:
template: |
{%- for _, ingress := range resources.ingresses.List() %}
{%- var header = fallback(ingress.metadata.annotations["example.com/request-id-header"], "") %}
{%- if header != "" %}
http-request set-header {{ header }} %[uuid()]
{%- end %}
{%- end %}
Any Ingress opts in:
example.com/request-id-header: "X-Request-ID"
$ haptic --install
$ helm install \
haptic oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--version 0.1.0
$ kubectl get haproxytemplateconfig
$ haptic --docs
Controller
How the ingress controller works: resource watching, template rendering, configuration validation, and HAProxy deployment.
Available versions
Helm Chart
Installs the controller into your cluster with preconfigured templates. Start here if you already know the basics or just want to deploy.
Available versions
// Built for operators who'd rather write a template than file a feature request.
Community project — independent and not affiliated with or endorsed by HAProxy Technologies.