HAProxy - Lua (Built-in HTTP Client)

🚧

Supported versions

This DataDome module is supported with HAProxy 2.6.8+ and 2.7.1+ as it requires a built-in HTTP client to call DataDome's Protection API.

Installation

If you already have HAProxy binary with Lua support, you can skip this section.

You can check HAProxy version by running

$ haproxy -v
HAProxy version 2.6.8-1ppa1~jammy 2023/01/24 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2027.
Known bugs: http://www.haproxy.org/bugs/bugs-2.6.8.html
Running on: Linux 5.15.0-1028-aws #32-Ubuntu SMP Mon Jan 9 12:28:07 UTC 2023 x86_64

You can validate Lua Version using

$ haproxy -vv
HAProxy version 2.6.8-1ppa1~jammy 2023/01/24 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2027.
[...]
Built with Lua version : Lua 5.3.6
[...]

Configuration

You need to follow the steps below:

  1. Download the latest DataDome module from this link here and extract it in your HAProxy configuration directory.
    The archive includes the following files:
  • datadome.lua: a Lua script that handles the transformation of the HTTP request
  • core/helper.lua: Lua scripts to manipulate strings and HTTP Requests
  • haproxy.cfg: Example file of a working configuration
  1. Edit the HAProxy configuration file and set DATADOME_SERVERSIDE_API_KEY with your own API server key provided by DataDome. You can find this key inside our dashboard.
  2. Update your HAProxy configuration file by replacing <PATH> with the actual path where you placed the file, and setting the different blocks needed:
  3. Add the txn.placeholderX variable in the frontend to protect
  4. Add the request/response hook as in the example below
global
    [...]
    lua-load <PATH>/datadome.lua
    set-var proc.Datadome_key str("DATADOME_SERVERSIDE_API_KEY") # Set your serverside key here
    [...]

# Example of frontend which will be protected
frontend http
    [...]
    # Insert these lines on each frontend you want to protect
    http-request set-var(txn.placeholder1) var(txn.dd.x_datadome_request_headers)
    http-request set-var(txn.placeholder2) var(txn.dd.x_datadome_headers)
    http-request set-var(txn.placeholder3) var(txn.dd.x_datadome_response)
    http-request set-var(txn.placeholder4) var(txn.dd.body)
    http-request set-var(txn.placeholder5) var(txn.dd.error)
    
    # Here check uri is not in exclusion path
		acl excluded_files path_reg -i .\.(avi|flv|mka|mkv|mov|mp4|mpeg|mpg|mp3|flac|ogg|ogm|opus|wav|webm|webp|bmp|gif|ico|jpeg|jpg|png|svg|svgz|swf|eot|otf|ttf|woff|woff2|css|less|jsf|js|map)$
    
    http-request lua.Datadome_request_hook if !excluded_files
    http-response lua.Datadome_response_hook
    
    # Insert this line before all default_backend / use_backend directives
    use_backend failure_backend if { var(txn.dd.status) -m str blocked }
    default_backend [...]

# Backend to server the "blocked page"
backend failure_backend
    mode http
    http-request    use-service     lua.failure_service

Settings

SettingsDescriptionDefault ValueRequiredFile
DataDome_Key (*haproxy.cfg)Your DataDome server-side key - Available inside our dashboardYeshaproxy.cfg
EndpointURL of the closest endpoint.
More info here
api.datadome.coOptionaldatadome.lua
TimeoutAPI request timeout for reused connections in ms150msOptionaldatadome.lua

FAQ

How can I have DataDome response status in the log?

  • For each request protected by DataDome, the txn.dd.x_datadome_response contains the value of the HTTP response API
  • If there is an issue in the call to Datadome, the variable txn.dd.error contains the error code and details.
  • the main errors are as follow:
    • 400 - Bad Request (Invalid DataDome Key ?)
    • 504 - API Server times out
    • 503 - Invalid response from API Server

How can I get Bot Name, RuleType and Bot/Human flags in my application?

It is possible to specify a Log-Format to log the returned Datadome Headers
Some headers returned by the API are:

  • X-DataDome-botname
  • X-DataDome-ruletype
  • X-DataDome-isbot
  • X-DataDome-requestid
  • ...
    and can be logged using the method lua.ddHeaders as follow
log-format "X-DataDome-botname: %{+Q}[lua.ddHeaders(X-DataDome-botname)] | X-DataDome-family: %{+Q}[lua.ddHeaders(X-DataDome-ruletype)] | X-DataDome-isbot: %{+Q}[lua.ddHeaders(X-DataDome-isbot)] | %{+Q}[lua.ddHeaders(X-DataDome-requestid)]"

You can find more information here.

How can I exclude files from DataDome protection?

In the Haproxy configuration, option to call DataDome is managed by an HAProxy ACL.
Default ACL is as follow

acl excluded_files path_reg -i .\.(avi|flv|mka|mkv|mov|mp4|mpeg|mpg|mp3|flac|ogg|ogm|opus|wav|webm|webp|bmp|gif|ico|jpeg|jpg|png|svg|svgz|swf|eot|otf|ttf|woff|woff2|css|less|jsf|js|map)$

It can be completed by custom rules / other ACLs