# How do I serve a single static file from HAProxy?

**URL:** <https://discourse.haproxy.org/t/how-do-i-serve-a-single-static-file-from-haproxy/32>\
**Category:** Help!\
**Created:** [December 9, 2015, 10:02pm UTC](https://discourse.haproxy.org/t/how-do-i-serve-a-single-static-file-from-haproxy/32 "2015-12-09T22:02:57Z")\
**Posts on this page:** 1\
**Showing post:** 11

<div class="post-metadata">

**Author:** ![gladiac](https://avatars.discourse-cdn.com/v4/letter/g/96bed5/32.png) [@gladiac](https://discourse.haproxy.org/u/gladiac)\
**Post date:** [December 23, 2018, 1:34pm UTC](https://discourse.haproxy.org/t/how-do-i-serve-a-single-static-file-from-haproxy/32/11 "2018-12-23T13:34:23Z")

</div>

Hey there,  
I came up with the following solution for serving files just **like a web-server** would do with the help of LUA. The following _frontend-config_ sets the HTTP-header **X-LUA-LOADFILE-DOCROOT** with a local directory path which serves as the document-root. Furthermore, it defines a lua-service called load-file. See:

```
lua-load /etc/haproxy/lua/load-file.lua

...

backend lua-load-file
  http-request set-header X-LUA-LOADFILE-DOCROOT /etc/haproxy/docroot
  http-request use-service lua.load-file

```

As you can see I load a lua-file called _load-file.lua_. The contents of that file are as follows:

```
core.register_service("load-file", "http", function(applet)
  local docroot
  local location
  local file
  local retval
  local response
  local extension

  if(applet.path == nil or applet.headers["x-lua-loadfile-docroot"] == nil or applet.headers["x-lua-loadfile-docroot"][0] == "") then
    retval = 500
    response = "Internal Server Error"
  else
    docroot = applet.headers["x-lua-loadfile-docroot"][0]
    location = applet.path
    if(location == "" or location == "/") then
      location = "/index.html"
    end
    file = io.open(docroot .. location, "r")
    if(file == nil) then
      retval = 404
      response = "File Not Found"
    else
      retval = 200
      response = file:read("*all")
      file:close()
    end
  end

  extension = string.match(location, ".(%w+)$")
  if extension == "css" then applet:add_header("content-type", "text/css")
    elseif extension == "gif" then applet:add_header("content-type", "image/gif")
    elseif extension == "htm" then applet:add_header("content-type", "text/html")
    elseif extension == "html" then applet:add_header("content-type", "text/html")
    elseif extension == "ico" then applet:add_header("content-type", "image/x-icon")
    elseif extension == "jpg" then applet:add_header("content-type", "image/jpeg")
    elseif extension == "jpeg" then applet:add_header("content-type", "image/jpeg")
    elseif extension == "js" then applet:add_header("content-type", "application/javascript; charset=UTF-8")
    elseif extension == "json" then applet:add_header("content-type", "application/json")
    elseif extension == "mpeg" then applet:add_header("content-type", "video/mpeg")
    elseif extension == "png" then applet:add_header("content-type", "image/png")
    elseif extension == "txt" then applet:add_header("content-type", "text/plain")
    elseif extension == "xml" then applet:add_header("content-type", "application/xml")
    elseif extension == "zip" then applet:add_header("content-type", "application/zip")
  end

  applet:set_status(retval)
  if(response ~= nil and response ~= "") then
    applet:add_header("content-length", string.len(response))
  end
  applet:start_response()
  applet:send(response)
end)

```

Basically, this code reads files from a specified document-root location in the filesystem based on the query string and generates appropriate HTTP-responses just as a normal webserver would do. That is why the script needs a document-root do be configured via the HTTP-header **X-LUA-LOADFILE-DOCROOT**. Furthermore, the code also does some very basic mimetype handling - extend the list according your needs. I hope someone finds this useful.

cheers!

---

_[View the full topic](https://discourse.haproxy.org/t/how-do-i-serve-a-single-static-file-from-haproxy/32)._
