When working with HAProxy as a reverse proxy for Tomcat applications, we often need to route traffic based on either subdomains or URL paths. In this scenario, we have:
- Main domain (
www.xyz.com
) should route to backend server 10.0.0.1 - Subdomain
abc.xyz.com
OR path/abc
should route to 10.0.0.2
Here's the foundational configuration we'll be building upon:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
This handles incoming HTTP traffic and routes based on the Host header (for subdomains):
frontend http-in
bind *:80
acl is_abc hdr(host) -i abc.xyz.com
acl is_abc_path path_beg /abc
use_backend tomcat_abc if is_abc or is_abc_path
default_backend tomcat_main
Define the actual backend servers where Tomcat is running:
backend tomcat_main
balance roundrobin
server tomcat1 10.0.0.1:8080 check
backend tomcat_abc
balance roundrobin
server tomcat2 10.0.0.2:8080 check
For more complex path-based routing scenarios, you might need:
frontend http-in
bind *:80
acl is_main hdr(host) -i www.xyz.com
acl is_main_path path_reg ^/(?!abc)
use_backend tomcat_main if is_main is_main_path
use_backend tomcat_abc if { hdr(host) -i abc.xyz.com } || { path_beg /abc }
default_backend tomcat_main
If you need HTTPS support, add this to your frontend:
frontend https-in
bind *:443 ssl crt /etc/ssl/xyz.com.pem
http-request set-header X-Forwarded-Proto https if { ssl_fc }
acl is_abc hdr(host) -i abc.xyz.com
use_backend tomcat_abc if is_abc
default_backend tomcat_main
Here's a complete configuration that combines all elements:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http-in
bind *:80
acl is_main hdr(host) -i www.xyz.com
acl is_abc hdr(host) -i abc.xyz.com
acl is_abc_path path_beg /abc
use_backend tomcat_abc if is_abc or is_abc_path
use_backend tomcat_main if is_main
default_backend tomcat_main
backend tomcat_main
balance roundrobin
server tomcat1 10.0.0.1:8080 check
http-request set-header X-Forwarded-Host %[req.hdr(host)]
http-request set-header X-Forwarded-Port %[dst_port]
backend tomcat_abc
balance roundrobin
server tomcat2 10.0.0.2:8080 check
http-request set-header X-Forwarded-Host %[req.hdr(host)]
http-request set-header X-Forwarded-Port %[dst_port]
When working with HAProxy for complex routing scenarios, we often need to direct traffic based on either subdomains or URL paths to different backend servers. In this case, we need to handle both www.xyz.com
and abc.xyz.com
(or www.xyz.com/abc
) routing to separate Tomcat servers.
Here's the foundational HAProxy configuration we'll build upon:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
For routing based on subdomains (abc.xyz.com
to 10.0.0.2):
frontend http-in
bind *:80
acl host_abc hdr(host) -i abc.xyz.com
use_backend backend_abc if host_abc
default_backend backend_www
backend backend_www
server server1 10.0.0.1:8080 check
backend backend_abc
server server2 10.0.0.2:8080 check
If you prefer path-based routing (www.xyz.com/abc
to 10.0.0.2):
frontend http-in
bind *:80
acl path_abc path_beg -i /abc
use_backend backend_abc if path_abc
default_backend backend_www
backend backend_www
server server1 10.0.0.1:8080 check
backend backend_abc
server server2 10.0.0.2:8080 check
For handling both subdomain and path-based routing simultaneously:
frontend http-in
bind *:80
acl host_abc hdr(host) -i abc.xyz.com
acl path_abc path_beg -i /abc
use_backend backend_abc if host_abc or path_abc
default_backend backend_www
backend backend_www
server server1 10.0.0.1:8080 check
backend backend_abc
server server2 10.0.0.2:8080 check
For production environments, you'll want SSL termination:
frontend https-in
bind *:443 ssl crt /etc/ssl/xyz.com.pem
acl host_abc hdr(host) -i abc.xyz.com
acl path_abc path_beg -i /abc
use_backend backend_abc if host_abc or path_abc
default_backend backend_www
frontend http-redirect
bind *:80
redirect scheme https code 301 if !{ ssl_fc }
For more complex scenarios, you might want to:
- Add health checks to your backend servers
- Implement load balancing across multiple instances
- Add request/response header modifications
- Configure logging for troubleshooting