How to Choose between HAProxy TCP and HTTP Modes

Choose HAProxy TCP mode when a frontend needs to relay a Transmission Control Protocol (TCP) stream without applying HTTP request rules. Choose HTTP mode when HAProxy must process Hypertext Transfer Protocol (HTTP) requests and responses, such as routing by request path or modifying a header. For HTTPS, the encrypted form of HTTP, those operations require access to decrypted messages at the proxy.
Transport Layer Security (TLS) termination and proxy mode are separate settings. TCP mode can relay an encrypted stream unchanged, or HAProxy can terminate TLS while still treating the decrypted application stream as TCP. HTTP mode does not enable encryption by itself.
Choose a mode for each frontend and the backends it can use. A frontend accepts client connections; a backend defines the servers that receive the traffic. Check the settings inherited from defaults, especially when one HAProxy instance serves both web traffic and a non-HTTP application.
Map Both Sides of the Proxy
Write down the protocol arriving at the frontend, where TLS ends, and the protocol the selected backend expects. A public listener on port 443 does not answer those questions by itself. It could carry HTTPS that HAProxy terminates, HTTPS that passes through to a server, or another application using TLS.
Identify the routing information needed at HAProxy. A single pool of database servers may only require a connection to be assigned to a server. Routing /api/ requests to a separate application requires an HTTP path, which is unavailable inside encrypted passthrough traffic.
Then inspect the current frontend, every backend reachable through its selection rules, and the defaults they inherit. For the straightforward configurations here, set the intended mode explicitly in both the frontend and its backends. These explicit settings make the mode clear and keep a later change to the default mode from affecting those frontends and backends.
Use TCP Mode to Relay Application Data
TCP mode relays application bytes over the selected backend connection. HTTP traffic can pass through in TCP mode, but HAProxy does not process the HTTP messages as requests and responses.
For TLS passthrough, the backend server handles the client's TLS handshake and presents the service certificate. HAProxy forwards the stream without terminating that handshake. This is appropriate when the TLS endpoint needs to remain at the backend and HAProxy does not need to inspect the encrypted request.
This configuration uses HAProxy 3.2 syntax for TLS passthrough. The backend address is reserved for documentation, and the timeout values are examples rather than values chosen for a measured workload:
defaults
timeout connect 5s
timeout client 30s
timeout server 30s
frontend tls_passthrough
mode tcp
bind :443
default_backend tls_servers
backend tls_servers
mode tcp
server app1 192.0.2.10:443 checkThe frontend bind has no ssl option, and the server line adds no new TLS layer. The TLS bytes arriving from the client are the bytes delivered to the server. Adding TLS on the server connection in this particular passthrough design would wrap an already encrypted stream in another TLS connection instead of turning it into HTTP inspection.
Changing a URL path on the same passthrough connection should not cause HAProxy to select a different backend through an HTTP rule. The backend application can interpret the request after decryption, but that interpretation happens at the backend.
Use HTTP Mode Where Request Rules Are Required
HTTP mode gives HAProxy the request structure needed for path and header decisions. When HTTPS terminates at HAProxy, the frontend bind also needs the TLS configuration and a suitable service certificate. The backend can then receive clear HTTP or HTTP protected by a separate TLS connection.
This example uses an access control list (ACL) to route paths beginning with /api/ to an application programming interface (API) backend. Other requests go to a web backend. It is an alternative to the passthrough example, not an additional listener to place alongside it on the same address and port:
defaults
timeout connect 5s
timeout client 30s
timeout server 30s
frontend https_requests
mode http
bind :443 ssl crt /etc/haproxy/certs/example.pem
acl api_path path_beg /api/
use_backend api_servers if api_path
default_backend web_servers
backend api_servers
mode http
server api1 192.0.2.11:8080 check
backend web_servers
mode http
server web1 192.0.2.12:8080 checkThe certificate path represents a file that must exist in the deployment and contain the appropriate certificate and private key. Replace the documentation addresses with authorized backend addresses. The two servers in this example are deliberately configured to receive clear HTTP on port 8080.
The /api/ prefix is part of the matching condition. A request for /api/status matches, while /api without the trailing slash does not match this particular ACL. If both forms should reach the API, add an exact-path condition for /api rather than broadening the prefix to /api and unintentionally matching /apix.
Backend selection does not remove /api/ from the request. Decide whether the API expects that prefix before adding a separate rewrite. A routing rule that chooses the correct server can still produce an application error if the forwarded path does not match the server's routes.
Configure Backend TLS Separately
If the backend requires HTTPS, the HTTP example needs a TLS connection from HAProxy to that server. Enable TLS on the server line and configure certificate verification against the intended trust store and service name. Include the appropriate server name indication (SNI) when the backend uses it to select a certificate.
A server address ending in :443 does not automatically turn a clear HTTP connection into HTTPS. Sending unencrypted requests to a TLS listener can fail before the application receives a usable request. Changing the proxy mode does not repair that mismatch between the server's listener and the outgoing transport.
The client connection and the backend connection can therefore use different encryption settings while HAProxy remains in HTTP mode. Decide whether clear HTTP is permitted on that particular backend network rather than assuming that TLS on the public listener protects the entire route to the application.
Place Request Rules at the Proxy That Can Read Them
A path ACL belongs at a point where HAProxy can parse the HTTP request. If an earlier proxy passes TLS through unchanged, a later proxy may terminate it and apply HTTP rules there. The earlier proxy cannot apply the same path decision by merely adding an HTTP ACL to its encrypted TCP path.
If the API requires the /api/ prefix to be removed, place that rewrite in the selected backend so routing can still use the original path. An http-request rewrite in the frontend runs before use_backend rules, even if it appears later in the file. Removing the prefix there could prevent the path ACL from matching.
A shared defaults section can affect unrelated listeners. Before changing its mode, account for every frontend and backend that inherits from it. Setting mode http only on the web frontend and its backends keeps the change from affecting an unrelated database proxy.
Check the Configuration with the Deployed Version
Use the HAProxy binary and configuration files that the service actually uses. These examples are based on HAProxy 3.2 syntax, but the installed release and its TLS build options still matter. A check performed with a different binary does not establish that the service will accept the same file.
In an authorized environment with the configuration saved at the example path, the following command checks the file without starting the proxy:
haproxy -c -f /etc/haproxy/haproxy.cfgRead the reported errors and warnings and check the command's exit status. The configuration check exits before binding listeners, so a successful result does not prove that a port is available or that a backend can be reached. The certificate file in the HTTPS example also needs to be present and usable for the configuration to pass.
Load the corrected configuration through the deployment's established service procedure. Retain the previous configuration so a routing change that passes parsing but fails request checks can be reversed. The commands and configurations here are proposed examples, not results from a running deployment.
Verify TLS Termination and Backend Selection
Test the proxy configuration using service names and backend addresses that you are authorized to access. For passthrough, the client should complete TLS with the backend service. For termination at HAProxy, the client should complete TLS at the proxy and the application should receive the resulting request over the configured backend transport.
A valid certificate alone may not identify the TLS endpoint if both machines use the same service certificate. Confirm the connection path with the deployment's configuration and available connection records. Keep that check separate from the question of whether the HTTP request reached the intended application.
For the HTTP routing example, check several paths and record the selected backend:
- /api/status should select api_servers.
- / should select web_servers.
- /api and /apix should select web_servers with the exact ACL shown.
These are expected selections, not promises that every request returns a successful HTTP status. The API application can reject a request even when HAProxy selects the intended backend, while two applications can return similar successful pages. Use the selected backend and an application response that identifies the intended service to distinguish those cases.
The basic check on each example server tests TCP connectivity. It does not establish that a particular API route works or that the full client TLS exchange succeeds. Verify those operations separately, and investigate a connection failure, a certificate failure, and an unexpected backend as different problems.
Include the application's normal long requests or idle periods when choosing the timeout values. A brief successful request does not show that a streaming operation survives its expected pauses. Record the deployed release, configuration used, requested paths, selected backends, and observed responses so the decision can be tied to actual behavior.







