Kubernetes
EasyHAProxy acts as an Ingress controller for Kubernetes — it watches Ingress resources with ingressClassName: easyhaproxy and configures HAProxy automatically.
EasyHAProxy queries all ingress definitions with either the
spec.ingressClassName: easyhaproxy field (recommended) or the deprecated annotation
kubernetes.io/ingress.class: easyhaproxy-ingress (for backward compatibility).
Deployment Modes
Choose the deployment mode that fits your infrastructure:
| Mode | Workload | Exposed Ports | Node Label | Recommended When |
|---|---|---|---|---|
| NodePort | Deployment | 31080 / 31443 / 31936 | No | Most setups (recommended) |
| ClusterIP | Deployment | cluster-internal only | No | Behind a LoadBalancer (recommended) |
| DaemonSet | DaemonSet | 80 / 443 / 1936 (host) | Yes | Bare-metal, special cases |
NodePort and ClusterIP run as a Deployment — no node label needed, and they survive node replacements safely.
DaemonSet binds to host ports and requires a node label (easyhaproxy/node=master) via nodeAffinity. The label must be manually reapplied after any node replacement, which can cause outages. Use only for bare-metal or special-case setups.
EasyHAProxy detects its deployment mode automatically (EASYHAPROXY_DEPLOYMENT_MODE=auto). See the environment variable reference for manual override options.
Step 1 — Install EasyHAProxy
kubectl create namespace easyhaproxy
NodePort (recommended)
Exposes HAProxy on NodePort 31080 (HTTP), 31443 (HTTPS), and 31936 (stats). Point your DNS or external load balancer to any node IP on these ports.
kubectl apply -f \
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.0.1/deploy/kubernetes/easyhaproxy-nodeport.yml
ClusterIP (behind a LoadBalancer)
Cluster-internal only. Pair with an external cloud LoadBalancer or kubectl port-forward for local testing.
kubectl apply -f \
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.0.1/deploy/kubernetes/easyhaproxy-clusterip.yml
DaemonSet (special cases — requires node label)
The node label must be reapplied after any node replacement. Failing to do so will cause an outage.
# Label the target node first
kubectl label nodes node-01 "easyhaproxy/node=master"
kubectl apply -f \
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.0.1/deploy/kubernetes/easyhaproxy-daemonset.yml
If you need to configure environment variables (log levels, stats password, etc.), see the environment variable reference.
Step 2 — Create an Ingress
kind: Ingress
metadata:
name: example-ingress
namespace: example
spec:
ingressClassName: easyhaproxy
rules:
- host: example.org
http:
paths:
- backend:
service:
name: example-service
port:
number: 8080
pathType: ImplementationSpecific
EasyHAProxy routes traffic from example.org:80 to your service at port 8080. No container port exposure needed.
The deprecated annotation kubernetes.io/ingress.class: easyhaproxy-ingress is still supported but spec.ingressClassName is recommended for new deployments.
Step 3 — Verify
curl http://example.org
Kubernetes Annotations
Customize EasyHAProxy behavior per-ingress using annotations. For the full annotations reference, see Container Labels — Kubernetes Ingress Annotations.
Important: Annotations apply to all hosts in the ingress configuration.
Using Plugins
Add the easyhaproxy.plugins annotation with a comma-separated list of plugin names:
metadata:
annotations:
easyhaproxy.plugins: "cloudflare,deny_pages"
easyhaproxy.plugin.deny_pages.paths: "/wp-admin,/wp-login.php"
easyhaproxy.plugin.deny_pages.status_code: "404"
For full plugin documentation, see the Using Plugins guide.
Loading Plugin Configuration from Kubernetes Secrets
EasyHAProxy supports loading sensitive plugin configuration values from Kubernetes Secrets using the k8s_secret pattern:
# Auto-detect key (tries common variations):
easyhaproxy.plugin.{plugin_name}.k8s_secret.{config_key}: "secret_name"
# Explicit key (no variations):
easyhaproxy.plugin.{plugin_name}.k8s_secret.{config_key}: "secret_name/key_name"
How It Works
- You create a Kubernetes Secret with your sensitive data
- You reference the secret in your ingress annotation using the
k8s_secretpattern - EasyHAProxy reads the secret from the same namespace as the ingress
- EasyHAProxy transforms the annotation to inject the secret value
- The plugin receives the value as if it was provided directly in the annotation
Complete Example
---
apiVersion: v1
kind: Secret
metadata:
name: jwt-pubkey-secret
namespace: production
type: Opaque
stringData:
pubkey: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
namespace: production
annotations:
easyhaproxy.plugins: "jwt_validator"
easyhaproxy.plugin.jwt_validator.algorithm: "RS256"
easyhaproxy.plugin.jwt_validator.issuer: "https://auth.example.com/"
easyhaproxy.plugin.jwt_validator.audience: "https://api.example.com"
easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "jwt-pubkey-secret"
spec:
ingressClassName: easyhaproxy
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
Priority Order
- Explicit annotation (e.g.,
easyhaproxy.plugin.jwt_validator.pubkey: "value") - k8s_secret annotation (e.g.,
easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "secret")
Security Considerations
- Secrets are read from the same namespace as the ingress (no cross-namespace access)
- EasyHAProxy needs RBAC permissions to read secrets (included in default deployment)
- Use Kubernetes RBAC to control which service accounts can read which secrets
ACME / Let's Encrypt
Add the easyhaproxy.certbot annotation to enable automatic certificate issuing:
kind: Ingress
metadata:
annotations:
easyhaproxy.certbot: 'true'
name: example-ingress
namespace: example
spec:
ingressClassName: easyhaproxy
More info in the ACME guide. Make sure ports 80 and 443 are publicly reachable.
Custom SSL Certificates
Create a secret with your certificate and key and associate it with your ingress:
---
apiVersion: v1
kind: Secret
metadata:
name: host2-tls
namespace: default
data:
tls.crt: base64 of your certificate
tls.key: base64 of your certificate private key
type: kubernetes.io/tls
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example
namespace: default
spec:
ingressClassName: easyhaproxy
tls:
- hosts:
- host2.local
secretName: host2-tls
rules:
...
Important Limitations
- The implementation doesn't support all ingress properties or wildcard domains.
- EasyHAProxy reads all
spec.rules[].hostvalues but parses only the first path per rule.