When faced with aging NetScaler appliances and expensive renewal costs, many organizations are looking for alternatives. This guide documents a real-world migration from Citrix NetScaler to HAProxy on Ubuntu 24.04 (can be RedHat), preserving critical functionality like content switching and SSL offloading.
Why Migrating Was Necessary
In my case, there were two major blockers that forced the move away from NetScaler:
- Freemium throughput limitation: The VPX freemium edition is capped at 20 Mb/s, which was a real bottleneck for modern workloads.
- Hardware failure: My NetScaler SDX 11500 appliance died, leaving me with only the two VPX instances running on proxmox and those were both constrained by the freemium license limits.
That combination meant I needed a serious, production-ready alternative that could replace the NetScaler VPX instances without throughput restrictions, licensing headaches, or dependence on proprietary hardware.
Understanding the Starting Point
The NetScaler configuration revealed a typical setup:
- Content Switching: Routing traffic to different backends based on hostname
- SSL Offloading: Handling TLS termination with multiple wildcard certificates
- Load Balancing: Distributing traffic across Docker Swarm nodes
- Health Monitoring: Various HTTP/HTTPS checks with custom parameters
The configuration served 18 different services across three domains with traffic distributed across multiple Docker hosts.
Why HAProxy?
After evaluating alternatives including NGINX, Traefik and F5 BIG-IP, HAProxy emerged as the optimal choice because:
- Configuration concepts map directly from NetScaler
- Production-proven at scale
- Robust health checking capabilities
- Excellent SSL/SNI support
- Open source with strong community

Installation Process
Step 1: Installing HAProxy on Ubuntu 24.04
sudo apt update
sudo apt install haproxy
sudo systemctl enable haproxy
Step 2: Preparing SSL Certificates
NetScaler stores certificates and keys separately, while HAProxy requires combined PEM files:
sudo mkdir -p /etc/haproxy/certs
# For each certificate, combine cert and key
openssl rsa -in domain.key -out temp.key.nopass
cat domain.crt temp.key.nopass > /etc/haproxy/certs/domain.pem
sudo chmod 400 /etc/haproxy/certs/*.pem
sudo chown haproxy:haproxy /etc/haproxy/certs/*.pem
Configuration Translation
NetScaler to HAProxy Mapping
NetScaler Component | HAProxy Equivalent |
---|---|
Content Switch Virtual Server | Frontend with ACLs |
CS Policies | ACL rules |
CS Actions | use_backend directives |
Service Groups | Backend server pools |
Monitors | Health checks |
SSL Profile | SSL bind options |
The Configuration Structure
The HAProxy configuration follows this pattern:
global
# System-wide settings
log 127.0.0.1:514 local0
user haproxy
group haproxy
defaults
# Default parameters for all proxies
mode http
timeout client 180s
timeout server 360s
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/
# Content switching ACLs
acl host_app1 hdr(host) -i app1.example.com
acl host_app2 hdr(host) -i app2.example.com
# Route to appropriate backend
use_backend app1_backend if host_app1
use_backend app2_backend if host_app2
backend app1_backend
balance roundrobin
server node01 10.0.1.10:3000 check
server node02 10.0.1.11:3000 check
backend app2_backend
balance roundrobin
server node01 10.0.1.10:8080 check
server node02 10.0.1.11:8080 check
Key Challenges and Solutions
Challenge 1: SSL Certificate Format
Problem: NetScaler uses separate certificate and key files, HAProxy needs combined PEM files.
Solution: Automated script to combine certificates with keys after removing passphrases.
Challenge 2: Health Check Syntax
Problem: HAProxy 2.8 deprecated inline headers in httpchk
.
Solution: Used new http-check send
syntax with explicit method and headers:
http-check send meth HEAD uri / hdr Host app.example.com
Challenge 3: Multiple Acceptable Status Codes
Problem: Some services return 302 or 405 as valid responses.
Solution: Used regex patterns in health checks:
http-check expect rstatus (200|302|405)
Challenge 4: IP Binding Issues
Problem: Initial config tried to bind to IPs not present on the server.
Solution: Used wildcard binding for main services, specific IPs only when necessary.
Challenge 5: Home Assistant Behind HAProxy
Problem: Requests to Home Assistant returned HTTP 400 Bad Request because HA saw duplicated or untrusted X-Forwarded-For
headers.
Solution:
- Removed duplicate header injection (
option forwardfor
or manualhttp-request set-header X-Forwarded-For
, not both). - Added
timeout tunnel 1h
in HAProxy defaults to keep WebSocket connections alive.
Configured Home Assistant to trust the proxy in HAS configuration.yaml:
http:
use_x_forwarded_for: true
trusted_proxies:
- 192.168.89.125 # HAProxy IP
Challenge 6: Outline (Outliner) Behind HAProxy
Problem: Outline (the collaborative docs app) returned 500 errors during health checks and login redirects failed.
Solution:
- Once
FORCE_HTTPS
was enabled, Outline behaved correctly behind HAProxy.
Adjusted the application’s Docker Compose environment:
URL=https://docs.example.com
FORCE_HTTPS=true
Added proper Host header in health checks:
http-check send meth GET uri / hdr Host docs.example.com
http-check expect rstatus (200|301|302|401)

What You Cannot Migrate
One important limitation: Citrix Gateway (NetScaler Gateway) cannot be migrated to HAProxy.
- NetScaler Gateway provides full ICA Proxy, VPN and authentication gateway features for Citrix Virtual Apps and Desktops.
- HAProxy is strictly a reverse proxy and load balancer; it does not implement Citrix’s ICA proxying or VPN gateway functionality.
- If your NetScaler is used as a Citrix Gateway, you will need to keep it, replace it with another Citrix ADC, or move to alternative VPN/remote access solutions.
- HAProxy is excellent for content switching, SSL offload and load balancing web applications but it is not a replacement for NetScaler Gateway.
Feature Comparison: NetScaler vs HAProxy
Feature | Citrix NetScaler | HAProxy (OSS) |
---|---|---|
Content Switching | ✅ Yes (CS vServers, policies) | ✅ Yes (frontends, ACLs) |
SSL Offloading | ✅ Yes (profiles, SNI) | ✅ Yes (bind crt/SNI) |
Load Balancing (HTTP/TCP) | ✅ Yes | ✅ Yes |
Advanced Health Checks | ✅ Yes (monitors) | ✅ Yes (http-check, regex) |
Session Persistence | ✅ Yes (stickiness, cookies) | ✅ Yes (stick-tables, cookies) |
WebSockets Support | ⚠️ Limited, needs config | ✅ Native (HTX, timeout tunnel) |
GUI Management | ✅ Full GUI | ❌ CLI / config files only |
Citrix Gateway (ICA Proxy/VPN) | ✅ Yes (ICA Proxy, VPN, SSO, MFA) | ❌ Not supported |
Licensing Cost | 💰 Expensive | ✅ Free (open-source) |
Migration Execution
Phase 1: Parallel Running
- Set up HAProxy on new server.
- Tested with hosts file entries before DNS changes.
- Monitored logs for issues.
Phase 2: Traffic Cutover
- Updated my firall rule to switch from Netscaler Content Switching VIP to point to HAProxy.
- Monitored both old and new systems.
- Gradual service migration.
Phase 3: Decommissioning
- Confirmed all traffic on HAProxy.
- Exported any remaining NetScaler configs.
- Decommissioned NetScaler appliances.
Monitoring and Validation
Essential monitoring commands post-migration:
# Check backend health
echo "show stat" | sudo socat stdio /run/haproxy/admin.sock
# Monitor real-time traffic
sudo tail -f /var/log/haproxy.log
# Verify certificate loading
openssl s_client -connect localhost:443 -servername app.example.com
Performance Comparison
The migration resulted in:
- Cost: 100% reduction in licensing fees
- Performance: Comparable request handling with lower memory footprint
- Flexibility: Easier configuration updates without GUI
- Maintenance: Simplified with standard Linux tooling
Lessons Learned
- Test thoroughly: Use a staging environment matching production.
- Certificate management: Establish a process for certificate updates.
- Health checks: Ensure health check expectations match actual service behavior.
- Documentation: Map every NetScaler feature to its HAProxy equivalent before starting.
- Proxy-aware apps need tuning: Some apps (Home Assistant, Outline) require explicit configuration of
trusted_proxies
or HTTPS enforcement. - Citrix Gateway is not replaceable: HAProxy cannot serve as a Citrix Gateway; plan alternatives if you use ICA Proxy/VPN.
- Chroot considerations: Initially disabled chroot to avoid binding issues; can be re-enabled with proper configuration.
- Freemium limits hurt: The 20 Mb/s throughput limit on NetScaler VPX freemium makes it unusable for production. Combined with SDX hardware failure, it was the trigger to migrate.
Common Gotchas
- Private key passwords: HAProxy cannot handle password-protected keys at runtime.
- Certificate order: Must be certificate, intermediate (if any), then private key in PEM files.
- Health check methods: Some applications reject HEAD requests; adjust to GET when needed.
- Session persistence: Different syntax from NetScaler but same concepts apply.

Migrating from NetScaler to HAProxy is entirely feasible for most load balancing and content switching scenarios. The key is understanding the configuration mapping and preparing certificates properly. While you lose the GUI and some enterprise features, you gain flexibility, cost savings and a solution that integrates naturally with modern infrastructure automation.
The complete configuration serves 18 services across multiple domains, handles SSL termination with SNI and provides the same content-based routing previously handled by NetScaler all on a simple Ubuntu VM with HAProxy.
For organizations evaluating alternatives to expensive commercial load balancers, HAProxy provides a production-ready solution that can handle enterprise workloads while maintaining familiar concepts for network administrators.