Haproxy, Lua and client's IP simple application

By Лука Билановић | July 28, 2018

Ever since haproxy started supporting embedded lua applications, I wanted to write one :) Finally I got chance to write simple application just a litte more than hello world - application that will emit your IP address via HTTP. First step is to write lua script and place it somewhere on FS (preferably somewhere under /etc/haproxy):

bilke@io:~$ cat /etc/haproxy/ip.lua
core.register_service("ip", "http", function(applet)
   local src = applet.sf:src()
   local response = tostring(src) .. "\n"
   applet:set_status(200)
   applet:add_header("content-length", string.len(response))
   applet:add_header("content-type", "text/plain")
   applet:start_response()
   applet:send(response)
end)

We are registering lua function executed as a HTTP service and named ip. Then we are using AppletHTTP’s Fetches class to get access to haproxy samples - and in our case src() sample - which is holding value of the remote IP. Then we are convering address to string, concating new line at the end and emmting it in simple HTTP plain text response with minimum of necessay headers along with HTTP/200 response code.

Haproxy configuration is quite simple. First we need to load lua script and we are doing that (as the last line) in global section of our haproxy.cfg:

global
[...]
[...]

        lua-load /etc/haproxy/ip.lua

And finally we are configuring host and path (if needed other conditions too) in simple ACL in frontend section and http-request/response with our lua application if that ACL’s conditions are met:

frontend http-https-in
[...]
[...]
        acl ip_application path /ip and hdr(host) -i io.bot.nu
        http-request use-service lua.ip if METH_GET ip_application

Restart haproxy and test it:

bilke@longitude:~$ curl -4 io.bot.nu/ip
139.162.127.169

bilke@longitude:~$ curl -6 io.bot.nu/ip
2a01:7e81::a03c:92ff:fea8:66eb

Not only it works, but it’s blazingly fast - 40745 requests/responses per second

bilke@io:~$ wrk -c 80 -d 10 -t 4 http://localhost/ip
Running 10s test @ http://localhost/ip
  4 threads and 80 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.93ms  292.35us   9.40ms   86.58%
    Req/Sec    10.24k   339.71    10.81k    85.75%
  407753 requests in 10.01s, 26.44MB read
Requests/sec:  40745.34
Transfer/sec:      2.64MB

If you need fast, simple (and not so simple) TCP/HTTP service lua+haproxy is a way to go!