Microsoft Remote Desktop Services (RDS) Load-Balancing

Microsoft Remote Desktop services (RDS)

Remote Desktop Services, formerly Terminal Services, is a technology from Microsoft that allows users to access remotely to a session-based desktop, virtual machine-based desktop or applications hosted in a datacenter from their corporate network or from the internet.

Multiple RDS servers can be used in a farm. Hence we need to balance the load against them.
To achieve this purpose, we have different ways:
* using a connection broker
* using a load-balancer with the connection broker
* using a load-balancer without the connection broker

Of course, our load-balancer of choice is HAProxy!
In this blog article, we’re going to focus only on the case where a load-balancer is used.

The main issue when load-balancing multiple Remote Desktop Services servers is to ensure a user the continuity of his session in case of a network outage.

Current article will focus on session high availability for an optimal end user experience.

HAProxy with a connection broker

The connection broker, formerly Session broker, main purpose is to reconnect a user to his existing session. Since Windows 2008, the connection broker also have some load-balancing mechanism.

So, why using a load-balancer if the connection broker can do load-balance?

Answer is simple: security. Since HAProxy is a Reverse-Proxy, it breaks the TCP connection between the client and the server. HAProxy can be deployed in DMZ to give access to users coming from internet to a RDS farm deployed in the VLAN dedicated to servers.

HAProxy configuration

Note: this configuration works for the ALOHA 6.0 and above and HAPEE (HAProxy Enterprise Edition) 1.5 and above.

frontend ft_rdp
  mode tcp
  bind name rdp
  timeout client 1h
  log global
  option tcplog
  tcp-request inspect-delay 2s
  tcp-request content accept if RDP_COOKIE
  default_backend bk_rdp

backend bk_rdp
  mode tcp
  balance leastconn
  persist rdp-cookie
  timeout server 1h
  timeout connect 4s
  log global
  option tcplog
  option tcp-check
  tcp-check connect port 3389 ssl
  default-server inter 3s rise 2 fall 3
  server srv01 weight 10 check
  server srv02 weight 10 check

HAProxy without a connection broker

HAProxy can be used on its own to perform session load-balancing and resumption. For this purpose, it needs a stick-table where the user-server association is stored.
A peers section is added to the configuration. So we can share session persistence information between a cluster of ALOHAs or HAPEE servers.

peers aloha
 peer aloha1
 peer aloha2

frontend ft_rdp
  mode tcp
  bind name rdp
  timeout client 1h
  log global
  option tcplog
  tcp-request inspect-delay 2s
  tcp-request content accept if RDP_COOKIE
  default_backend bk_rdp

backend bk_rdp
  mode tcp
  balance leastconn
  timeout server 1h
  timeout connect 4s
  log global
  option tcplog
  stick-table type string len 32 size 10k expire 8h peers aloha
  stick on rdp_cookie(mstshash)
  option tcp-check
  tcp-check connect port 3389 ssl
  default-server inter 3s rise 2 fall 3
  server srv01 weight 10 check
  server srv02 weight 10 check

To know the user-server association, we can simply read the content of the stick-table:

echo show table bk_rdp | socat /var/run/haproxy.stat -
# table: bk_rdp, type: string, size:10240, used:5
0x21c7eac: key=Administrator use=0 exp=83332288 server_id=1
0x21c7eac: key=test-001 use=0 exp=83332288 server_id=2

We can easily read the login used by the user, the expiation date (in milliseconds) and the server ID used for the session.


Posted in Aloha, architecture, HAPEE, HAProxy, Uncategorized | Tagged , , , , | Leave a comment

HAProxy 1.6-dev1 and LUA

HAProxy 1.6-dev1

Yesterday, Willy has released HAProxy 1.6-dev1: ANNOUNCE HAProxy 1.6-dev1.
This version contains many new features and core improvements. Amongst the new features, one is LUA, contributed by Thierry (HAProxy Technologies developer).

NOTE: We invite everyone to download and test HAProxy 1.6-dev1 and to report bugs to the mailing list.

Please note that there may be a code freeze of HAProxy 1.6 in May. Purpose is to release a stable version in September.


LUA is a powerful, fast, lightweight, embeddable scripting language.

More about lua

The main advantage of LUA for HAProxy is to give the ability to anyone to write their own features without having to know writing C code and patching HAProxy…

About this article

Please note that LUA integration in HAProxy is brand new. So the information provided here are true today but may be obsolete later, because of internal changes and updates.

Compiling HAProxy and LUA

Installaing LUA 5.3

For now, HAProxy requires LUA 5.3 to work, here is the procedure to install it:

cd /usr/src
curl -R -O
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make linux
sudo make INSTALL_TOP=/opt/lua53 install

LUA 5.3 library and include files are now installed in /opt/lua53.

Compiling HAProxy for lua

Since HAProxy is in a dev state, we may encounter some bugs. Let’s enable some debugging features:

make DEBUG=-ggdb CFLAGS=-O0 TARGET=linux2628 \
USE_LUA=yes LUA_LIB=/opt/lua53/lib/ \
LUA_INC=/opt/lua53/include/ LDFLAGS=-ldl

Using LUA in HAProxy

turning HAProxy as a mirror web server

By mirror web server, I mean a web server which returns the request in the body of the response, without any modification.
It may be useful to use in HAProxy when you want to setup some HTTP header manipulation in HAProxy and you want to see the result. (It is more convenient than tcpdump).

* First, the HAProxy configuration:

 lua-load ./mylua.lua

 mode http
 timeout connect 1s
 timeout client 1s
 timeout server 1s

frontend fe
 bind name fe
 acl debugme req.hdr_cnt(X-debug-me) ge 1
 # add your http manipulation rules here
 http-request lua mirror if debugme
 default_backend be

backend be
 server s

* And the LUA which does the mirroring of the request:

-- a simple mirror web server
-- it generates a response whose body contains the requests headers
function mirror(txn)
local buffer = ""
local response = ""
local mydate =

buffer = buffer .. "You sent the following headers\r\n"
buffer = buffer .. "===============================================\r\n"
buffer = buffer .. txn.req:dup()
buffer = buffer .. "===============================================\r\n"

response = response .. "HTTP/1.0 200 OK\r\n"
response = response .. "Server: haproxy-lua/mirror\r\n"
response = response .. "Content-Type: text/html\r\n"
response = response .. "Date: " .. mydate .. "\r\n"
response = response .. "Content-Length: " .. buffer:len() .. "\r\n"
response = response .. "Connection: close\r\n"
response = response .. "\r\n"
response = response .. buffer


Some explanations:
* mydate is the result of an HAProxy converter applied to an HAProxy fetch txn.f:date()
* The call to txn.req:dup returns the content of HAProxy’s buffer request.

Testing: simply run a curl against HAProxy, don’t forget to send a X-debug-me HTTP header with the parameter -H "X-debug-me: yes". HAProxy should return your request in the response body:

HTTP/1.0 200 OK
Server: haproxy-lua/mirror
Content-Type: text/html
Date: Fri, 12 Mar 2015 13:06:44 GMT
Content-Length: 208
Connection: keep-alive

You sent the following headers
GET / HTTP/1.1
User-Agent: curl/7.41.0
Accept: */*



Posted in HAProxy | Tagged , , | Leave a comment

A HTTP monitor which matches multiple conditions in HAProxy

Load-Balancing and health checking

Health checking is the method to check a service availability on a server.
It is one of the most important feature of a load-balancer. How could we balance traffic amongst servers if we don’t know if the service is alive???

HAProxy and HTTP check

HAProxy can probe HTTP applications using httpchk option.
This option can be customized using the http-check expect directive to match different status codes or content.
That said, a single http-check expect rule can match.
So we can’t match a status code and the presence of a string in the page, for example.

Make HAProxy match multiple conditions for HTTP health checking

The solution is to use to the raw tcp-check and write a health check script sequence which match all the conditions.

For example, you want to ensure the server’s response has:

  • HTTP status code is 200
  • absence of keyword Error
backend myapp
 option tcp-check
 tcp-check send GET\ /my/check/url\ HTTP/1.1\r\n
 tcp-check send Host:\ myhost\r\n
 tcp-check send Connection:\ close\r\n
 tcp-check send \r\n
 tcp-check expect string HTTP/1.1\ 200\ OK
 tcp-check expect ! string Error


Posted in architecture, HAProxy, layer7 | Tagged , , | Leave a comment

Web application name to backend mapping in HAProxy


Let’s take a web application platform where many HTTP Host header points to.
Of course, this platform hosts many backends and HAProxy is used to perform content switching based on the Host header to route HTTP traffic to each backend.

HAProxy map

HAProxy 1.5 introduced a cool feature: converters. One converter type is map.
Long story made short: a map allows to map a data in input to an other one on output.

A map is stored in a flat file which is loaded by HAProxy on startup. It is composed by 2 columns, on the left the input string, on the right the output one:

in out

Basically, if you call the map above and give it the in strings, it will return out.


Now, the interesting part of the article 🙂

As stated in introduction, we want to map hundreds of Host headers to tens of backends.

The old way of mapping: acl and use_backend rules

Before the map, we had to use acls and use_backend rules.

like below:

frontend ft_allapps
 use_backend bk_app1 if { hdr(Host) -i }
 use_backend bk_app2 if { hdr(Host) -i }
 default_backend bk_default

Add one statement per use_backend rule.

This works nicely for a few backends and a few domain names. But this type of configuration is hardly scallable…

The new way of mapping: one map and one use_backend rule

Now we can use map to achieve the same purpose.

First, let’s create a map file called, with the following content: on the left, the domain name, on the right, the backend name:

#domainname  backendname bk_app1 bk_app1 bk_app2 bk_app2

And now, HAProxy configuration:

frontend ft_allapps
 use_backend %[req.hdr(host),lower,map(/etc/hapee-1.5/,bk_default)]

Here is what HAProxy will do:

  1. req.hdr(host) ==> fetch the Host header from the HTTP request
  2. lower ==> convert the string into lowercase
  3. map(/etc/hapee-1.5/ ==> look for the lowercase Host header in the map and return the backend name if found. If not found, the name of a default backend is returned
  4. route traffic to the backend name returned by the map

Now, adding a new content switching rule means just add one new line in the map content (and reload HAProxy). No regexes, map data is stored in a tree, so processing time is very low compared to matching many string in many ACLs for many use_backend rules.

simple is beautiful!!!

HAProxy map content auto update

If you are an HAPEE user (and soon available for the ALOHA), you can use the lb-update content to download the content of the map automatically.
Add the following statement in your configuration:

 update id url delay 60s timeout 5s retries 3 map


Posted in Aloha, architecture, HAPEE, HAProxy, layer7, optimization, performance | Tagged , , , , , , , , | Leave a comment

HAProxy and sslv3 poodle vulnerability

SSLv3 poodle vulnerability

Yesterday, Google security researchers have disclosed a new vulnerability on SSL protocol.
Fortunately, this vulnerability is only on an old version of the SSL protocol: SSLv3 (15 years old protocol).
An attacker can force a browser to downgrade the protocol version used to cipher traffic to SSLv3 in order to exploit the POODLE vulnerability and access to data in clear.

Some reading about SSLv3 Poodle vulnerability:

Today’s article is going to explain how to use HAProxy to simply prevent using SSLv3 or to prevent those users to reach your applications and print them a message.

Disable SSLv3 in HAProxy

In SSL offloading mode

In this mode, HAProxy is the SSL endpoint of the connection.
It’s a simple keyword on the frontend bind directive:

  bind ssl crt /pat/to/cert.pem no-sslv3

In SSL forward mode

In this mode, HAProxy forwards the SSL traffic to the server without deciphering it.
We must setup an ACL to match the SSL protocol version, then we can refuse the connection. This must be added in a **frontend** section:

  tcp-request inspect-delay 2s
  acl sslv3 req.ssl_ver 3
  tcp-request content reject if sslv3

Communicate a message to users

Denying sslv3 is a good way, but a better one would to educate as well users who are using this protocol.
The configuration below shows how to redirect a user to a specific page when they want to use your application over an SSLv3 connection. Of course, HAProxy must allow itself SSLv3:

frontend ft_www
  bind ssl crt /pat/to/cert.pem
  acl sslv3 ssl_fc_protocol SSLv3
# first rule after all your 'http-request deny' and
# before all the redirect, rewrite, etc....
  http-request allow if sslv3
# first content switching rule
  use_backend bk_sslv3 if sslv3

backend bk_sslv3
  mode http
  errorfile 503 /etc/haproxy/pages/sslv3.http

And the content of the file /etc/haproxy/pages/sslv3.http:

HTTP/1.0 200 OK
Cache-Control: no-cache
Connection: close
Content-Type: text/html

<title>SSLv3 spotted</title>
<body><h1>SSLv3 spotted</h1></body>
SSLv3 forbidden for your safety:<BR><BR>
If you want to browse this website, you should upgrade your browser.


Posted in HAProxy, security, ssl | Tagged , , , , | 7 Comments

Mitigating the shellshock vulnerability with HAProxy

Bash Shellshock vulnerability (CVE-2014-6271 and CVE-2014-7169)

Last week, a vulnerability in bash has been discovered. It is possible, under some circumstances, to inject code into a bash shell script.
It could be very dangerous if bash is used to process request sent remotely.
For now, you’re safe if no bash scripts are called by services with remote accesses.

Some reading about bash shellshock vulnerability:

Today’s article is going to explain how to use HAProxy to protect your application from bash shellshock vulnerability if you’re in the case where you have to be protected.


The diagram is pretty simple. Our purpose will to detect any purposely built requests and to prevent them to reach the server:

|                                                 |
| +----------+     +---------+     +------------+ |
| |          |     |         |     |            | |
| | Attacker | +-> | HAProxy | +-> | Vulnerable | |
| |          |     |         |     | server     | |
| +----------+     +---------+     |            | |
|                                  +------------+ |
|                                                 |


Place the configuration sniplet into your HAProxy frontend configuration:

  reqdeny  ^[^:]+:\s*\(\s*\)\s+\{
  reqdeny  ^[^:]+:\s+.*?(<<[^<;]+){5,}

Of course, your frontend must be in http mode and HAProxy must have been compiled with USE_PCRE option.

HAProxy will return a 403 if a request matches the shellshock attack.

Note: greeting to Thomas for providing the tip on HAProxy’s mailing list


Posted in HAProxy, security | Tagged | Leave a comment

binary health check with HAProxy 1.5: php-fpm/fastcgi probe example

Application layer health checking

Health checking is the ability to probe a server to ensure the service is up and running.
This is one of the root feature of any load-balancer.

One can probe servers and services at different layer of the OSI model:
  * ARP check (not available in HAProxy)
  * ICMP (ping) check (not available in HAProxy)
  * TCP (handshake) check
  * Application (HTTP, MySql, SMTP, POP, etc…) check

The most representative of the application status the check is, the best.

This means that the best way to check a service is to “speak” the protocol itself.
Unfortunately, it is impossible to write one check per protocol, there are too many protocols and some of them are proprietary and/or binary.
That’s why HAProxy 1.5 now embeds a new health checking method called “tcp-check“. It is very simple and basic “send/expect” probing method where HAProxy can send arbitrary strings and match string or regex comparison on server responses.
Many send and expect can be executed in a row to determine the status of a server.

I’ve already explained how to check redis server and how to balance traffic only to the redis master server of a cluster.

Today’s article introduces a binary protocol widely deployed: fastcgi used by php-fpm.

fastcgi binary ping/pong health check

fastcgi is a binary protocol. It means data on the network are not readable by humans, like HTTP or SMTP.
php-fpm relies on this protocol to treat PHP code. It is common to use HAProxy to load-balance many php-fpm servers for resiliency and scalability.

php-fpm Configuration

Enable a dedicated url to probe and setup the response in your php-fpm configuration:

ping.path = /ping
ping.response = pong

Which means HAProxy has to send a fastcgi request on /ping and expects the server to response with “pong“.

HAProxy health checking for php-fpm

Add the following tcp-check sequence in your php-fpm backend to probe the /ping url and ensure the server answers a “pong“.
The comment at the end of the line describe the php-cgi protocol fields.

option tcp-check
 tcp-check send-binary   01 # version
 tcp-check send-binary   01 # FCGI_BEGIN_REQUEST
 tcp-check send-binary 0001 # request id
 tcp-check send-binary 0008 # content length
 tcp-check send-binary   00 # padding length
 tcp-check send-binary   00 #
 tcp-check send-binary 0001 # FCGI responder
 tcp-check send-binary 0000 # flags
 tcp-check send-binary 0000 #
 tcp-check send-binary 0000 #
 tcp-check send-binary   01 # version
 tcp-check send-binary   04 # FCGI_PARAMS
 tcp-check send-binary 0001 # request id
 tcp-check send-binary 0045 # content length
 tcp-check send-binary   03 # padding length: padding for content % 8 = 0
 tcp-check send-binary   00 #
 tcp-check send-binary 0e03524551554553545f4d4554484f44474554 # REQUEST_METHOD = GET
 tcp-check send-binary 0b055343524950545f4e414d452f70696e67   # SCRIPT_NAME = /ping
 tcp-check send-binary 0f055343524950545f46494c454e414d452f70696e67 # SCRIPT_FILENAME = /ping
 tcp-check send-binary 040455534552524F4F54 # USER = ROOT
 tcp-check send-binary 000000 # padding
 tcp-check send-binary   01 # version
 tcp-check send-binary   04 # FCGI_PARAMS
 tcp-check send-binary 0001 # request id
 tcp-check send-binary 0000 # content length
 tcp-check send-binary   00 # padding length: padding for content % 8 = 0
 tcp-check send-binary   00 #

 tcp-check expect binary 706f6e67 # pong

Note that the whole send string could be written on a single line.

Any protocol???

If some day, you have to do the same type of configuration on a protocol nobody knows, simply capture network traffic of a “hello” sequence using tcpdump.
Then send the tcp payload cpatured using the tcp-check send command and configure the appropriate expect.
And it will work!


Posted in Aloha, HAProxy | Tagged , , , , | 1 Comment