Listeners & Backends
Overview
Listeners and backends are the foundation of coreX Platform’s traffic routing. A listener (HAProxy frontend) accepts inbound connections on a bind address and port. A backend is a pool of upstream servers that the listener forwards traffic to, using a configurable load balancing algorithm and health checks.
Listeners support HTTP/1.1, HTTP/2 (h2 and h2c), and HTTP/3 (QUIC). TLS termination is configured per listener and is covered in the Certificates & TLS guide.
Listeners
Creating a Listener
- Navigate to Core > Listeners
- Click Add Listener
- Configure the bind address and port (e.g.
*:443) - Select the protocol mode (HTTP or TCP)
- Enable TLS if needed and select a certificate
- Click Save and Apply Changes
Listener Properties
| Property | Description |
|---|---|
| Name | Display name for the listener |
| Bind address | IP and port to bind (e.g. *:80, 0.0.0.0:443) |
| Mode | http or tcp |
| TLS | Enable SSL termination with a bound certificate |
| HTTP/2 | Enable h2 support (alpn h2,http/1.1) |
| QUIC | Enable HTTP/3 (UDP bind + alt-svc header) |
| Default backend | Backend to route to when no other rule matches |
HTTP/2 and QUIC
HTTP/2 is enabled by adding alpn h2,http/1.1 to the TLS bind line. This allows the listener to negotiate HTTP/2 with supporting clients while remaining compatible with HTTP/1.1.
HTTP/3 (QUIC) requires an additional UDP bind on the same port. When QUIC is enabled on a listener, coreX Platform:
- Adds a UDP bind directive
- Emits an
Alt-Svcheader on HTTP/1.1 and HTTP/2 responses advertising the QUIC endpoint - Configures the QUIC connection migration and retry logic
QUIC requires HAProxy 2.6+ compiled with QUIC support. The bundled HAProxy in the coreX Platform Docker image includes QUIC support. Ensure your firewall allows UDP traffic on the listener port in addition to TCP.
SNI-based Routing
For TLS listeners with multiple hostnames, coreX Platform generates SNI-based routing using crt directories or crt-list files. Each certificate is matched by its CN/SAN, and traffic is routed to the appropriate backend based on the SNI hostname.
Backends
Creating a Backend
- Navigate to Core > Backends
- Click Add Backend
- Enter a name (e.g.
web-servers) - Add server entries (name, address, port)
- Select a load balancing algorithm
- Configure health checks if needed
- Click Save and Apply Changes
Load Balancing Algorithms
| Algorithm | Description |
|---|---|
| roundrobin | Distribute requests sequentially across servers (default) |
| leastconn | Send to the server with the fewest active connections |
| static-rr | Round-robin with static weights (faster, no dynamic weight adjustment) |
| source | Hash client IP to consistently route to the same server |
| uri | Hash request URI for cache-friendly routing |
| random | Random server selection with optional draw count |
Server Properties
Each server in a backend has:
| Property | Description |
|---|---|
| Name | Display name |
| Address | IP or hostname |
| Port | Target port |
| Weight | Relative weight for weighted algorithms |
| Max connections | Connection limit per server |
| Check | Enable health checks |
| Check interval | Seconds between health checks |
| Rise / Fall | Consecutive successful/failed checks before up/down |
| Backup | Only used when all non-backup servers are down |
| Disabled | Mark as down without removing from config |
Health Checks
Health checks verify that backend servers are responsive. coreX Platform supports:
- TCP check — verify the TCP connection succeeds (default)
- HTTP check — send an HTTP request and check the response status
- Custom check path — the URL path to check (e.g.
/health) - Expected status — the HTTP status code that indicates health (e.g.
200)
Use a dedicated health check endpoint (e.g. /health) that returns 200 only when the service is fully ready. Set rise to 2 and fall to 3 to avoid flapping. A shorter check interval detects failures faster but increases load.
Session Persistence (Stick Tables)
For sessions that must stick to a single server, coreX Platform supports stick-table-based persistence:
- stick-table type —
ip,string,binary(what to key on) - stick on — the expression to match (e.g.
srcfor client IP) - expire — how long to remember the stickiness (e.g.
30m)
HTTP Connection Reuse
Each backend has an optional http-reuse setting that controls server-side connection pooling. HAProxy’s default is safe (reuse idle connections when safe). Override per backend:
| Value | When to use |
|---|---|
| safe (default) | General purpose — reuse idle connections without aggressive pooling |
| aggressive | Cache farms and high-throughput APIs — maximize connection reuse |
| never | Streaming/SSE backends — each request gets its own connection |
The MCP gateway backend is hardcoded to http-reuse never because it serves SSE streams and cross-client connection sharing would break session affinity. FastCGI backends use their own connection model (option keep-conn in the fcgi-app block) and are unaffected by http-reuse.
FastCGI
FastCGI applications (PHP-FPM, etc.) are configured separately from regular HTTP backends and attached to a backend via the backend’s FastCGI App field. A FastCGI app defines how HAProxy talks to the FastCGI process: the document root, index file, path-info handling, connection options, and arbitrary FastCGI parameters.
FastCGI App Properties
| Property | Description |
|---|---|
| Name | Display name (unique) — referenced by backends |
| Description | Optional free-text description |
| Docroot | Document root passed to the FastCGI process (e.g. /var/www/html) |
| Index | Index file (e.g. index.php) |
| Path-info regex | Optional regex to extract the path-info portion of the URI |
| Log stderr | When enabled, forward the FastCGI process’s stderr to a HAProxy log target |
| Stderr log target | HAProxy log target name for stderr (empty = global) |
| Keep connection open | Keep the FastCGI connection alive between requests (option keep-conn, default on) |
| Connection multiplexing | Enable multiplexed connections (option mpxs-conns) — only supported by some FastCGI servers |
| Max concurrent requests | Max requests per multiplexed connection (only used when multiplexing is enabled) |
| Params | Arbitrary FastCGI parameters (name/value pairs, each individually enabled) |
Attaching a FastCGI App to a Backend
- Create the FastCGI app under Core > Load Balancing > FastCGI
- Create or edit a backend under Core > Load Balancing > Backends
- Set the backend Protocol to
fastcgi - Set FastCGI App to the app you created
- Add the FastCGI server(s) (e.g.
php-fpmat127.0.0.1:9000) - Save and Apply
HAProxy 3.4 has a bug (fcgi_flt_check) that rejects Lua-based filters alongside use-fcgi-app. As a result, Response Transforms, Brotli/Zstd Compression, and Image-to-WebP conversion are automatically skipped for FastCGI backends (a warning comment is emitted in the generated config). Native gzip/deflate compression and the HAProxy cache are unaffected and still work on FastCGI backends.
Step-by-Step: Route to a PHP-FPM Backend
-
Create the FastCGI app:
- Navigate to Core > Load Balancing > FastCGI, click Add FCGI App
- Name:
php-app - Docroot:
/var/www/html - Index:
index.php - Keep connection open: enabled
- Add any FastCGI params your app needs (e.g.
SCRIPT_FILENAME=/var/www/html/index.php) - Save
-
Create the backend:
- Navigate to Core > Load Balancing > Backends, click Add Backend
- Name:
php-fpm - Protocol: FastCGI
- FastCGI App:
php-app - Add server:
php-fpmat127.0.0.1:9000 - Save
-
Create the listener:
- Navigate to Core > Listeners, click Add Listener
- Name:
web-http - Bind:
*:80 - Mode:
http - Default backend:
php-fpm - Save
-
Apply:
- Click Apply Changes
- Verify with
curl http://localhost/
Step-by-Step: Create a TLS Listener with Two Backends
-
Create the primary backend:
- Navigate to Core > Backends, click Add Backend
- Name:
web-primary - Add servers:
web1at10.0.0.1:8080,web2at10.0.0.2:8080 - Algorithm:
roundrobin - Enable HTTP health checks on
/health, expect200 - Save
-
Create a fallback backend:
- Add another backend named
web-fallback - Add server:
fallback1at10.0.0.10:8080, mark as backup - Save
- Add another backend named
-
Create the listener:
- Navigate to Core > Listeners, click Add Listener
- Name:
web-https - Bind:
*:443 - Mode:
http - Enable TLS, select your certificate
- Enable HTTP/2
- Default backend:
web-primary - Save
-
Apply:
- Click Apply Changes
- Verify with
curl -k https://localhost/
Verification
# Check HAProxy is listening
ss -tlnp | grep :443
# Test HTTP/2
curl -k --http2 https://localhost/
# Check backend health
curl -k https://localhost/haproxy?stats
# Verify load balancing (multiple requests)
for i in $(seq 1 10); do curl -k -s -o /dev/null -w '%{remote_ip}\n' https://localhost/; done
Next Steps
- Certificates & TLS — Bind TLS certificates to listeners
- Security Rules — Add access control rules
- Metrics & Logging — Monitor traffic and backend health