HAProxy Subdomain and Path-Based Routing Configuration for Tomcat Backends


2 views

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