1
0
Fork 0

Add detailed plugin documentation for Cleanup, Cloudflare, Deny Pages, IP Whitelist, JWT Validator, and FastCGI plugins

- Added individual markdown files with examples, configuration options, and HAProxy outputs for each plugin.
- Updated `README.md` to link plugin-specific documentation.
- Enhanced `plugins.md` to summarize plugin features and usage.
- Included Docker, Kubernetes, Swarm, and static configuration examples for all plugins.
This commit is contained in:
Joao Gilberto Magalhaes 2025-12-01 13:36:11 -05:00
parent 883521e7e1
commit ae6eb1b55a
10 changed files with 2431 additions and 1317 deletions

View file

@ -42,368 +42,14 @@ Execute **once for each discovered domain/host**.
## Built-in Plugins
### Cloudflare Plugin (Domain)
Restores the original visitor IP address when requests come through Cloudflare's CDN.
**Why use it:** Cloudflare replaces the visitor's IP with its own. This plugin restores the original IP from the `CF-Connecting-IP` header.
**Configuration options:**
- `enabled` - Enable/disable plugin (default: `true`)
- `ip_list_path` - Path to Cloudflare IP list (default: `/etc/haproxy/cloudflare_ips.lst`)
**Enable via container label:**
```yaml
services:
myapp:
labels:
easyhaproxy.http.host: example.com
easyhaproxy.http.plugins: cloudflare
```
**Custom IP list path:**
```yaml
labels:
easyhaproxy.http.plugins: cloudflare
easyhaproxy.http.plugin.cloudflare.ip_list_path: /custom/path/cf_ips.lst
```
**HAProxy config generated:**
```
# Cloudflare - Restore original visitor IP
acl from_cloudflare src -f /etc/haproxy/cloudflare_ips.lst
http-request set-header X-Forwarded-For %[req.hdr(CF-Connecting-IP)] if from_cloudflare
```
**Required:** Download Cloudflare IP list from [Cloudflare documentation](https://support.cloudflare.com/hc/en-us/articles/200170786).
### Cleanup Plugin (Global)
Performs cleanup tasks during each discovery cycle, such as removing old temporary files.
**Why use it:** Prevents disk space issues by automatically cleaning up temporary files created by EasyHAProxy.
**Configuration options:**
- `enabled` - Enable/disable plugin (default: `true`)
- `max_idle_time` - Maximum age in seconds before deleting files (default: `300`)
- `cleanup_temp_files` - Enable temp file cleanup (default: `true`)
**Enable via YAML:**
```yaml
# /etc/haproxy/static/config.yaml
plugins:
enabled: [cleanup]
config:
cleanup:
max_idle_time: 600
cleanup_temp_files: true
```
**Enable via environment variable:**
```bash
EASYHAPROXY_PLUGINS_ENABLED=cleanup
EASYHAPROXY_PLUGIN_CLEANUP_MAX_IDLE_TIME=600
```
### Deny Pages Plugin (Domain)
Blocks access to specific paths for a domain, returning a configurable HTTP status code.
**Why use it:** Protect admin panels, internal APIs, or debugging endpoints from public access.
**Configuration options:**
- `enabled` - Enable/disable plugin (default: `true`)
- `paths` - Comma-separated list of paths to block (e.g., `/admin,/private`)
- `status_code` - HTTP status code to return (default: `403`)
**Enable via container label:**
```yaml
services:
webapp:
labels:
easyhaproxy.http.host: example.com
easyhaproxy.http.plugins: deny_pages
easyhaproxy.http.plugin.deny_pages.paths: /admin,/private,/debug
easyhaproxy.http.plugin.deny_pages.status_code: 404
```
**HAProxy config generated:**
```
# Deny Pages - Block specific paths
acl denied_path path_beg /admin /private /debug
http-request deny deny_status 404 if denied_path
```
### IP Whitelist Plugin (Domain)
Restricts access to a domain to only specific IP addresses or CIDR ranges.
**Why use it:** Restrict access to internal tools, admin panels, or staging environments to only trusted IP addresses.
**Configuration options:**
- `enabled` - Enable/disable plugin (default: `true`)
- `allowed_ips` - Comma-separated list of IPs/CIDR ranges to allow (e.g., `192.168.1.0/24,10.0.0.1`)
- `status_code` - HTTP status code to return for blocked IPs (default: `403`)
**Enable via container label:**
```yaml
services:
admin:
labels:
easyhaproxy.http.host: admin.example.com
easyhaproxy.http.plugins: ip_whitelist
easyhaproxy.http.plugin.ip_whitelist.allowed_ips: 192.168.1.0/24,10.0.0.5
easyhaproxy.http.plugin.ip_whitelist.status_code: 403
```
**HAProxy config generated:**
```
# IP Whitelist - Only allow specific IPs
acl whitelisted_ip src 192.168.1.0/24 10.0.0.5
http-request deny deny_status 403 if !whitelisted_ip
```
**Important:** This blocks ALL IPs except those in the whitelist. Make sure to include your own IP!
### JWT Validator Plugin (Domain)
Validates JWT (JSON Web Token) authentication tokens using HAProxy's built-in JWT functionality.
**Why use it:** Protect APIs and services with JWT authentication without needing application-level code.
**Configuration options:**
- `enabled` - Enable/disable plugin (default: `true`)
- `algorithm` - JWT signing algorithm (default: `RS256`)
- `issuer` - Expected JWT issuer (optional, set to `none`/`null` to skip validation)
- `audience` - Expected JWT audience (optional, set to `none`/`null` to skip validation)
- `pubkey_path` - Path to public key file (required if `pubkey` not provided)
- `pubkey` - Public key content as base64-encoded string (required if `pubkey_path` not provided)
- `paths` - List of paths that require JWT validation (optional, if not set ALL domain is protected)
- `only_paths` - If `true`, only specified paths are accessible; if `false` (default), only specified paths require JWT validation
**Path Validation Logic:**
- **No paths configured:** ALL requests to the domain require JWT validation (default behavior)
- **Paths configured + `only_paths=false`:** Only specified paths require JWT validation, other paths pass through without validation
- **Paths configured + `only_paths=true`:** Only specified paths are accessible (with JWT validation), all other paths are denied
**Enable via container label (protect all paths):**
```yaml
services:
api:
labels:
easyhaproxy.http.host: api.example.com
easyhaproxy.http.plugins: jwt_validator
easyhaproxy.http.plugin.jwt_validator.algorithm: RS256
easyhaproxy.http.plugin.jwt_validator.issuer: https://auth.example.com/
easyhaproxy.http.plugin.jwt_validator.audience: https://api.example.com
easyhaproxy.http.plugin.jwt_validator.pubkey_path: /etc/haproxy/jwt_keys/api_pubkey.pem
volumes:
- ./pubkey.pem:/etc/haproxy/jwt_keys/api_pubkey.pem:ro
```
**Protect specific paths only (others can pass without JWT):**
```yaml
labels:
easyhaproxy.http.plugins: jwt_validator
easyhaproxy.http.plugin.jwt_validator.pubkey_path: /etc/haproxy/jwt_keys/api_pubkey.pem
easyhaproxy.http.plugin.jwt_validator.paths: /api/admin,/api/sensitive
easyhaproxy.http.plugin.jwt_validator.only_paths: false
```
**Only allow specific paths (deny all others):**
```yaml
labels:
easyhaproxy.http.plugins: jwt_validator
easyhaproxy.http.plugin.jwt_validator.pubkey_path: /etc/haproxy/jwt_keys/api_pubkey.pem
easyhaproxy.http.plugin.jwt_validator.paths: /api/public,/api/v1
easyhaproxy.http.plugin.jwt_validator.only_paths: true
```
**Skip issuer/audience validation:**
```yaml
labels:
easyhaproxy.http.plugin.jwt_validator.issuer: none
easyhaproxy.http.plugin.jwt_validator.audience: none
easyhaproxy.http.plugin.jwt_validator.pubkey_path: /etc/haproxy/jwt_keys/api_pubkey.pem
```
**HAProxy config generated (all paths protected):**
```
# JWT Validator - Validate JWT tokens
http-request deny content-type 'text/html' string 'Missing Authorization HTTP header' unless { req.hdr(authorization) -m found }
# Extract JWT header and payload
http-request set-var(txn.alg) http_auth_bearer,jwt_header_query('$.alg')
http-request set-var(txn.iss) http_auth_bearer,jwt_payload_query('$.iss')
http-request set-var(txn.aud) http_auth_bearer,jwt_payload_query('$.aud')
http-request set-var(txn.exp) http_auth_bearer,jwt_payload_query('$.exp','int')
# Validate JWT
http-request deny content-type 'text/html' string 'Unsupported JWT signing algorithm' unless { var(txn.alg) -m str RS256 }
http-request deny content-type 'text/html' string 'Invalid JWT issuer' unless { var(txn.iss) -m str https://auth.example.com/ }
http-request deny content-type 'text/html' string 'Invalid JWT audience' unless { var(txn.aud) -m str https://api.example.com }
http-request deny content-type 'text/html' string 'Invalid JWT signature' unless { http_auth_bearer,jwt_verify(txn.alg,"/etc/haproxy/jwt_keys/api_pubkey.pem") -m int 1 }
# Validate expiration
http-request set-var(txn.now) date()
http-request deny content-type 'text/html' string 'JWT has expired' if { var(txn.exp),sub(txn.now) -m int lt 0 }
```
**HAProxy config generated (specific paths, only_paths=false):**
```
# JWT Validator - Validate JWT tokens
# Define paths that require JWT validation
acl jwt_protected_path path_beg /api/admin
acl jwt_protected_path path_beg /api/sensitive
http-request deny content-type 'text/html' string 'Missing Authorization HTTP header' unless { req.hdr(authorization) -m found } if jwt_protected_path
# Extract JWT header and payload
http-request set-var(txn.alg) http_auth_bearer,jwt_header_query('$.alg') if jwt_protected_path
http-request set-var(txn.iss) http_auth_bearer,jwt_payload_query('$.iss') if jwt_protected_path
http-request set-var(txn.aud) http_auth_bearer,jwt_payload_query('$.aud') if jwt_protected_path
http-request set-var(txn.exp) http_auth_bearer,jwt_payload_query('$.exp','int') if jwt_protected_path
# Validate JWT (only on protected paths)
http-request deny content-type 'text/html' string 'Unsupported JWT signing algorithm' unless { var(txn.alg) -m str RS256 } if jwt_protected_path
http-request deny content-type 'text/html' string 'Invalid JWT signature' unless { http_auth_bearer,jwt_verify(txn.alg,"/etc/haproxy/jwt_keys/api_pubkey.pem") -m int 1 } if jwt_protected_path
# Validate expiration
http-request set-var(txn.now) date() if jwt_protected_path
http-request deny content-type 'text/html' string 'JWT has expired' if { var(txn.exp),sub(txn.now) -m int lt 0 } if jwt_protected_path
```
**HAProxy config generated (specific paths, only_paths=true):**
```
# JWT Validator - Validate JWT tokens
# Define paths that require JWT validation
acl jwt_protected_path path_beg /api/public
acl jwt_protected_path path_beg /api/v1
# Deny access to paths not in the protected list
http-request deny content-type 'text/html' string 'Access denied' unless jwt_protected_path
http-request deny content-type 'text/html' string 'Missing Authorization HTTP header' unless { req.hdr(authorization) -m found }
# Extract JWT header and payload
http-request set-var(txn.alg) http_auth_bearer,jwt_header_query('$.alg')
http-request set-var(txn.iss) http_auth_bearer,jwt_payload_query('$.iss')
http-request set-var(txn.aud) http_auth_bearer,jwt_payload_query('$.aud')
http-request set-var(txn.exp) http_auth_bearer,jwt_payload_query('$.exp','int')
# Validate JWT (all requests at this point are on allowed paths)
http-request deny content-type 'text/html' string 'Unsupported JWT signing algorithm' unless { var(txn.alg) -m str RS256 }
http-request deny content-type 'text/html' string 'Invalid JWT signature' unless { http_auth_bearer,jwt_verify(txn.alg,"/etc/haproxy/jwt_keys/api_pubkey.pem") -m int 1 }
# Validate expiration
http-request set-var(txn.now) date()
http-request deny content-type 'text/html' string 'JWT has expired' if { var(txn.exp),sub(txn.now) -m int lt 0 }
```
**What it validates:**
- ✅ Authorization header presence
- ✅ JWT signing algorithm (RS256, RS512, etc.)
- ✅ JWT issuer (if configured)
- ✅ JWT audience (if configured)
- ✅ JWT signature using public key
- ✅ JWT expiration time
**Important:** Requires HAProxy 2.5+ with JWT support. Mount public key file as read-only volume.
### FastCGI Plugin (Domain)
Configures FastCGI parameters for PHP-FPM and other FastCGI applications.
**Why use it:** Automatically generates HAProxy `fcgi-app` configuration that defines required CGI parameters for PHP-FPM communication without manual HAProxy configuration.
**Configuration options:**
- `enabled` - Enable/disable plugin (default: `true`)
- `document_root` - Document root path (default: `/var/www/html`)
- `script_filename` - Custom pattern for SCRIPT_FILENAME (default: `%[path]`, uses HAProxy's default)
- `index_file` - Default index file (default: `index.php`)
- `path_info` - Enable PATH_INFO support (default: `true`)
- `custom_params` - Dictionary of custom FastCGI parameters (optional)
**Enable via container label (TCP connection):**
```yaml
services:
php-fpm:
image: php:8.2-fpm
labels:
easyhaproxy.http.host: phpapp.local
easyhaproxy.http.port: 80
easyhaproxy.http.localport: 9000
easyhaproxy.http.proto: fcgi
easyhaproxy.http.plugins: fastcgi
easyhaproxy.http.plugin.fastcgi.document_root: /var/www/html
easyhaproxy.http.plugin.fastcgi.index_file: index.php
volumes:
- ./app:/var/www/html
```
**Or with Unix socket:**
```yaml
services:
php-fpm:
image: php:8.2-fpm
labels:
easyhaproxy.http.host: phpapp.local
easyhaproxy.http.socket: /run/php/php-fpm.sock
easyhaproxy.http.proto: fcgi
easyhaproxy.http.plugins: fastcgi
easyhaproxy.http.plugin.fastcgi.document_root: /var/www/html
easyhaproxy.http.plugin.fastcgi.index_file: index.php
volumes:
- ./app:/var/www/html
- /run/php:/run/php
```
**Custom document root and index file:**
```yaml
labels:
easyhaproxy.http.plugins: fastcgi
easyhaproxy.http.plugin.fastcgi.document_root: /var/www/myapp/public
easyhaproxy.http.plugin.fastcgi.index_file: app.php
easyhaproxy.http.plugin.fastcgi.path_info: true
```
**HAProxy config generated:**
The plugin generates a top-level `fcgi-app` section and a `use-fcgi-app` directive in the backend:
```haproxy
# Top-level fcgi-app definition (added after defaults, before frontends/backends)
fcgi-app fcgi_phpapp_local
docroot /var/www/html
index index.php
path-info ^(/.+\.php)(/.*)?$
# Backend configuration (added to the backend section)
backend srv_phpapp_local_80
use-fcgi-app fcgi_phpapp_local
# TCP connection:
server srv-0 172.19.0.3:9000 proto fcgi
# OR Unix socket:
# server srv-0 /run/php/php-fpm.sock proto fcgi
```
**Note:** HAProxy automatically sets standard CGI parameters (SCRIPT_FILENAME, DOCUMENT_ROOT, REQUEST_URI, QUERY_STRING, REQUEST_METHOD, CONTENT_TYPE, CONTENT_LENGTH, SERVER_NAME, SERVER_PORT, etc.) based on the `fcgi-app` configuration when communicating with PHP-FPM via the FastCGI protocol.
**What it configures:**
- ✅ SCRIPT_FILENAME - Path to PHP script
- ✅ DOCUMENT_ROOT - Document root directory
- ✅ SCRIPT_NAME - Script name from URL
- ✅ REQUEST_URI - Full request URI with query string
- ✅ QUERY_STRING - URL query parameters
- ✅ REQUEST_METHOD - HTTP method (GET, POST, etc.)
- ✅ CONTENT_TYPE & CONTENT_LENGTH - Request body info
- ✅ SERVER_NAME & SERVER_PORT - Server details
- ✅ HTTPS - SSL/TLS status
- ✅ PATH_INFO - Path information (optional)
**Important:** Use this plugin together with `proto: fcgi` parameter for complete PHP-FPM support.
EasyHAProxy includes several built-in plugins ready to use:
- [Cloudflare](plugins/cloudflare.md) - Restore visitor IP from Cloudflare CDN
- [Cleanup](plugins/cleanup.md) - Cleanup temporary files
- [Deny Pages](plugins/deny-pages.md) - Block specific paths
- [IP Whitelist](plugins/ip-whitelist.md) - Restrict access to IPs/CIDR ranges
- [JWT Validator](plugins/jwt-validator.md) - Validate JWT tokens
- [FastCGI](plugins/fastcgi.md) - Configure PHP-FPM and FastCGI applications
## Configuration Methods
@ -746,7 +392,7 @@ Per-ingress/per-container settings override global configuration.
## Creating Custom Plugins
To create your own plugins, see the [Plugin Developer Guide](plugin-development.md).
Want to create your own plugins? See the [Plugin Developer Guide](plugin-development.md) for detailed instructions on building custom plugins that extend EasyHAProxy functionality.
## Further Reading
@ -754,3 +400,4 @@ To create your own plugins, see the [Plugin Developer Guide](plugin-development.
- [Container Labels](container-labels.md) - Label configuration reference
- [Environment Variables](environment-variable.md) - Environment variable reference
- [Static Configuration](static.md) - YAML configuration reference
- [Kubernetes Guide](kubernetes.md) - Using plugins with Kubernetes