The Lua scripting language was developed in 1993 at the University of Rio de Janeiro and was placed under the MIT license as of version 5 . The interpreter, which weighs in at just a few kilobytes, is seriously fast and can use a C interface to dock with other programs. This has made Lua very popular in the gaming industry in particular. But Lua has slowly made inroads into more serious applications, such as Adobe's Lightroom or Wireshark. Lua itself is an imperative and functional language, with rudimentary support for object-oriented programming. The syntax uses a minimum of keywords, which – on the downside – makes Lua programs more cryptic than their PHP counterparts.
Thanks to all these properties, Lua would seem to be an obvious choice of scripting language for web servers. Thus, it is no surprise that modules for Apache have been presented at various phases of the language's history. The ambitious Kepler project took this one step further , introducing a number of self-developed tools, libraries, and standards that aimed to give developers the ability to produce complete web applications simply in Lua. One of the results was Xavante , a web server written in Lua. The Kepler project has been dormant since 2010; the many Apache modules never made the cut for the official Apache package and thus quickly disappeared from sight – with one exception.
In 2006, Brian McCallister started work on a module with the slightly wacky name of
mod_wombat. It welds the Lua interpreter onto the Apache web server, which lets the server launch and execute Lua scripts – very much in the style of
mod_perl. Although development was slow over the years, McCallister's module officially made its way into the new Apache 2.4. Somewhere down the line, the developers renamed the module to
mod_lua. Unfortunately, this is the name that many obsolete Apache modules also used.
If you look for documentation on the web, you are likely to stumble across much unusable ballast. Although
mod_lua is part of the Apache package, it is still tagged as experimental; thus, it is not suitable for production use. That said,
mod_lua is stable, and it allows programmers to work with hooks – and that makes it well worth looking into.
If you want to use
mod_lua, you need to create the module when you build the Apache server. To do this, you need version 5.1 of the Lua library, including the matching developer files. On Ubuntu, the packages go by the names of
liblua5.1.0-dev; openSUSE users will need
Once you have Lua in place on your disk, you can turn to the Apache web server source code and run the provided
configure with the additional
--enable-lua parameter. Alternatively, you can append
--enable-mods-shared=, or just go for
If you are inexperienced with the build process but want to try out
mod_lua in a small test environment on your own Linux PC, check out the "Quick Install" box for a brief how-to. The future v1.8.0 of the XAMPP package for this kind of application will include Apache 2.4, but the beta 2 version of
mod_lua, which was the latest when this issue went to press, was strangely only available in the Windows variant .
To enable the Lua module, add the following line to your
httpd.conf file (if you followed the instructions in the "Quick Install" box, you will find the file in
LoadModule lua_module modules/mod_lua
To tell Apache to run any files with a
.lua suffix as Lua scripts, you can add the following line:
AddHandler lua-script .lua
lua-script is a handler provided by
mod_lua, and you can use it like any other Apache handler.
After storing the modified configuration, you need to restart the Apache server; then, you can proceed to write your own Lua scripts.
Any Lua script launched by Apache must have a
mod_lua calls this function and passes in a request object, typically called
function handle(r) ... do something ... end
The request object provides a couple of methods, which you can use to output the page to be served up. To see how this works, check out Listing 1  with the obligatory Hello World example. Comments in Lua always start with two hyphens.
r.content_type first changes the MIME type of the returned document to
r.puts then outputs the
Hello World string. To start the script, store it as
hello.lua in the document root (if you followed the "Quick Install" example, this is
~/httpd/htdocs). Now you can access the function in your browser by typing, for example:
Listing 1: Lua "Hello World"
01 function handle(r) 02 -- Set MIME type to text/plain: 03 r.content_type = "text/plain" 04 05 -- return the "Hello World" text: 06 r:puts("Hello World!") 07 end
If you have a typo, Apache returns an internal server error (number 500). You only get to see a Lua interpreter error message under special circumstances (Figure 1). If you forgot to set the MIME type, Apache will offer to download the Lua script by default.
A script normally wants to evaluate data from a form. Listing 2 shows a simple example. The HTML file here creates a form that prompts the user for their first and last names and then uses a
get to send them to the
Listing 2: question.html with a Form
01 <html> 02 <head><title>Question</title></head> 03 <body> 04 <p>Please enter your first and last names:</p> 05 <form action="answer.lua" method="get"> 06 <input type="text" name="firstname"> 07 <input type="text" name="lastname"><br> 08 <input type="submit" value="Send!" /> 09 </form> 10 </body> 11 </html>
Listing 3 shows the content. The
handler() function first sets the MIME type to
text/html and then issues multiple
r.puts() to create the start of the HTML document. The form then needs to be filled with data. Again, the request object will help here.
Listing 3: Evaluating the Form, answer.lua
01 require 'string' 02 03 function handle(r) 04 r.content_type = "text/html" 05 r:puts("<html>") 06 r:puts("<head><title>Answer</title></head>") 07 r:puts("<body>") 08 09 for k, v in pairs(r:parseargs()) do 10 if k=='firstname' then 11 firstname=v 12 elseif k=='lastname' then 13 lastname=v 14 end 15 end 16 17 r:puts(string.format("Hello %s %s!", firstname, lastname)) 18 19 r:puts("</body></html>") 20 end
r:parseargs() returns all the parameters sent by the Get method as a table. This data structure is known in other programming languages as an associative array or dictionary.
The table returned by
parseargs() has for each field in the form an entry with the name of the field and the value stored in that field. To access the first and last names, the subsequent
for loop iterates through the complete table. The
pairs() function helps it do so by pointing to the next entry in the table. The form field name is stored in the variable
v stores the matching content.
if condition checks to see whether the name is a first name. If so, it is stored in the variable
firstname. Similarly, the
lastname variable stores the last names. Variables in Lua can be used directly to store arbitrary values.
Lua experts will probably object at this point, saying that you could save yourself the trouble of the loop and do the following
allparameters = r:parseargs(); firstname = allparameters["firstname"]
to fish the first names directly out of the table; however, this will provoke an error if the first name wasn't transferred for some obscure reason.
After sending the first and last names off to their respective variables in Listing 3, the
string.format() function concatenates to create a new string. The
%s placeholder replaces
string.format() with the content of the
lastname variables. The results end up in
r:puts() and, thus, in the finished HTML document (Figure 2).
string.format() originates from Lua's standard
string library; the
require command at the start includes this library.
No POST Today
Listing 3 only works if the script receives the form content via Get. If the Post method is used,
r:parsebody() will provide the desired data. You can identify the HTTP method used here with
r.method. This means you can work with cases as shown in Listing 4. Although the official
mod_lua documentation suggests using
parsebody(), doing so in our lab only generated an error message (Figure 3). A quick check of the
mod_lua source code showed that the function isn't actually implemented, or at least not in Apache 2.4.2. All other functions and attributes of the request object are listed in the "Data Structures" section of the official documentation for the module .
Listing 4: Differentiating Post and Get
01 if r.method == 'GET' then 02 for k, v in pairs( r:parseargs() ) do 03 -- Evaluation for GET here ... 04 end 05 elseif r.method == 'POST' then 06 for k, v in pairs( r:parsebody() ) do 07 -- Evaluation for POST here ... 08 end 09 else 10 r:puts("Unknown HTTP method") 11 end
A Lua script needs to include a
handle() function by default. The configuration directive
LuaMapHandler can change this, however. If you add the line
LuaMapHandler /info /var/www/example.lua sayhello
httpd.conf file, for example, Apache should launch the
sayhello function in the Lua script
/var/www/example.lua when calling the
http://localhost/info URL. The emphasis is on "should" here, because this directive is just not implemented (Figure 4) – like
parsebody() – although test scripts for it actually exist in
/modules/lua/test of the Apache source code. Other interesting directives are also missing, such as
LuaCodeCache, which might at some time modify cache behavior for Lua scripts.
Hooks allow you to integrate DIY modules and thus effect changes in various web server processing phases.
mod_lua gives you this ability for Lua scripts, too, which means you could implement a URL redirect as a Lua script. Listing 5 returns the
forbidden.html file when a user attempts to access http://localhost/secret.
Listing 5: URL Redirect via Lua Script
01 require 'string' 02 require 'apache2' 03 04 function translate_name(r) 05 if r.uri == "/secret" then 06 r.uri = "/forbidden.html" 07 return apache2.DECLINED 08 end 09 return apache2.DECLINED 10 end
apache2 library included in Listing 5 provides the constants shown in Table 1, among other things. Depending on the hook, other return values might make sense, such as an HTTP status code.
Tabelle 1: Standard Return Values for Hooks
Request not processed
Request completely processed
For Apache to know which Lua file needs to be called by which function and when, you need to add a line to your
httpd.conf, as follows:
LuaHookTranslateName /usr/local/apache2/scripts/redirect.lua translate_name early
LuaHookTranslateName tells Apache to call the Lua
translate_name function as early as possible when interpreting the request URL.
The function name in the Lua script could thus have a different name, but it makes sense to name it after the Apache hook, as in Listing 5.
/usr/local/apache2/scripts/redirect.lua also supplies the full path to the script file. The optional
early ensures that Apache runs the function as early as possible in the process flow. An alternative to this is
late, which tells Apache to run the function as late as possible.
The official module documentation lists the other existing hook directives , but again, some of these aren't implemented. For more sample scripts, in particular on the subject of hooks, check out the Apache source code directory below
Mod-lua is enticing: The Lua scripts launched by the module can put an HTML document together faster than their PHP or Perl counterparts, and you can even hook Lua scripts into the Apache server's process chain. However, closer inspection of the module reveals many construction sites.
The documentation explicitly points out that the module's configuration and approach could change at some time in the future. Seen in this light, you can understand that the official documentation is just a single, fairly terse, page , and this makes it all the more surprising that
mod_lua has made the cut for the official Apache package. On the other hand, this will improve the module's chances of being discovered by more developers – and this is something it definitely deserves.