How to Configure HAProxy for SSL Termination with X-Forwarded-For and HTTPS Detection in PHP Backends


2 views

When implementing HAProxy as a reverse proxy with SSL termination, two critical requirements often emerge:

  1. Preserving client IP information via X-Forwarded-For headers
  2. Properly signaling HTTPS usage to backend PHP applications

Here's a production-ready configuration that addresses both requirements:

frontend https-in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
    mode http
    option forwardfor except 127.0.0.1
    http-request set-header X-Forwarded-Proto https
    http-request add-header X-Forwarded-Port 443
    default_backend php_servers

backend php_servers
    mode http
    balance roundrobin
    option httpchk HEAD /health-check HTTP/1.1\r\nHost:\ example.com
    server php1 192.168.1.101:80 check
    server php2 192.168.1.102:80 check
    server php3 192.168.1.103:80 check
    server php4 192.168.1.104:80 check

    # Force backend to recognize forwarded HTTPS
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header X-Real-IP %[src]

On your Apache/PHP servers, ensure proper handling of forwarded headers:

# In your Apache virtual host
SetEnvIf X-Forwarded-Proto https HTTPS=on

# PHP application should check these values
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && 
    $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
    $_SERVER['HTTPS'] = 'on';
}

# Get real client IP
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
    $client_ip = $_SERVER['REMOTE_ADDR'];
}

For pfSense users, navigate to:

  1. Services > HAProxy
  2. Create Frontend with SSL certificates
  3. Add "http-request set-header" rules in Advanced Settings
  4. Configure backend with health checks and proper header forwarding
  • Enable SSL session caching in HAProxy for better performance
  • Configure keepalive connections between HAProxy and backends
  • Consider using HTTP/2 for frontend connections

If PHP still doesn't detect HTTPS:

# Additional check in PHP
if (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && 
    $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
    $_SERVER['HTTPS'] = 'on';
}

When implementing HAProxy as a reverse proxy for HTTPS traffic, we face three critical requirements:

  • SSL termination at the proxy level
  • Preservation of client IP addresses via X-Forwarded-For headers
  • Proper SSL flag propagation to backend PHP applications

Here's a complete solution that addresses all requirements:


frontend http-in
    bind *:80
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
    option forwardfor except 127.0.0.1
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header X-Forwarded-Port %[dst_port]
    default_backend apache_servers

backend apache_servers
    balance roundrobin
    option forwardfor
    server server1 192.168.1.10:80 check
    server server2 192.168.1.11:80 check
    server server3 192.168.1.12:80 check

On your Apache servers, ensure these settings are configured:


# In Apache configuration
SetEnvIf X-Forwarded-Proto https HTTPS=on
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 192.168.1.0/24

For pfSense users, follow these additional steps:

  1. Install HAProxy package through Package Manager
  2. Upload your SSL certificate via System → Cert Manager
  3. Configure frontend with "SSL Offloading" enabled
  4. Enable "Forwarded-For Header" in advanced settings

Create a test PHP file to verify all components:


<?php
echo "Client IP: " . $_SERVER['HTTP_X_FORWARDED_FOR'] . "\n";
echo "HTTPS: " . ($_SERVER['HTTPS'] ? 'ON' : 'OFF') . "\n";
echo "Protocol: " . $_SERVER['HTTP_X_FORWARDED_PROTO'] . "\n";
?>

When using SSL termination:

  • Enable SSL session caching in HAProxy: ssl-default-server-options ssl-max-ver TLSv1.2 no-sslv3
  • Consider adding ssl-min-ver TLSv1.2 for better security
  • For high traffic sites, implement OCSP stapling

While nginx could serve as an alternative, HAProxy offers advantages:

  • More efficient TCP-level load balancing
  • Advanced health checking capabilities
  • Better integration in pfSense environment

Use these HAProxy logging directives for troubleshooting:


global
    log /dev/log local0 debug

frontend http-in
    capture request header X-Forwarded-For len 50
    capture request header X-Forwarded-Proto len 10