Merge pull request #81 from byjg/fastcgi-pass-headers
Some checks failed
Docker / Test (push) Has been cancelled
Docker / Tests-E2E-Docker (push) Has been cancelled
Docker / Tests-E2E-Kubernetes (push) Has been cancelled
Docker / Tests-E2E-Additional (push) Has been cancelled
Docker / Tests-E2E-Swarm (push) Has been cancelled
Docker / Build (push) Has been cancelled
Docker / Publish-PyPI (push) Has been cancelled
Docker / Helm (push) Has been cancelled
Docker / HelmDeploy (push) Has been cancelled
Docker / Documentation (push) Has been cancelled
Some checks failed
Docker / Test (push) Has been cancelled
Docker / Tests-E2E-Docker (push) Has been cancelled
Docker / Tests-E2E-Kubernetes (push) Has been cancelled
Docker / Tests-E2E-Additional (push) Has been cancelled
Docker / Tests-E2E-Swarm (push) Has been cancelled
Docker / Build (push) Has been cancelled
Docker / Publish-PyPI (push) Has been cancelled
Docker / Helm (push) Has been cancelled
Docker / HelmDeploy (push) Has been cancelled
Docker / Documentation (push) Has been cancelled
Add enhancements to FastCGI plugin and Helm chart
This commit is contained in:
commit
8bd9f06f12
26 changed files with 351 additions and 79 deletions
|
|
@ -54,7 +54,7 @@ EasyHAProxy follows [Semantic Versioning](https://semver.org/):
|
||||||
- **MINOR**: New features, plugin additions, backward-compatible changes
|
- **MINOR**: New features, plugin additions, backward-compatible changes
|
||||||
- **PATCH**: Bug fixes, documentation updates, minor improvements
|
- **PATCH**: Bug fixes, documentation updates, minor improvements
|
||||||
|
|
||||||
**Current Version:** `6.1.0` (as of Chart.yaml)
|
**Current Version:** `6.1.1` (as of Chart.yaml)
|
||||||
|
|
||||||
## Automated Release (Recommended)
|
## Automated Release (Recommended)
|
||||||
|
|
||||||
|
|
@ -329,6 +329,7 @@ helm show chart byjg/easyhaproxy
|
||||||
|
|
||||||
| Version | Release Date | Type | Highlights |
|
| Version | Release Date | Type | Highlights |
|
||||||
|---------|--------------|-------|---------------------------------------------------------------------------------------------------------------------------------------|
|
|---------|--------------|-------|---------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| 6.1.1 | 2026-06-25 | Patch | Add pass_headers support to FastCGI plugin, fix flaky ACME e2e test timeout |
|
||||||
| 6.1.0 | 2026-06-24 | Minor | FastCGI protocol support, certbot sidecar plugin, dependency updates |
|
| 6.1.0 | 2026-06-24 | Minor | FastCGI protocol support, certbot sidecar plugin, dependency updates |
|
||||||
| 6.0.1 | 2026-02-23 | Patch | HAProxy dashboard, real-time monitoring dashboard with live traffic charts, ACME e2e test fixes |
|
| 6.0.1 | 2026-02-23 | Patch | HAProxy dashboard, real-time monitoring dashboard with live traffic charts, ACME e2e test fixes |
|
||||||
| 6.0.0 | 2026-XX-XX | Major | Python module refactoring (one-class-per-file), IngressClassName support (spec.ingressClassName + deprecated annotation fallback), modernized build system (uv/pyproject.toml), improved version management and release tooling, GitHub Actions workflow_dispatch push control |
|
| 6.0.0 | 2026-XX-XX | Major | Python module refactoring (one-class-per-file), IngressClassName support (spec.ingressClassName + deprecated annotation fallback), modernized build system (uv/pyproject.toml), improved version management and release tooling, GitHub Actions workflow_dispatch push control |
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
services:
|
services:
|
||||||
easyhaproxy:
|
easyhaproxy:
|
||||||
image: byjg/easy-haproxy:6.1.0
|
image: byjg/easy-haproxy:6.1.1
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- certs_certbot:/etc/easyhaproxy/certs/certbot
|
- certs_certbot:/etc/easyhaproxy/certs/certbot
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
---
|
---
|
||||||
# Source: easyhaproxy/templates/clusterrole.yaml
|
# Source: easyhaproxy/templates/clusterrole.yaml
|
||||||
|
|
@ -19,10 +19,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
|
|
@ -83,10 +83,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
@ -105,10 +105,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
annotations:
|
annotations:
|
||||||
{}
|
{}
|
||||||
|
|
@ -140,10 +140,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
|
@ -164,7 +164,7 @@ spec:
|
||||||
- name: easyhaproxy
|
- name: easyhaproxy
|
||||||
securityContext:
|
securityContext:
|
||||||
{}
|
{}
|
||||||
image: "byjg/easy-haproxy:6.1.0"
|
image: "byjg/easy-haproxy:6.1.1"
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
|
|
@ -217,10 +217,10 @@ kind: IngressClass
|
||||||
metadata:
|
metadata:
|
||||||
name: easyhaproxy
|
name: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
spec:
|
spec:
|
||||||
controller: byjg.com/easyhaproxy
|
controller: byjg.com/easyhaproxy
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
---
|
---
|
||||||
# Source: easyhaproxy/templates/clusterrole.yaml
|
# Source: easyhaproxy/templates/clusterrole.yaml
|
||||||
|
|
@ -19,10 +19,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
|
|
@ -83,10 +83,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
@ -104,10 +104,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
|
|
@ -136,7 +136,7 @@ spec:
|
||||||
- name: easyhaproxy
|
- name: easyhaproxy
|
||||||
securityContext:
|
securityContext:
|
||||||
{}
|
{}
|
||||||
image: "byjg/easy-haproxy:6.1.0"
|
image: "byjg/easy-haproxy:6.1.1"
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
|
|
@ -189,10 +189,10 @@ kind: IngressClass
|
||||||
metadata:
|
metadata:
|
||||||
name: easyhaproxy
|
name: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
spec:
|
spec:
|
||||||
controller: byjg.com/easyhaproxy
|
controller: byjg.com/easyhaproxy
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
---
|
---
|
||||||
# Source: easyhaproxy/templates/clusterrole.yaml
|
# Source: easyhaproxy/templates/clusterrole.yaml
|
||||||
|
|
@ -19,10 +19,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
|
|
@ -83,10 +83,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
@ -105,10 +105,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
annotations:
|
annotations:
|
||||||
{}
|
{}
|
||||||
|
|
@ -140,10 +140,10 @@ metadata:
|
||||||
name: ingress-easyhaproxy
|
name: ingress-easyhaproxy
|
||||||
namespace: easyhaproxy
|
namespace: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
|
@ -164,7 +164,7 @@ spec:
|
||||||
- name: easyhaproxy
|
- name: easyhaproxy
|
||||||
securityContext:
|
securityContext:
|
||||||
{}
|
{}
|
||||||
image: "byjg/easy-haproxy:6.1.0"
|
image: "byjg/easy-haproxy:6.1.1"
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
|
|
@ -217,10 +217,10 @@ kind: IngressClass
|
||||||
metadata:
|
metadata:
|
||||||
name: easyhaproxy
|
name: easyhaproxy
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: easyhaproxy-2.0.3
|
helm.sh/chart: easyhaproxy-2.0.4
|
||||||
app.kubernetes.io/name: easyhaproxy
|
app.kubernetes.io/name: easyhaproxy
|
||||||
app.kubernetes.io/instance: ingress
|
app.kubernetes.io/instance: ingress
|
||||||
app.kubernetes.io/version: "6.1.0"
|
app.kubernetes.io/version: "6.1.1"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
spec:
|
spec:
|
||||||
controller: byjg.com/easyhaproxy
|
controller: byjg.com/easyhaproxy
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ Exposes HAProxy on NodePort `31080` (HTTP), `31443` (HTTPS), and `31936` (stats)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f \
|
kubectl apply -f \
|
||||||
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-nodeport.yml
|
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-nodeport.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
### ClusterIP (behind a LoadBalancer)
|
### ClusterIP (behind a LoadBalancer)
|
||||||
|
|
@ -50,7 +50,7 @@ Cluster-internal only. Pair with an external cloud LoadBalancer or `kubectl port
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f \
|
kubectl apply -f \
|
||||||
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-clusterip.yml
|
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-clusterip.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
### DaemonSet (special cases — requires node label)
|
### DaemonSet (special cases — requires node label)
|
||||||
|
|
@ -64,7 +64,7 @@ The node label must be reapplied after any node replacement. Failing to do so wi
|
||||||
kubectl label nodes node-01 "easyhaproxy/node=master"
|
kubectl label nodes node-01 "easyhaproxy/node=master"
|
||||||
|
|
||||||
kubectl apply -f \
|
kubectl apply -f \
|
||||||
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need to configure environment variables (log levels, stats password, etc.), see the [environment variable reference](../reference/environment-variables.md).
|
If you need to configure environment variables (log levels, stats password, etc.), see the [environment variable reference](../reference/environment-variables.md).
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ docker network create -d overlay --attachable easyhaproxy
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
haproxy:
|
haproxy:
|
||||||
image: byjg/easy-haproxy:6.1.0
|
image: byjg/easy-haproxy:6.1.1
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
deploy:
|
deploy:
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ Here's a complete `docker-compose.yml` showing proper ACME configuration:
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
easyhaproxy:
|
easyhaproxy:
|
||||||
image: byjg/easy-haproxy:6.1.0
|
image: byjg/easy-haproxy:6.1.1
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
# REQUIRED: Persist Certbot certificates (ACME)
|
# REQUIRED: Persist Certbot certificates (ACME)
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ docker cp single.pem easyhaproxy:/etc/easyhaproxy/certs/haproxy/example.com.pem
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
easyhaproxy:
|
easyhaproxy:
|
||||||
image: byjg/easy-haproxy:6.1.0
|
image: byjg/easy-haproxy:6.1.1
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- certs_haproxy:/etc/easyhaproxy/certs/haproxy
|
- certs_haproxy:/etc/easyhaproxy/certs/haproxy
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,56 @@ Automatically generates HAProxy `fcgi-app` configuration that defines required C
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
| Option | Description | Default |
|
| Option | Description | Default |
|
||||||
|-------------------|-----------------------------------------|------------------------------------|
|
|-------------------|--------------------------------------------|--------------------------------------|
|
||||||
| `enabled` | Enable/disable plugin | `true` |
|
| `enabled` | Enable/disable plugin | `true` |
|
||||||
| `document_root` | Document root path | `/var/www/html` |
|
| `document_root` | Document root path | `/var/www/html` |
|
||||||
| `script_filename` | Custom pattern for SCRIPT_FILENAME | `%[path]` (uses HAProxy's default) |
|
| `script_filename` | Custom pattern for SCRIPT_FILENAME | `%[path]` (uses HAProxy's default) |
|
||||||
| `index_file` | Default index file | `index.php` |
|
| `index_file` | Default index file | `index.php` |
|
||||||
| `path_info` | Enable PATH_INFO support | `true` |
|
| `path_info` | PATH_INFO preset or custom regex | `php` |
|
||||||
|
| `log_stderr` | Forward FastCGI stderr to HAProxy logs | `false` |
|
||||||
|
| `keep_conn` | Reuse FastCGI connections between requests | `true` |
|
||||||
| `custom_params` | Dictionary of custom FastCGI parameters | (optional) |
|
| `custom_params` | Dictionary of custom FastCGI parameters | (optional) |
|
||||||
|
| `pass_headers` | HTTP headers to forward to the FastCGI app | (optional) |
|
||||||
|
|
||||||
|
### `path_info` — PATH_INFO Presets
|
||||||
|
|
||||||
|
The `path_info` option accepts a preset name or a custom regex. Built-in presets:
|
||||||
|
|
||||||
|
| Preset | Language | Regex |
|
||||||
|
|----------|----------------|---------------------------------|
|
||||||
|
| `php` | PHP (default) | `^(/.+\.php)(/.*)?$` |
|
||||||
|
| `python` | Python FastCGI | `^(/.+\.py)(/.*)?$` |
|
||||||
|
| `perl` | Perl/CGI | `^(/.+\.(pl\|cgi))(/.*)?$` |
|
||||||
|
| `ruby` | Ruby FastCGI | `^(/.+\.rb)(/.*)?$` |
|
||||||
|
| `any` | Generic | `^(.+?)(/.*)?$` |
|
||||||
|
|
||||||
|
Pass `false` to disable PATH_INFO entirely, or any other string to use it as a custom regex directly.
|
||||||
|
|
||||||
|
Setting `path_info: true` maps to `php` for backward compatibility.
|
||||||
|
|
||||||
|
### `pass_headers` — Forwarding HTTP Headers
|
||||||
|
|
||||||
|
:::important
|
||||||
|
HAProxy strips `Authorization`, `Proxy-Authorization`, and all hop-by-hop headers before forwarding requests to the FastCGI backend. Applications that rely on these headers (e.g. APIs using Bearer tokens, Basic auth, or JWT) will fail silently without this option.
|
||||||
|
:::
|
||||||
|
|
||||||
|
`pass_headers` accepts a comma-separated string or a list of strings/dicts:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Simple — single header
|
||||||
|
pass_headers: "Authorization"
|
||||||
|
|
||||||
|
# Multiple — comma-separated
|
||||||
|
pass_headers: "Authorization, Proxy-Authorization"
|
||||||
|
|
||||||
|
# With ACL condition — list of dicts
|
||||||
|
pass_headers:
|
||||||
|
- Authorization
|
||||||
|
- name: X-Custom-Header
|
||||||
|
condition: "if { ssl_fc }"
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** `Content-Type` and `Content-Length` cannot be passed here — they are automatically converted to the CGI parameters `CONTENT_TYPE` and `CONTENT_LENGTH`.
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
|
|
@ -78,6 +121,7 @@ metadata:
|
||||||
easyhaproxy.plugin.fastcgi.document_root: "/var/www/html"
|
easyhaproxy.plugin.fastcgi.document_root: "/var/www/html"
|
||||||
easyhaproxy.plugin.fastcgi.index_file: "index.php"
|
easyhaproxy.plugin.fastcgi.index_file: "index.php"
|
||||||
easyhaproxy.plugin.fastcgi.script_filename: "/var/www/html/index.php"
|
easyhaproxy.plugin.fastcgi.script_filename: "/var/www/html/index.php"
|
||||||
|
easyhaproxy.plugin.fastcgi.pass_headers: "Authorization, Proxy-Authorization"
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: easyhaproxy
|
ingressClassName: easyhaproxy
|
||||||
rules:
|
rules:
|
||||||
|
|
@ -114,7 +158,7 @@ easymapping:
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
| Environment Variable | Config Key | Type | Default | Description |
|
| Environment Variable | Config Key | Type | Default | Description |
|
||||||
|----------------------------------------------|-------------------|----------|------------------------|---------------------------------------|
|
|----------------------------------------------|-------------------|----------|-------------------------|---------------------------------------|
|
||||||
| `EASYHAPROXY_PLUGIN_FASTCGI_ENABLED` | `enabled` | boolean | `true` | Enable/disable plugin for all domains |
|
| `EASYHAPROXY_PLUGIN_FASTCGI_ENABLED` | `enabled` | boolean | `true` | Enable/disable plugin for all domains |
|
||||||
| `EASYHAPROXY_PLUGIN_FASTCGI_DOCUMENT_ROOT` | `document_root` | string | `/var/www/html` | Document root path |
|
| `EASYHAPROXY_PLUGIN_FASTCGI_DOCUMENT_ROOT` | `document_root` | string | `/var/www/html` | Document root path |
|
||||||
| `EASYHAPROXY_PLUGIN_FASTCGI_SCRIPT_FILENAME` | `script_filename` | string | `%[path]` | Custom pattern for SCRIPT_FILENAME |
|
| `EASYHAPROXY_PLUGIN_FASTCGI_SCRIPT_FILENAME` | `script_filename` | string | `%[path]` | Custom pattern for SCRIPT_FILENAME |
|
||||||
|
|
@ -128,7 +172,10 @@ easymapping:
|
||||||
fcgi-app fcgi_phpapp_local
|
fcgi-app fcgi_phpapp_local
|
||||||
docroot /var/www/html
|
docroot /var/www/html
|
||||||
index index.php
|
index index.php
|
||||||
|
option keep-conn
|
||||||
path-info ^(/.+\.php)(/.*)?$
|
path-info ^(/.+\.php)(/.*)?$
|
||||||
|
pass-header Authorization
|
||||||
|
pass-header Proxy-Authorization
|
||||||
|
|
||||||
# Backend configuration (added to the backend section)
|
# Backend configuration (added to the backend section)
|
||||||
backend srv_phpapp_local_80
|
backend srv_phpapp_local_80
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,12 @@ type: application
|
||||||
# This is the chart version. This version number should be incremented each time you make changes
|
# This is the chart version. This version number should be incremented each time you make changes
|
||||||
# to the chart and its templates, including the app version.
|
# to the chart and its templates, including the app version.
|
||||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||||
version: 2.0.3
|
version: 2.0.4
|
||||||
|
|
||||||
# This is the version number of the application being deployed. This version number should be
|
# This is the version number of the application being deployed. This version number should be
|
||||||
# incremented each time you make changes to the application. Versions are not expected to
|
# incremented each time you make changes to the application. Versions are not expected to
|
||||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||||
# It is recommended to use it with quotes.
|
# It is recommended to use it with quotes.
|
||||||
appVersion: "6.1.0"
|
appVersion: "6.1.1"
|
||||||
|
|
||||||
icon: https://opensource.byjg.com/img/easy_haproxy_logo.png
|
icon: https://opensource.byjg.com/img/easy_haproxy_logo.png
|
||||||
|
|
|
||||||
|
|
@ -99,3 +99,6 @@ spec:
|
||||||
{{- end }}
|
{{- end }}
|
||||||
- name: EASYHAPROXY_STATUS_UPDATE_INTERVAL
|
- name: EASYHAPROXY_STATUS_UPDATE_INTERVAL
|
||||||
value: {{ .Values.ingressStatus.updateInterval | quote }}
|
value: {{ .Values.ingressStatus.updateInterval | quote }}
|
||||||
|
{{- with .Values.extraEnv }}
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
|
|
||||||
|
|
@ -98,3 +98,15 @@ masterNode:
|
||||||
label: easyhaproxy/node
|
label: easyhaproxy/node
|
||||||
values:
|
values:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
|
# Extra environment variables to inject into the container
|
||||||
|
# Supports all Kubernetes env var forms: value, valueFrom (secretKeyRef, configMapKeyRef, fieldRef)
|
||||||
|
# extraEnv:
|
||||||
|
# - name: MY_VAR
|
||||||
|
# value: "my-value"
|
||||||
|
# - name: SECRET_VAR
|
||||||
|
# valueFrom:
|
||||||
|
# secretKeyRef:
|
||||||
|
# name: my-secret
|
||||||
|
# key: my-key
|
||||||
|
extraEnv: []
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "easyhaproxy"
|
name = "easyhaproxy"
|
||||||
version = "6.1.0"
|
version = "6.1.1"
|
||||||
description = "HAProxy label based routing with service discovery for Docker, Swarm, and Kubernetes"
|
description = "HAProxy label based routing with service discovery for Docker, Swarm, and Kubernetes"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = {file = "LICENSE"}
|
license = {file = "LICENSE"}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ Configuration:
|
||||||
- index_file: Default index file (default: index.php)
|
- index_file: Default index file (default: index.php)
|
||||||
- path_info: Enable PATH_INFO support (default: true)
|
- path_info: Enable PATH_INFO support (default: true)
|
||||||
- custom_params: Dictionary of custom FastCGI parameters (optional)
|
- custom_params: Dictionary of custom FastCGI parameters (optional)
|
||||||
|
- pass_headers: Headers to forward to the FastCGI app (optional).
|
||||||
|
Comma-separated string or list of strings/dicts with optional condition.
|
||||||
|
|
||||||
Example YAML config:
|
Example YAML config:
|
||||||
plugins:
|
plugins:
|
||||||
|
|
@ -34,6 +36,7 @@ Example Kubernetes Annotation:
|
||||||
easyhaproxy.plugins: "fastcgi"
|
easyhaproxy.plugins: "fastcgi"
|
||||||
easyhaproxy.plugin.fastcgi.document_root: /var/www/myapp
|
easyhaproxy.plugin.fastcgi.document_root: /var/www/myapp
|
||||||
easyhaproxy.plugin.fastcgi.index_file: index.php
|
easyhaproxy.plugin.fastcgi.index_file: index.php
|
||||||
|
easyhaproxy.plugin.fastcgi.pass_headers: "Authorization, Proxy-Authorization"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
@ -48,13 +51,25 @@ from plugins import PluginContext, PluginInterface, PluginResult, PluginType
|
||||||
class FastcgiPlugin(PluginInterface):
|
class FastcgiPlugin(PluginInterface):
|
||||||
"""Plugin to configure FastCGI parameters for PHP-FPM"""
|
"""Plugin to configure FastCGI parameters for PHP-FPM"""
|
||||||
|
|
||||||
|
# Built-in path-info regex presets
|
||||||
|
PATH_INFO_PRESETS = {
|
||||||
|
"php": r"^(/.+\.php)(/.*)?$",
|
||||||
|
"python": r"^(/.+\.py)(/.*)?$",
|
||||||
|
"perl": r"^(/.+\.(?:pl|cgi))(/.*)?$",
|
||||||
|
"ruby": r"^(/.+\.rb)(/.*)?$",
|
||||||
|
"any": r"^(.+?)(/.*)?$",
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
self.document_root = "/var/www/html"
|
self.document_root = "/var/www/html"
|
||||||
self.script_filename = "%[path]"
|
self.script_filename = "%[path]"
|
||||||
self.index_file = "index.php"
|
self.index_file = "index.php"
|
||||||
self.path_info = True
|
self.path_info = "php" # False | preset name | custom regex string
|
||||||
|
self.log_stderr = False
|
||||||
|
self.keep_conn = True
|
||||||
self.custom_params = {}
|
self.custom_params = {}
|
||||||
|
self.pass_headers = [] # list of {"name": str, "condition": str|None}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
|
|
@ -76,6 +91,29 @@ class FastcgiPlugin(PluginInterface):
|
||||||
- index_file: Default index file
|
- index_file: Default index file
|
||||||
- path_info: Enable PATH_INFO support
|
- path_info: Enable PATH_INFO support
|
||||||
- custom_params: Dictionary of custom FastCGI parameters
|
- custom_params: Dictionary of custom FastCGI parameters
|
||||||
|
- path_info: Enable PATH_INFO splitting. Accepts:
|
||||||
|
- False / "false" / "no" / "0": disabled
|
||||||
|
- "php" (default): ^(/.+[.]php)(/.*)?$
|
||||||
|
- "python": ^(/.+[.]py)(/.*)?$
|
||||||
|
- "perl": ^(/.+[.](pl|cgi))(/.*)?$
|
||||||
|
- "ruby": ^(/.+[.]rb)(/.*)?$
|
||||||
|
- "any": ^(.+?)(/.*)?$
|
||||||
|
- any other string: used as-is as the regex
|
||||||
|
- log_stderr: Forward FastCGI app's stderr to HAProxy logs (default: false)
|
||||||
|
- keep_conn: Reuse FastCGI connections between requests (default: true)
|
||||||
|
- pass_headers: Headers to forward to the FastCGI application.
|
||||||
|
HAProxy omits Authorization, Proxy-Authorization, and hop-by-hop headers
|
||||||
|
by default — this directive is required to pass them through.
|
||||||
|
Note: Content-Type and Content-Length are never passable here; they are
|
||||||
|
already converted to CGI parameters (CONTENT_TYPE, CONTENT_LENGTH).
|
||||||
|
|
||||||
|
Accepts a comma-separated string or a list of strings/dicts:
|
||||||
|
Simple: "Authorization"
|
||||||
|
Multiple: "Authorization, Proxy-Authorization"
|
||||||
|
With ACL: [{"name": "Authorization", "condition": "if { ssl_fc }"}]
|
||||||
|
|
||||||
|
HAProxy syntax: pass-header <name> [ { if | unless } <condition> ]
|
||||||
|
Ref: https://docs.haproxy.org/dev/configuration.html
|
||||||
"""
|
"""
|
||||||
if "enabled" in config:
|
if "enabled" in config:
|
||||||
self.enabled = str(config["enabled"]).lower() in ["true", "1", "yes"]
|
self.enabled = str(config["enabled"]).lower() in ["true", "1", "yes"]
|
||||||
|
|
@ -90,11 +128,40 @@ class FastcgiPlugin(PluginInterface):
|
||||||
self.index_file = config["index_file"]
|
self.index_file = config["index_file"]
|
||||||
|
|
||||||
if "path_info" in config:
|
if "path_info" in config:
|
||||||
self.path_info = str(config["path_info"]).lower() in ["true", "1", "yes"]
|
val = str(config["path_info"]).lower()
|
||||||
|
if val in ["false", "0", "no"]:
|
||||||
|
self.path_info = False
|
||||||
|
elif val in ["true", "1", "yes"]:
|
||||||
|
self.path_info = "php" # backward-compatible: true → php preset
|
||||||
|
else:
|
||||||
|
self.path_info = str(config["path_info"]) # preset name or custom regex
|
||||||
|
|
||||||
|
if "log_stderr" in config:
|
||||||
|
self.log_stderr = str(config["log_stderr"]).lower() in ["true", "1", "yes"]
|
||||||
|
|
||||||
|
if "keep_conn" in config:
|
||||||
|
self.keep_conn = str(config["keep_conn"]).lower() in ["true", "1", "yes"]
|
||||||
|
|
||||||
if "custom_params" in config:
|
if "custom_params" in config:
|
||||||
self.custom_params = config["custom_params"]
|
self.custom_params = config["custom_params"]
|
||||||
|
|
||||||
|
if "pass_headers" in config:
|
||||||
|
val = config["pass_headers"]
|
||||||
|
if isinstance(val, str):
|
||||||
|
self.pass_headers = [{"name": h.strip(), "condition": None}
|
||||||
|
for h in val.split(",") if h.strip()]
|
||||||
|
elif isinstance(val, list):
|
||||||
|
result = []
|
||||||
|
for item in val:
|
||||||
|
if isinstance(item, str):
|
||||||
|
result.append({"name": item.strip(), "condition": None})
|
||||||
|
elif isinstance(item, dict):
|
||||||
|
result.append({
|
||||||
|
"name": item["name"],
|
||||||
|
"condition": item.get("condition")
|
||||||
|
})
|
||||||
|
self.pass_headers = result
|
||||||
|
|
||||||
def process(self, context: PluginContext) -> PluginResult:
|
def process(self, context: PluginContext) -> PluginResult:
|
||||||
"""
|
"""
|
||||||
Process the plugin and generate FastCGI configuration
|
Process the plugin and generate FastCGI configuration
|
||||||
|
|
@ -121,9 +188,16 @@ class FastcgiPlugin(PluginInterface):
|
||||||
fcgi_app_lines.append(f" docroot {self.document_root}")
|
fcgi_app_lines.append(f" docroot {self.document_root}")
|
||||||
fcgi_app_lines.append(f" index {self.index_file}")
|
fcgi_app_lines.append(f" index {self.index_file}")
|
||||||
|
|
||||||
|
if self.log_stderr:
|
||||||
|
fcgi_app_lines.append(" log-stderr")
|
||||||
|
|
||||||
|
if self.keep_conn:
|
||||||
|
fcgi_app_lines.append(" option keep-conn")
|
||||||
|
|
||||||
# PATH_INFO support
|
# PATH_INFO support
|
||||||
if self.path_info:
|
if self.path_info:
|
||||||
fcgi_app_lines.append(" path-info ^(/.+\\.php)(/.*)?$")
|
regex = self.PATH_INFO_PRESETS.get(self.path_info, self.path_info)
|
||||||
|
fcgi_app_lines.append(f" path-info {regex}")
|
||||||
|
|
||||||
# Set SCRIPT_FILENAME if customized
|
# Set SCRIPT_FILENAME if customized
|
||||||
if self.script_filename and self.script_filename != "%[path]":
|
if self.script_filename and self.script_filename != "%[path]":
|
||||||
|
|
@ -134,6 +208,13 @@ class FastcgiPlugin(PluginInterface):
|
||||||
for param_name, param_value in self.custom_params.items():
|
for param_name, param_value in self.custom_params.items():
|
||||||
fcgi_app_lines.append(f" set-param {param_name.upper()} {param_value}")
|
fcgi_app_lines.append(f" set-param {param_name.upper()} {param_value}")
|
||||||
|
|
||||||
|
# Pass headers
|
||||||
|
for header in self.pass_headers:
|
||||||
|
line = f" pass-header {header['name']}"
|
||||||
|
if header.get("condition"):
|
||||||
|
line += f" {header['condition']}"
|
||||||
|
fcgi_app_lines.append(line)
|
||||||
|
|
||||||
fcgi_app_definition = "\n".join(fcgi_app_lines)
|
fcgi_app_definition = "\n".join(fcgi_app_lines)
|
||||||
|
|
||||||
# Build metadata
|
# Build metadata
|
||||||
|
|
@ -143,7 +224,10 @@ class FastcgiPlugin(PluginInterface):
|
||||||
"document_root": self.document_root,
|
"document_root": self.document_root,
|
||||||
"index_file": self.index_file,
|
"index_file": self.index_file,
|
||||||
"path_info": self.path_info,
|
"path_info": self.path_info,
|
||||||
"custom_params_count": len(self.custom_params)
|
"log_stderr": self.log_stderr,
|
||||||
|
"keep_conn": self.keep_conn,
|
||||||
|
"custom_params_count": len(self.custom_params),
|
||||||
|
"pass_headers_count": len(self.pass_headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
return PluginResult(
|
return PluginResult(
|
||||||
|
|
|
||||||
|
|
@ -950,8 +950,11 @@ class TestFastcgiPlugin:
|
||||||
assert plugin.enabled is True
|
assert plugin.enabled is True
|
||||||
assert plugin.document_root == "/var/www/html"
|
assert plugin.document_root == "/var/www/html"
|
||||||
assert plugin.index_file == "index.php"
|
assert plugin.index_file == "index.php"
|
||||||
assert plugin.path_info is True
|
assert plugin.path_info == "php"
|
||||||
|
assert plugin.log_stderr is False
|
||||||
|
assert plugin.keep_conn is True
|
||||||
assert plugin.custom_params == {}
|
assert plugin.custom_params == {}
|
||||||
|
assert plugin.pass_headers == []
|
||||||
|
|
||||||
def test_fastcgi_plugin_configuration(self):
|
def test_fastcgi_plugin_configuration(self):
|
||||||
"""Test plugin configuration"""
|
"""Test plugin configuration"""
|
||||||
|
|
@ -1046,6 +1049,128 @@ class TestFastcgiPlugin:
|
||||||
|
|
||||||
assert result.haproxy_config is None or result.haproxy_config == ""
|
assert result.haproxy_config is None or result.haproxy_config == ""
|
||||||
|
|
||||||
|
def test_fastcgi_plugin_pass_headers_string(self):
|
||||||
|
"""Test pass_headers parsed from comma-separated string"""
|
||||||
|
plugin = FastcgiPlugin()
|
||||||
|
plugin.configure({"pass_headers": "Authorization, Proxy-Authorization"})
|
||||||
|
|
||||||
|
assert plugin.pass_headers == [
|
||||||
|
{"name": "Authorization", "condition": None},
|
||||||
|
{"name": "Proxy-Authorization", "condition": None},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = PluginContext(
|
||||||
|
parsed_object={}, easymapping=[], container_env={},
|
||||||
|
domain="phpapp.local", port="80", host_config={}
|
||||||
|
)
|
||||||
|
result = plugin.process(context)
|
||||||
|
fcgi_app_def = result.global_configs[0]
|
||||||
|
|
||||||
|
assert "pass-header Authorization" in fcgi_app_def
|
||||||
|
assert "pass-header Proxy-Authorization" in fcgi_app_def
|
||||||
|
assert result.metadata["pass_headers_count"] == 2
|
||||||
|
|
||||||
|
def test_fastcgi_plugin_pass_headers_list(self):
|
||||||
|
"""Test pass_headers parsed from list of strings and dicts with condition"""
|
||||||
|
plugin = FastcgiPlugin()
|
||||||
|
plugin.configure({
|
||||||
|
"pass_headers": [
|
||||||
|
"Authorization",
|
||||||
|
{"name": "X-Custom-Header", "condition": "if { ssl_fc }"},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
assert plugin.pass_headers == [
|
||||||
|
{"name": "Authorization", "condition": None},
|
||||||
|
{"name": "X-Custom-Header", "condition": "if { ssl_fc }"},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = PluginContext(
|
||||||
|
parsed_object={}, easymapping=[], container_env={},
|
||||||
|
domain="phpapp.local", port="80", host_config={}
|
||||||
|
)
|
||||||
|
result = plugin.process(context)
|
||||||
|
fcgi_app_def = result.global_configs[0]
|
||||||
|
|
||||||
|
assert "pass-header Authorization" in fcgi_app_def
|
||||||
|
assert "pass-header X-Custom-Header if { ssl_fc }" in fcgi_app_def
|
||||||
|
assert result.metadata["pass_headers_count"] == 2
|
||||||
|
|
||||||
|
def test_fastcgi_plugin_log_stderr(self):
|
||||||
|
"""Test log-stderr directive is emitted when enabled"""
|
||||||
|
plugin = FastcgiPlugin()
|
||||||
|
plugin.configure({"log_stderr": "true"})
|
||||||
|
assert plugin.log_stderr is True
|
||||||
|
|
||||||
|
context = PluginContext(
|
||||||
|
parsed_object={}, easymapping=[], container_env={},
|
||||||
|
domain="phpapp.local", port="80", host_config={}
|
||||||
|
)
|
||||||
|
result = plugin.process(context)
|
||||||
|
assert "log-stderr" in result.global_configs[0]
|
||||||
|
assert result.metadata["log_stderr"] is True
|
||||||
|
|
||||||
|
def test_fastcgi_plugin_keep_conn_disabled(self):
|
||||||
|
"""Test option keep-conn is omitted when disabled"""
|
||||||
|
plugin = FastcgiPlugin()
|
||||||
|
plugin.configure({"keep_conn": "false"})
|
||||||
|
assert plugin.keep_conn is False
|
||||||
|
|
||||||
|
context = PluginContext(
|
||||||
|
parsed_object={}, easymapping=[], container_env={},
|
||||||
|
domain="phpapp.local", port="80", host_config={}
|
||||||
|
)
|
||||||
|
result = plugin.process(context)
|
||||||
|
assert "option keep-conn" not in result.global_configs[0]
|
||||||
|
assert result.metadata["keep_conn"] is False
|
||||||
|
|
||||||
|
def test_fastcgi_plugin_path_info_presets(self):
|
||||||
|
"""Test path_info presets resolve to correct regexes"""
|
||||||
|
presets = {
|
||||||
|
"php": r"^(/.+\.php)(/.*)?$",
|
||||||
|
"python": r"^(/.+\.py)(/.*)?$",
|
||||||
|
"perl": r"^(/.+\.(?:pl|cgi))(/.*)?$",
|
||||||
|
"ruby": r"^(/.+\.rb)(/.*)?$",
|
||||||
|
"any": r"^(.+?)(/.*)?$",
|
||||||
|
}
|
||||||
|
context = PluginContext(
|
||||||
|
parsed_object={}, easymapping=[], container_env={},
|
||||||
|
domain="phpapp.local", port="80", host_config={}
|
||||||
|
)
|
||||||
|
for preset, expected_regex in presets.items():
|
||||||
|
plugin = FastcgiPlugin()
|
||||||
|
plugin.configure({"path_info": preset})
|
||||||
|
assert plugin.path_info == preset
|
||||||
|
result = plugin.process(context)
|
||||||
|
assert f"path-info {expected_regex}" in result.global_configs[0], \
|
||||||
|
f"Preset '{preset}' did not emit expected regex"
|
||||||
|
|
||||||
|
def test_fastcgi_plugin_path_info_custom_regex(self):
|
||||||
|
"""Test path_info accepts a custom regex"""
|
||||||
|
plugin = FastcgiPlugin()
|
||||||
|
plugin.configure({"path_info": r"^(/.+\.fcgi)(/.*)?$"})
|
||||||
|
assert plugin.path_info == r"^(/.+\.fcgi)(/.*)?$"
|
||||||
|
|
||||||
|
context = PluginContext(
|
||||||
|
parsed_object={}, easymapping=[], container_env={},
|
||||||
|
domain="phpapp.local", port="80", host_config={}
|
||||||
|
)
|
||||||
|
result = plugin.process(context)
|
||||||
|
assert r"path-info ^(/.+\.fcgi)(/.*)?$" in result.global_configs[0]
|
||||||
|
|
||||||
|
def test_fastcgi_plugin_path_info_backward_compat(self):
|
||||||
|
"""Test path_info: true maps to php preset (backward compatibility)"""
|
||||||
|
plugin = FastcgiPlugin()
|
||||||
|
plugin.configure({"path_info": "true"})
|
||||||
|
assert plugin.path_info == "php"
|
||||||
|
|
||||||
|
context = PluginContext(
|
||||||
|
parsed_object={}, easymapping=[], container_env={},
|
||||||
|
domain="phpapp.local", port="80", host_config={}
|
||||||
|
)
|
||||||
|
result = plugin.process(context)
|
||||||
|
assert r"path-info ^(/.+\.php)(/.*)?$" in result.global_configs[0]
|
||||||
|
|
||||||
|
|
||||||
class TestPluginManager:
|
class TestPluginManager:
|
||||||
"""Test cases for PluginManager"""
|
"""Test cases for PluginManager"""
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
|
|
||||||
services:
|
services:
|
||||||
haproxy:
|
haproxy:
|
||||||
image: byjg/easy-haproxy:6.1.0
|
image: byjg/easy-haproxy:6.1.1
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
# Persist the CERTBOT to avoid re-challenge when the server restarts
|
# Persist the CERTBOT to avoid re-challenge when the server restarts
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
services:
|
services:
|
||||||
easyhaproxy:
|
easyhaproxy:
|
||||||
image: byjg/easy-haproxy:6.1.0
|
image: byjg/easy-haproxy:6.1.1
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- certs_certbot:/etc/easyhaproxy/certs/certbot
|
- certs_certbot:/etc/easyhaproxy/certs/certbot
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
# ```bash
|
# ```bash
|
||||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||||
# kubectl create namespace easyhaproxy
|
# kubectl create namespace easyhaproxy
|
||||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||||
#
|
#
|
||||||
# # 2. Download Cloudflare IP ranges
|
# # 2. Download Cloudflare IP ranges
|
||||||
# curl -s https://www.cloudflare.com/ips-v4 > cloudflare_ips.lst
|
# curl -s https://www.cloudflare.com/ips-v4 > cloudflare_ips.lst
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
# ```bash
|
# ```bash
|
||||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||||
# kubectl create namespace easyhaproxy
|
# kubectl create namespace easyhaproxy
|
||||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||||
#
|
#
|
||||||
# # 2. IMPORTANT: Edit this file (line 80) and update allowed_ips
|
# # 2. IMPORTANT: Edit this file (line 80) and update allowed_ips
|
||||||
# # with your actual office/VPN IP addresses or networks
|
# # with your actual office/VPN IP addresses or networks
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
# ```bash
|
# ```bash
|
||||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||||
# kubectl create namespace easyhaproxy
|
# kubectl create namespace easyhaproxy
|
||||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||||
#
|
#
|
||||||
# # 2. Generate RSA key pair (idempotent - skips if exists)
|
# # 2. Generate RSA key pair (idempotent - skips if exists)
|
||||||
# [ -f jwt_private.pem ] || openssl genrsa -out jwt_private.pem 2048
|
# [ -f jwt_private.pem ] || openssl genrsa -out jwt_private.pem 2048
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
# ```bash
|
# ```bash
|
||||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||||
# kubectl create namespace easyhaproxy
|
# kubectl create namespace easyhaproxy
|
||||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||||
#
|
#
|
||||||
# # 2. Generate JWT keys (idempotent - skips if exists)
|
# # 2. Generate JWT keys (idempotent - skips if exists)
|
||||||
# [ -f jwt_private.pem ] || openssl genrsa -out jwt_private.pem 2048
|
# [ -f jwt_private.pem ] || openssl genrsa -out jwt_private.pem 2048
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
# ```bash
|
# ```bash
|
||||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||||
# kubectl create namespace easyhaproxy
|
# kubectl create namespace easyhaproxy
|
||||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||||
#
|
#
|
||||||
# # 2. Label the node where EasyHAProxy will run
|
# # 2. Label the node where EasyHAProxy will run
|
||||||
# kubectl label nodes <node-name> "easyhaproxy/node=master"
|
# kubectl label nodes <node-name> "easyhaproxy/node=master"
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
# ```bash
|
# ```bash
|
||||||
# # 1. Ensure EasyHAProxy is installed in your cluster
|
# # 1. Ensure EasyHAProxy is installed in your cluster
|
||||||
# kubectl create namespace easyhaproxy
|
# kubectl create namespace easyhaproxy
|
||||||
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.0/deploy/kubernetes/easyhaproxy-daemonset.yml
|
# kubectl apply -f https://raw.githubusercontent.com/byjg/docker-easy-haproxy/6.1.1/deploy/kubernetes/easyhaproxy-daemonset.yml
|
||||||
#
|
#
|
||||||
# # 2. Label the node where EasyHAProxy will run
|
# # 2. Label the node where EasyHAProxy will run
|
||||||
# kubectl label nodes <node-name> "easyhaproxy/node=master"
|
# kubectl label nodes <node-name> "easyhaproxy/node=master"
|
||||||
|
|
|
||||||
|
|
@ -920,7 +920,7 @@ class TestACME:
|
||||||
"""Test that Pebble successfully issues a certificate"""
|
"""Test that Pebble successfully issues a certificate"""
|
||||||
# Wait for certificate issuance (Certbot runs in background loop)
|
# Wait for certificate issuance (Certbot runs in background loop)
|
||||||
# Typical time: 10-15 seconds from container start
|
# Typical time: 10-15 seconds from container start
|
||||||
max_retries = 30
|
max_retries = 60
|
||||||
check_interval = 1
|
check_interval = 1
|
||||||
has_success = False
|
has_success = False
|
||||||
|
|
||||||
|
|
|
||||||
2
uv.lock
generated
2
uv.lock
generated
|
|
@ -616,7 +616,7 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "easyhaproxy"
|
name = "easyhaproxy"
|
||||||
version = "6.1.0"
|
version = "6.1.1"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "deepdiff" },
|
{ name = "deepdiff" },
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue