Using HAproxy as a reverse proxy

HAproxy has a great feature set when used in conjunction with Wt:
  • Uses async I/O and thus handles thousands of connections without any problem. Just like Wt!
  • Supports reverse proxying of WebSocket connections (as per draft-76).
  • Can be configured to use session affinity without needing cookies.

You need a fairly recent of haproxy for the options 'http-server-close' and 'http-pretend-keepalive' to work, which is needed for reliable load-balancing.

Basic setup

global
        log 127.0.0.1 local0
        log 127.0.0.1 local1 notice
        maxconn 4096
        user haproxy
        group haproxy
        daemon

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        option  http-server-close
        option  http-pretend-keepalive
        option  forwardfor
        option  originalto
        retries 3
        option redispatch
        maxconn 2000
        contimeout      5000
        clitimeout      50000
        srvtimeout      50000

listen 0.0.0.0:8181
        server srv1 0.0.0.0:9090 check

Using session affinity

All of the built-in mechanisms in HAproxy for session affinity using the appsession option rely on cookies, but cookies are not our preferred method since this does not give an intuitive user experience (e.g. a user cannot open multiple sessions), are not entirely reliable (a user can disable cookies) and a source of security risks (CSRF).

Luckily there is a work-around: using Wt's ability to generate session-id's that have a prefix which identifies the back-end, we can have HAproxy match on this prefix in the request URL and send the requests to the correct server.

Below is an example configuration for two back-end servers. http://svtros.ru

global
    log 127.0.0.1 local0 
    log 127.0.0.1 local1 notice
    maxconn 4096
    user haproxy
    group haproxy
    daemon

defaults
    log    global
    mode    http
    option    httplog
    option    dontlognull
        option  http-server-close
        option  http-pretend-keepalive
        option  forwardfor
        option  originalto
    retries    3
    option redispatch
    maxconn    2000
    contimeout    5000
    clitimeout    50000
    srvtimeout    50000

frontend wt
        bind 0.0.0.0:80
        acl srv1 url_sub wtd=wt1
        acl srv2 url_sub wtd=wt2
        acl srv1_up nbsrv(bck1) gt 0
        acl srv2_up nbsrv(bck2) gt 0
        use_backend bck1 if srv1_up srv1
        use_backend bck2 if srv2_up srv2
        default_backend bck_lb

backend bck_lb
        balance roundrobin
        server srv1 0.0.0.0:9090 track bck1/srv1
        server srv2 0.0.0.0:9091 track bck2/srv2

backend bck1
        balance roundrobin
        server srv1 0.0.0.0:9090 check

backend bck2
        balance roundrobin
        server srv2 0.0.0.0:9091 check

And start the two Wt httpd servers using:

$ app.wt --session-id-prefix=wt1 --http-port 9090 ...
$ app.wt --session-id-prefix=wt2 --http-port 9091 ...

Running multiple apps for multiple domains

In case you want different apps to be bound to different domains then I have the following configuration for you.
In my case it's a virtual Server for testing and development as well. With Apache to test wordpress and other things.
To not immediately show changes on the Main Page I have a second instance running, but see for yourself:

I hope the comments are self explanatory even for beginners like I have been =)

global
    maxconn 4096
    user     haproxy
    group    haproxy
    daemon

defaults
    log     global
    mode     http
    option    httplog
    option    dontlognull

    option    http-pretend-keepalive
    option    forwardfor
    option     originalto
    option     redispatch

    retries    3

    timeout    connect    5000
    timeout    client    50000
    timeout server     50000

frontend http-in
    bind *:80

# Having a .wt Application-Server for development/testing purposes with access regardless of path
#    but subdomain is dev: dev.sample.com / dev.example.com
#    While having several domains pointing to the same physical server
    acl is_dev_URL hdr_beg(host) -i dev.

# Main-Page to load when connecting to host: should load sample.com/wt1
    acl is_wt_Main   hdr_end(host) sample.com

# Secondary Page shown when connecting from 2nd URL: example.com/wt2
        acl is_wt_Second hdr_end(host) example.com

# Having apache for other reasons, too: testing wordpress / something
#     refers to specific path: html
        acl apache_path path_beg /html

# Following a folder architecture within docroot like:
#    docroot/wt1/[styles][images][whatever] 
#    docroot/wtSecondary/[styles][images] 
#       ->Just giving an example of having another folder name than deployment path

    acl wt_path     path_beg /wt1
    acl wt_path     path_beg /wt2
    acl wt_resource path_beg /resources
    acl wt_resource path_beg /wt1
    acl wt_resource path_beg /wtSecondary

# Checking whether Servers are up or down
    acl wt_srv_up nbsrv(wt_hp) gt 0
    acl wt_dev_up nbsrv(wt_dev) gt 0

# The Redirections:
#  Redirect to Location /wt1 if Main-Page,  no other app, Server is up, no apache path, no resource path, and no dev-server
    redirect location /wt1   if is_wt_Main  !wt_path      wt_srv_up     !apache_path    !wt_resource      !is_dev_URL

# Redirect Secondary
    redirect location /wt2   if is_wt_Second !wt_path wt_srv_up !apache_path !wt_resource !is_dev_URL

# Choose the Backend
    use_backend apache    if apache_path !wt_srv_up 

# HAProxy 1.5.x + :
    default_backend wt

# HAProxy 1.4.x - :
#    use_backend wt_live     if is_wt_Main is_wt_Second wt_path !is_dev_URL wt_srv_up
#     use_backend wt_dev    if is_dev_URL wt_dev_up

# The Backends
backend wt

# use-server is only available in HAProxy 1.5.x
        use-server Wt_Live unless is_dev_URL
    server Wt_Live  0.0.0.0:9050 track wt_hp/Wt_Live

    use-server Wt_Dev if is_dev_URL
    server Wt_Dev   0.0.0.0:9020 track wt_dev/Wt_Dev

backend wt_hp
    balance roundrobin  
    server Wt_Live 0.0.0.0:9050 check

backend apache
    balance roundrobin
    timeout connect 10s
    timeout server     30s
    server apache1 0.0.0.0:8050 check

backend wt_dev
    balance roundrobin
    server Wt_Dev 0.0.0.0:9020 check

This is also updated to exclude deprecated keywords