PermaLink Porting Lua/CGILua/Orbit/Haserl to an Embedded System01/06/2010 02:22 PM
Well..this was lot more painful than it needed to be, so I thought I'd document it for posterity (aka Google to find  
I had to port a web app development environment to an EmbeddedArm TS-7260 running Linux 2.4 because the current environment consisted of a bunch of cgi shell scripts that "printed" HTML code back as web pages.

Getting a Debian environment on this relatively old (3 yr old) board was fairly painful because they let you download the development image to put on a flash drive but don't tell you how to do it. Even though the documentation implies you can unpack the tar file onto a VFAT drive from Windows, you have to do it from a running Linux system (you can use a Live CD) by plugging the flash drive in, then doing "fdisk /dev/sdb" (assuming the flash drive shows up as sdb; you create one partition on it and mark it bootable), then you have to "mkfs.ext2 /dev/sdb1" before you can untar their development image on it. To make it more complicated, the image I had to use (to match the kernel on boards in the field) was missing the rcS.USB startup file (it was on the previous Woody tar image on their site and I used the Sarge image) so that failed to load. Always remember to do a "sync" before switching between the board and the Debian flash drive.

Once you get the Debian environment running, it's not as simple as running "apt-get install" to build the binaries you need because when you do this, it will want to install the latest version of gcc which requires the latest 2.6 kernel; you cannot use luarocks for the same reason...dependency updates inevitably suck down newer updates for gcc and the kernel. You end up having to do grab all the dependencies yourself and compiling them and installing them to the right place by looking at the makefile's install target.

The haserl web framework (used on various wifi routers and the ddwrt open source firmware replacement) required lua to be installed (haserl can only be compiled to use /bin/sh as the scripting language, but lua offers a lot more programming capability). In order to get lua compiled, you have to compile and install the Gnu readline and ncurses libraries (ncurses might fail compiling the c++ directory but you can do "make install.libs" to install what's been compiled to make lua happy). As part of the install of haserl, you have to make the executable file setuid or it will have problems handling file uploads and any other file operations. If you want to avoid any shared library dependencies, you can also configure it with "LDFLAGS=--static" to force it to build a statically linked executable (you can run ldd on the executable to make sure it doesn't use any shared libraries); this will make the file size grow to 324K (the shared library linked version is only 33K).

The cgilua web framework requires fastcgi and wsapi before it can be compiled. After you compile it, you still can't run cgilua scripts until you download Kepler's tarball and grab the cgilua.cgi and cgilua.fcgi files (if you want to install Orbit, grab the op.cgi and op.fcgi files as well); these files are needed to parse the web page headers before loading the lua server page files (they're lua server page launchers that you stick in your app's cgi-bin directory).
Unfortunately, these files are tied into Kepler's Xavante server, so you have to modify a few things to get them to work. The cgilua.cgi scripts get global variables from kepler_init.lua (you can get this out of any kepler installation and modify the paths appropriately; I put cgilua's config.lua in my apache/conf/cgilua directory); I renamed this file to cgilua_init.lua and put it in the usual /usr/local/share/lua/5.1 directory. The global variables that are important are CGILUA_CONF and CGILUA_TMP and RINGS_CGILUA_GLOBALS and CGI_LUA_ISDIRECT (CGILUA_APPS doesn't seem to be used). You then have to modify your cgilua.cgi file to initialize from this file instead of kepler_init.lua and also comment out the check for luarocks since luarocks can't be used in embedded systems. Once you get all that done, put the *.cgi scripts in apache's cgi-bin directory and make them executable and setuid so they have access to the file system. You can then do this to bring up a test page:
Note also that your lua page file *must* have an extension because the cgi files parse for it. If your embedded system has Apache's mod_rewrite module compiled/installed, you can also follow the directions on the Kepler site on how to set up a .htaccess file so the URLs look nicer. If you want to use FastCGI support, your Apache system also needs to have the mod_fcgid module installed.

Orbit is another webwork for lua which supports the MVC pattern (though it doesn't seem to have functions to support file uploads at this point so you have to use cgilua's support). Orbit pages are similar to PHP pages, so it needs the LPeg library (and the re.lua included in it) to parse the embedded function syntax in the web pages. When you finish setting it up, you can do something like this to bring up an Orbit page:

Finally, here's the list of files I added to the embedded system:
/usr/local/share/lua/5.1/wsapi (dir)
/usr/local/lib/lua/5.1/ (fastcgi)
/usr/local/lib/lua/5.1/ (luafilesystem)
/usr/local/share/lua/5.1/cgilua_init.lua (bastardized from kepler_init.lua)
/usr/local/share/lua/5.1/cgilua (dir)
/usr/local/share/lua/5.1/orbit (dir)
/usr/local/share/lua/5.1/cosmo (dir)
/usr/local/lib/lua/5.1/ (lpeg grammar parsing)
/usr/local/share/lua/5.1/re.lua (used w/ lpeg)

p.s., I found the cgilua web site's examples to be fairly sparse for file upload.
Hide details for The test page at was useful:The test page at was useful:
#!/usr/bin/env cgilua.cgi

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
<html xmlns="" xml:lang="en" lang="en">
   <title>CGILua Test</title>
   <link rel="stylesheet" href="css/doc.css" type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
   if cgilua.POST.user then
       cgilua.cookies.sethtml("cookie_kepler", cgilua.POST.user)


<div id="container">

<div id="product">
<div id="product_logo"><a href="">
<img src="img/keplerproject.gif" alt="Kepler Project logo" /></a>
<div id="product_name"><big><strong></strong></big></div>
<div id="product_description">CGILua simple tests</div>
</div> <!-- id="product" -->

<div id="main">

<div id="navigation">
local mods = {}
for file in lfs.dir("doc") do
   local attr = lfs.attributes ("doc/"..file)
   if attr.mode == "directory" and file ~= "." and file ~= ".." then
       table.insert(mods, file)

       <li><a href="index.lp">Documentation</a>
               for _,file in ipairs(mods) do
               <li><strong><a href="doc/<%= file %>/index.html"><%= file %></a></strong></li>
               if not next(mods) then
</div> <!-- id="navigation" -->

<div id="content">

<h2>Form Handling</h2>

Entering values on this form should display them as values in the first submission,
and as a cookie in the next submission

<form method="post" action="test.lp">
   <label>User name: </label><input name="user" maxlength="20" size="20">
   <label>Password: </label><input name="pass" type="password" maxlength="20" size="20">
   <input type="submit" value="Post it">
   <input type="reset" value="Reset">

The values should show the previous POST

Values: Username = <%= cgilua.POST.user or "(not set)"%>, Password = <%= cgilua.POST.pass or "(not set)"%>

<h2>Cookies test</h2>

Here you should see the values posted before the ones shown above

cookie_kepler = <%= cgilua.cookies.get("cookie_kepler") or "(not set)" %>

<h2>File Upload</h2>

<p>Choose a file to upload, press "Upload" and a link to the file should
appear below with the corresponding "Remove" button.</a>
<form method="POST" enctype="multipart/form-data" action="test.lp">
   <input type="file" name="file">
   <input type="submit" value="Upload">

   local f = cgilua.POST.file
   if f and next(f) then
       local _, name = cgilua.splitonlast(f.filename)
       local file = f.file
       local dest =, "wb")
       if dest then
           local bytes =
           cgilua.print("<a href='""'>""</a>\n")


   if cgilua.POST.remove then

local function showtable(t)
   cgilua.put "{"
   for i,v in pairs (t) do
       if type(v) == "table" then
           local vv = "{\n"
           for a,b in pairs(v) do
               vv = string.format ("%s  %s = [[%s]],\n", vv, a, tostring(b))
           v = vv.." },"
           cgilua.put (string.format (" %s = %s", i, tostring(v)))
           cgilua.put (string.format (" %s = [[%s]],", i, tostring(v)))
   if next(t) then
       cgilua.put "\n"
   cgilua.put "}\n"


<pre class="example">
<% showtable (cgilua.QUERY) %>

<pre class="example">
<% showtable (cgilua.POST) %>

<h2>CGILua Variables</h2>

<table border="1">
local vars = {
   "script_file", "script_path", "script_pdir", "script_vdir", "script_vpath", "urlpath",
for _, v in ipairs(vars) do %>
 <tr><td>cgilua.<%= v %></td><td><%= tostring(cgilua[v]) %></td></tr>
<% end %>

<h2>Server Variables</h2>

<table border="1">
local vars = {
for _, v in ipairs(vars) do %>
 <tr><td><%= v %></td><td><%= tostring(cgilua.servervariable(v)) %></td></tr>
<% end %>

<h2>Multiple Output</h2>

<p>The next tests should show numbers, from 1 to 3, and the string "OK" together, without spaces.</p>

<pre class="example">
cgilua.put(1, 2, 3, "OK")   --> <% cgilua.put(1, 2, 3, "OK") %>
cgilua.print(1, 2, 3, "OK") --> <% cgilua.print(1, 2, 3, "OK") %>


<p>Today is: <%= %></p>

<h2>Image test</h2>

<p>Here should be a small image: <img src="img/test.jpg" alt="a small photograph" /></p>

<h2>FileSystem test</h2>

 local d = lfs.currentdir () or ""
 cgilua.put("Iterating over "..d.."<br />")
 for file in lfs.dir(d) do cgilua.put("&nbsp;&nbsp;&nbsp;"..file.."<br />") end

<h2>Containment test</h2>

<% if (x == nil) then x = 1 else x = x + 1 end %>
Expected value: 1, actual value: <%= x %>.

</div> <!-- id="content" -->

</div> <!-- id="main" -->

<div id="about">
<p><a href="">Valid XHTML 1.0</a></p>
<p><small>$Id: test.lp,v 1.2 2007/12/17 22:03:18 carregal Exp $</small></p>
</div> <!-- id="about" -->

</div> <!-- id="container" -->

The examples at were also good.
And there's also the Lua Tutorial Wiki.
Comments :v

1. Felipe06/14/2015 07:24:03 PM

Five years after your post, the content from the page is the only true example I found. Thank you for posting it!

2. Ken Yee03/09/2010 08:25:30 AM

This is from a basic install via luarocks on Windows:

-- Kepler bootstrap file
-- Defines the default directories for Kepler

-- Kepler applications directory
KEPLER_APPS = [[c:\LuaRocks\kepler/apps]]

-- Kepler configuration directory
KEPLER_CONF = [[c:\LuaRocks\kepler/etc]]

-- Kepler logs directory
KEPLER_LOG = [[c:\LuaRocks\kepler/log]]

-- Kepler temporary directory

-- Kepler default web directory
KEPLER_WEB = [[c:\LuaRocks\kepler/htdocs]]

-- CGILua globals (usually defined using KEPLER globals)


3. rory toma02/26/2010 08:40:31 PM

Can you post the contents of your kepler_init file? It seems that this file is empty in the distribution. Thx

Start Pages
RSS News Feed RSS Comments Feed CoComment Integrated
The BlogRoll
October 2017
Contact Me
About Ken
Full-stack developer (consultant) working with .Net, Java, Android, Javascript (jQuery, Meteor.js, AngularJS), Lotus Domino