HAProxy in pfSense - Reverse Proxy and Load Balancing

HAProxy (High Availability Proxy) is a high-performance solution for proxying and load balancing TCP and HTTP traffic. In pfSense, HAProxy is installed as a package and provides reverse proxy functionality, load balancing across multiple servers, SSL termination to offload encryption from backend servers, and HTTP request routing based on ACL rules. HAProxy is widely used for publishing web applications through a single external IP address, ensuring server pool failover, and distributing client requests across multiple application instances.

Within the pfSense context, HAProxy operates alongside the firewall, enabling routing, filtering, and proxying functions on a single device. This simplifies network architecture and reduces points of failure.

Installing HAProxy

Installation is performed through the package manager:

  1. Navigate to System > Package Manager > Available Packages
  2. Search for haproxy (two versions are available: haproxy and haproxy-devel)
  3. Click Install and confirm the installation
  4. Wait for the installation to complete

After installation, configuration is accessible at Services > HAProxy.

Version Selection

VersionDescriptionRecommendation
haproxyStable version, tracks the stable FreeBSD port branchProduction environments
haproxy-develDevelopment version, receives new features firstTest environments

HAProxy Architecture

HAProxy operates with two primary entities:

Client --> Frontend (listener) --> ACL (routing) --> Backend (server pool)
                                                       |-- Server 1
                                                       |-- Server 2
                                                       |-- Server 3
ComponentDescription
FrontendEntry point for client connections (IP:port), defines protocol and ACL rules
BackendPool of backend servers with load balancing and health check settings
ServerIndividual backend server in the pool (IP, port, weight)
ACLCondition for routing requests between backends

pfSense Implementation Details

The pfSense web interface differs from standard HAProxy configuration. Instead of separate frontend/backend sections in the configuration file, the pfSense package generates listen sections that combine frontend and backend. This simplifies basic setup but limits capabilities for advanced multi-backend scenarios.

Backend Configuration

A backend defines the group of servers to which HAProxy directs client requests. Configuration is performed through Services > HAProxy > Backend.

Creating a Backend

  1. Navigate to Services > HAProxy > Backend
  2. Click Add
  3. Complete the parameters
  4. Click Save and Apply Changes

Core Backend Parameters

ParameterDescription
NameUnique backend name (no spaces)
Server ListPool server list
BalanceLoad balancing algorithm
Connection TimeoutServer connection timeout
Server TimeoutServer response timeout
RetriesNumber of connection retry attempts

Backend Servers

For each server in the pool, specify:

FieldDescriptionRequired
NameServer name for log identificationYes
AddressBackend server IP address or FQDNYes
PortBackend server portYes
SSLUse SSL when connecting to the serverNo
WeightServer weight for weighted balancing (1-256)No
CookieCookie value for session persistenceNo

Load Balancing Algorithms

AlgorithmDescriptionUse Case
Round RobinSequential distribution across serversServers with equal performance
Least ConnectionsRoutes to the server with fewest connectionsRequests with varying processing times
SourceClient-to-server binding based on IP addressSession persistence without cookies required
URIRouting by request URICaching servers
FirstFills servers sequentially to capacityMinimizing active server count

For most web applications, Round Robin or Least Connections is recommended. The Source algorithm suits applications that do not support distributed sessions.

Frontend Configuration

A frontend defines the entry point for client connections - the IP address, port, and protocol on which HAProxy accepts connections. Configuration is performed through Services > HAProxy > Frontend.

Creating a Frontend

  1. Navigate to Services > HAProxy > Frontend
  2. Click Add
  3. Complete the parameters
  4. Click Save and Apply Changes

Core Frontend Parameters

ParameterDescription
NameUnique frontend name
StatusState: Active or Disabled
External AddressListening IP address (WAN, VIP, localhost)
External PortListening port
Max ConnectionsMaximum simultaneous connections
TypeType: HTTP/HTTPS (Layer 7) or TCP (Layer 4)
Default BackendDefault backend for requests without ACL matches

HTTPS Frontend Configuration

To accept HTTPS connections:

  1. Set Type to HTTP / HTTPS (offloading)
  2. In the SSL Offloading section, select the certificate
  3. Set External Port to 443
  4. Configure the Default Backend

To redirect HTTP to HTTPS, create an additional Frontend on port 80 with an http-request redirect action or use an ACL.

Binding to Virtual IP

To accept connections on a specific IP address different from the primary WAN address, use a Virtual IP:

  1. Create an IP Alias or CARP VIP through Firewall > Virtual IPs
  2. In the Frontend settings, select the created VIP in the External Address field

This enables serving multiple domains on different IP addresses through a single HAProxy instance.

ACL - Routing Rules

ACLs (Access Control Lists) define conditions by which HAProxy routes requests to different backends. ACLs analyze incoming request parameters and apply the corresponding action.

Creating ACLs

ACLs are configured within the Frontend section:

  1. On the Frontend editing page, navigate to the Access Control Lists section
  2. Click Add ACL (down arrow)
  3. Complete the condition and action
  4. Repeat for each routing rule

ACL Condition Types

ConditionDescriptionExample
Host matchesHost header matchapp.example.com
Host starts withHost header prefixapi.
Host ends withHost header suffix.example.com
Host containsSubstring in Host headerstaging
Host regexRegular expression for Host^(www\.)?example\.com$
Path starts withURI path prefix/api/
Path ends withURI path suffix.php
Path containsSubstring in URI path/admin/
Path regexRegular expression for path^/v[0-9]+/
Source IP matchesClient IP address match192.168.1.0/24
SSL SNI matchesSNI match in TLS Client Helloapp.example.com
Custom ACLCustom HAProxy conditionhdr(X-Custom) -i value

ACL Actions

ActionDescription
Use BackendRoute request to specified backend
http-request denyReject request with error code
http-request redirectRedirect request to another URL
http-request set-headerSet or modify HTTP header

Domain-Based Routing Example

Publishing multiple web applications through a single external IP address:

ACLConditionBackend
ACL 1Host matches app1.example.combackend_app1
ACL 2Host matches app2.example.combackend_app2
ACL 3Host matches api.example.combackend_api
DefaultAll other requestsbackend_default

Path-Based Routing Example

ACLConditionBackend
ACL 1Path starts with /api/backend_api
ACL 2Path starts with /static/backend_static
DefaultAll other requestsbackend_webapp

SSL Termination

SSL termination (SSL offloading) allows HAProxy to accept HTTPS connections from clients, decrypt the traffic, and forward it to backend servers over HTTP. This removes the encryption burden from backend servers and simplifies certificate management.

Importing a Certificate

Before configuring SSL, import the certificate into pfSense:

  1. Navigate to System > Certificates > Certificates
  2. Click Add/Sign
  3. Select method: Import an existing Certificate
  4. Paste the certificate and private key
  5. Click Save

For Let’s Encrypt certificates, the ACME package is recommended for automatic issuance and renewal.

Configuring SSL Offloading in Frontend

  1. In the Frontend settings, set Type to HTTP / HTTPS (offloading)
  2. In the SSL Offloading section, select the certificate
  3. Optionally add extra certificates through Additional Certificates (for multiple domains)
  4. Configure the minimum TLS version (TLS 1.2 recommended)

SSL Parameters

ParameterDescriptionRecommendation
CertificatePrimary SSL certificateRequired
Additional CertificatesCertificates for additional domainsAs needed
SSL/TLS Minimum VersionMinimum protocol versionTLS 1.2
SSL/TLS CiphersCipher suiteDefault or Mozilla Modern
HSTSHTTP Strict Transport SecurityEnable for production
OCSP StaplingOCSP status staplingEnable for improved performance

SSL Pass-Through

When SSL termination must occur on the backend server (e.g., client certificates), use the SSL/HTTPS (TCP mode) type. HAProxy passes encrypted traffic without decryption, routing by SNI.

Health Checks

Health checks enable HAProxy to determine backend server availability and automatically remove unresponsive servers from the balancing pool.

Check Types

TypeDescriptionParameters
TCP CheckTCP connection check to portNo configuration required
HTTP CheckSends HTTP request and verifies response codeURI, method, expected code
SSL CheckSSL connection checkSimilar to TCP with SSL
LDAP CheckLDAP server verificationLDAP-specific parameters
MySQL CheckMySQL server verificationCredentials
PostgreSQL CheckPostgreSQL server verificationCredentials
SMTP CheckSMTP server verificationHELO domain
ESMTP CheckExtended SMTP verificationEHLO domain

Configuring HTTP Checks

For web applications, HTTP checks are recommended:

  1. In the Backend settings, navigate to Health Checking
  2. Set Health Check Method to HTTP
  3. Specify Check Frequency (check interval, e.g., 5 seconds)
  4. Specify Health Check URI (check path, e.g., /health)
  5. Specify HTTP Check Method (GET)
  6. Specify the expected response code (default 200-399)

Check Parameters

ParameterDescriptionDefault
Check FrequencyInterval between checks5 seconds
InterCheck interval for healthy servers5000 ms
Down InterCheck interval for unavailable servers1000 ms
RiseSuccessful checks required to restore server2
FallFailed checks required to remove server3

Session Persistence

Session persistence (sticky sessions) ensures all requests from a single client are directed to the same backend server. This is necessary for applications that store session state locally on the server.

Persistence Methods

MethodDescriptionUse Case
Cookie-basedHAProxy inserts a cookie with server identifierWeb applications with cookie support
Source IPBinding by client IP address (Source algorithm)Applications without cookies, APIs
SSL Session IDBinding by TLS session identifierHTTPS without cookies

Configuring Cookie-Based Persistence

  1. In the Backend settings under Cookie Persistence:
    • Cookie Name - cookie name (e.g., SERVERID)
    • Cookie Mode - mode: Insert (HAProxy inserts cookie), Prefix, Rewrite
    • Cookie Options - additional parameters (Indirect, NoCache, PostOnly)
  2. For each server in the backend, specify a unique value in the Cookie field

Statistics Page

HAProxy provides a built-in statistics page with information about the state of frontends, backends, and individual servers.

Enabling Statistics

Configuration is performed through Services > HAProxy > Settings under the Stats section:

ParameterDescription
Stats EnabledActivate the statistics page
Stats URIAccess URI (e.g., /haproxy-stats)
Stats RealmAuthentication dialog title
Stats UsernameUsername
Stats PasswordPassword
Stats AdminAllow server management through the web interface
Stats NodeNode name displayed in statistics

Statistics Page Information

The statistics page displays:

  • State of each frontend (UP/DOWN, current connections)
  • State of each backend and its servers (UP/DOWN, active/inactive)
  • Request counts, bytes, and errors for current and previous sessions
  • Server response times (avg, max)
  • Queue status (request queue during server overload)
  • Server weights and distribution ratios

With Stats Admin enabled, the following actions are available: disabling/enabling servers, draining connections, setting weights.

Warning:

The statistics page contains sensitive infrastructure information. Always configure authentication and restrict access by IP address through firewall rules or ACLs.

Common Use Cases

Reverse Proxy for Web Servers

Publishing multiple web applications through a single external IP address with domain-based routing:

  1. Create a Backend for each web application (backend_site1, backend_site2)
  2. Create a Frontend on port 443 with SSL termination
  3. Configure ACL routing rules by Host
  4. Create a Frontend on port 80 with HTTPS redirect
  5. Configure firewall rules to allow traffic on ports 80 and 443

Web Application Load Balancing

Distributing requests across multiple application instances:

  1. Create a Backend with multiple servers
  2. Select the balancing algorithm (Round Robin or Least Connections)
  3. Configure HTTP health check on the /health endpoint
  4. Configure Cookie-based session persistence if required
  5. Create a Frontend bound to a VIP or WAN address

API Publishing

Routing API requests with version separation:

  1. Create a Backend for each API version
  2. Create a Frontend with path-based ACLs: /v1/ - backend_v1, /v2/ - backend_v2
  3. Configure health checks for each backend
  4. Add rate limiting through ACLs if needed

Global Settings

General HAProxy parameters are configured through Services > HAProxy > Settings.

ParameterDescriptionRecommendation
Enable HAProxyActivate HAProxyEnable
Maximum ConnectionsGlobal connection limit1000-10000 (depends on RAM)
Internal Connections TimeoutClient connection timeout30000 ms
Connection TimeoutBackend connection timeout30000 ms
Server TimeoutBackend response timeout30000 ms
Tunnel TimeoutTimeout for WebSocket and long-lived connections3600000 ms
DNS ResolversDNS servers for backend name resolutionSpecify when using FQDN

Logging

HAProxy writes events to the pfSense system log (Status > System Logs > HAProxy).

Log Levels

LevelDescription
EmergencySystem is unusable
AlertImmediate action required
CriticalCritical errors
ErrorConnection and processing errors
WarningWarnings (server unavailability)
NoticeNormal but significant events
InfoInformational messages about requests
DebugDetailed debug information

HTTP Log Format

Each HTTP request log line contains:

  • Client IP and port
  • Connection acceptance time
  • Frontend and backend names
  • HTTP response code
  • Processing duration (Tq/Tw/Tc/Tr/Tt)
  • Transferred data volume
  • Request headers (when capture is enabled)

Troubleshooting

HAProxy Fails to Start

  1. Check configuration: Services > HAProxy > Settings > Configuration Validity
  2. Review system logs: Status > System Logs > HAProxy
  3. Verify frontend ports are not occupied by other services
  4. Confirm SSL certificates are valid and not expired

Backend Server Marked as DOWN

  1. Verify server reachability from pfSense: Diagnostics > Ping
  2. Confirm the backend server port accepts connections: Diagnostics > Test Port
  3. Review health check settings - URI, method, expected response code
  4. Examine HAProxy logs to determine the failure cause
  5. Temporarily disable the health check for diagnostics

502 Bad Gateway

  1. The backend server is not responding or returning an error
  2. Check the backend connection timeout (Connection Timeout)
  3. Verify the backend server can handle the request (not overloaded)
  4. When using SSL to the backend, verify certificate correctness

503 Service Unavailable

  1. All servers in the backend are marked as DOWN
  2. Review health checks for each server
  3. Verify the maximum connection count is not exceeded
  4. Check the request queue on the statistics page

SSL Errors

  1. Check certificate expiration: System > Certificates
  2. Verify the certificate chain is complete (including intermediate CAs)
  3. Confirm the domain name in the certificate matches the requested domain
  4. When using multiple certificates, verify SNI is configured correctly
  5. Check the minimum TLS version - older clients may not support TLS 1.2+

Session Not Persisting Between Requests

  1. Review Cookie Persistence settings in the backend
  2. Verify each server has a unique Cookie value
  3. When using the Source algorithm, confirm clients connect from a consistent IP
  4. Check whether a transparent proxy or CDN is modifying the client IP

Related Sections

Last updated on