Why Parallels RAS Wouldn't Work on Port 443 with my other services

The SNI Routing Trap....

4 min read
Why Parallels RAS Wouldn't Work on Port 443 with my other services

I needed to proxy Parallels RAS (Remote Application Server) through HAProxy alongside other services, all on port 443 with a single public IP. Sounds simple, right? It wasn't.

Initial symptoms:

  • Web portal loaded perfectly on first access
  • Clicking to launch an application triggered an infinite loading loop
  • Refreshing the page resulted in 503 Service Unavailable errors
  • Opening the same URL in a new incognito tab worked again

This intermittent behavior was maddening.

First Attempt: HTTP Mode (The Wrong Approach)

My initial HAProxy configuration treated Parallels RAS like any other web service:

frontend https_frontend
    bind *:443 ssl crt /etc/haproxy/certs/
    mode http
    use_backend home_backend if { hdr(host) -i home.raidho.fr }

backend home_backend
    mode http
    server ras01 192.168.0.159:443 check ssl verify none

Why this failed:

  • HAProxy was terminating SSL and re-encrypting to the backend
  • HTTP headers were being added/modified (X-Forwarded-For, X-Forwarded-Proto, etc.)
  • Parallels RAS uses WebSocket connections and proprietary protocols for application launching
  • These protocols are sensitive to header manipulation and SSL re-negotiation

Result: The web portal loaded, but launching applications failed completely.

Second Attempt: TCP Passthrough with SNI Routing

The solution seemed obvious: use TCP mode for transparent passthrough. But with multiple services on port 443, I needed a way to route traffic. Enter SNI (Server Name Indication) inspection:

frontend https_tcp_frontend
    bind *:443
    mode tcp
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }
    
    acl host_home req_ssl_sni -i home.raidho.fr
    use_backend home_tcp_backend if host_home
    default_backend https_ssl_termination

backend home_tcp_backend
    mode tcp
    server ras01 192.168.0.159:443 check

This worked... sort of. The portal loaded, I could log in, but refreshing the page gave 503 errors.

The Root Cause: Connection Reuse vs. SNI Inspection

Here's what I learned the hard way:

How SNI inspection works:

  1. Client initiates TLS handshake
  2. SNI (hostname) is sent during the ClientHello message
  3. HAProxy inspects SNI and routes to the appropriate backend
  4. Connection established

The fatal flaw:

  • SNI only exists in the initial TLS handshake
  • Modern browsers reuse TCP connections (HTTP/1.1 keep-alive, HTTP/2 multiplexing)
  • When a user refreshes the page, the browser reuses the existing connection
  • No new TLS handshake = no SNI to inspect
  • HAProxy can't determine where to route the traffic
  • HAProxy sends TCP RST (reset) packet
  • Result: 503 Service Unavailable

Why tcpdump revealed the truth:

$ sudo tcpdump -i any -n port 443 and host 192.168.0.159

# First connection - works
07:25:59.622151 ens18 Out IP ... Flags [S], seq ... (SYN)
07:25:59.622221 ens18 Out IP ... Flags [P.], seq 1:1725 (Data with SNI)

# Refresh attempt - fails
07:25:59.785608 ens18 Out IP ... Flags [R.], seq 1 (RST - connection reset!)

HAProxy was actively killing connections because it couldn't route without SNI.

Why Standard Solutions Don't Work

"Just use SSL offload!"

  • This brings us back to problem #1
  • Terminates SSL, modifies headers, breaks RAS protocols

"Use a second public IP!"

  • Requires additional IP allocation
  • More complex firewall rules
  • Valid solution, but I wanted something simpler

"Keep the SNI routing and live with it!"

  • Unacceptable UX: users can't refresh pages
  • Applications fail to launch intermittently
  • Support nightmare

The Actual Solution: Dedicated Port

After fighting with the architecture, I accepted reality: SNI-based routing on a shared port with TCP passthrough is fundamentally incompatible with connection reuse.

Final configuration:

# Port 443: Regular services with SSL termination
frontend https_frontend
    bind *:443 ssl crt /etc/haproxy/certs/
    mode http
    # ... route to various backends

# Port 8443: Parallels RAS with pure TCP passthrough
frontend ras_frontend
    bind *:8443
    mode tcp
    timeout client 3600s
    default_backend home_tcp_backend

backend home_tcp_backend
    mode tcp
    timeout server 3600s
    timeout tunnel 3600s
    server gateway01 192.168.0.163:443 check

Why this works:

  • No SNI inspection needed - all traffic on 8443 goes to RAS
  • Pure TCP passthrough maintains connection integrity
  • No header manipulation, no SSL termination
  • Connection reuse works perfectly
  • Refreshing works, application launching works, everything works

Lessons Learned

  1. SNI inspection is read-once during TLS handshake - it cannot work with connection reuse
  2. Not all protocols are HTTP-friendly - some require transparent TCP passthrough
  3. Sometimes the "simple" solution (shared port) is architecturally impossible - fighting it wastes time
  4. Port 8443 is standard for alternate HTTPS services - there's a reason enterprises use it
  5. Protocol limitations beat configuration cleverness - no amount of tuning fixes a fundamental incompatibility

Alternatives That Would Work

If opening port 8443 isn't possible:

  1. Second public IP address: Bind RAS to a dedicated IP, no SNI routing needed
  2. Different subdomain on different IP: ras.domain.com → separate IP
  3. HTTP redirect landing page: domain.comdomain.com:8443 (transparent to users)
  4. Accept the limitation: Document that users should bookmark the full URL and not refresh

The right architecture matters more than clever configuration. I spent hours trying to make SNI-based routing work on port 443 before accepting that the protocol stack itself made it impossible. Using port 8443 with pure TCP passthrough solved all issues immediately.