Running Lua on Heroku

Since the release of Heroku’s Cedar platform they've opened up the opportunity for users to run web applications on any stack. Using something called a buildpack we can describe a template for deploying any kind of application.

I saw this as a great opportunity to try using Lua on a cloud hosting platform (for free).

I put together heroku-buildpack-lua, a buildpack containing Lua 5.1 and LuaRocks (a Lua package manager) enable you to quickly deploy Lua along with any required dependencies that can be found on the LuaRocks server.

Here’s a tutorial on getting a very simple app running:

Feb 12 2012 — I've updated the buildpack and this post to simplify the process.

Creating An App

Assuming you've installed heroku we start by creating a new app:

$ heroku create --stack cedar --buildpack http://github.com/leafo/heroku-buildpack-lua.git

Clone the repository it created and we're ready to begin. (stark-dust-4830 was the randomly generated name of my app, replace it with yours.)

$ git clone git@heroku.com:stark-dusk-4830.git
$ cd stark-dust-4830

Describing Dependencies

Heroku manages a collection of app servers for us, called web dynos in their terminology. Each application server must expose itself to the outside world. This is done by running a web server on the dyno.

The Xavante project is simple web server written in Lua with a couple dependencies.

Using LuaRocks bundled in the Lua buildpack, we can easily install Xavante and all its dependencies. We describe the dependencies of our Lua project by creating a rockspec for it.

A rockspec is a special Lua file ending in .rockspec that describes meta-data about a Lua module. This meta-data includes things like the project name, the maintainer. It also holds any dependencies and how to build the module.

The Lua buildpack understands the rockspec format, but only looks at the dependencies. Thus, for simplicity we'll only define the dependencies.

Go ahead and create app.rockspec and place inside of it:

-- app.rockspec
dependencies = {
  "xavante"
}

Xavante will be our only dependency. We're going to keep this tutorial short and leave out the web frameworks. Xavante’s API is flexible enough that it functions as a makeshift framework.

If you commit and push, you'll see the buildpack fetch and build all the dependencies. There will be a lot of output, don’t be be concerned.

$ git add app.rockspec
$ git commit -m "init"
$ git push origin master
...

-----> Heroku receiving push
-----> Fetching custom buildpack... done
-----> Lua app detected
-----> Copying lua to bin
-----> Installing packages
Installing http://www.luarocks.org/repositories/rocks/xavante-2.2.1-1.all.rock...

... output truncated ...

-----> Discovering process types
       Procfile declares types -> (none)
-----> Compiled slug size is 292K
-----> Launching... done, v5
       http://stark-dusk-4830.herokuapp.com deployed to Heroku

Our dependencies work, but we still haven’t set up a web server. This we'll do by writing some Lua.

Creating A Web Server

We'll use Xavante’s programmatic API to create and run our server through a simple Lua script.

Create a file, web.lua, and place in it:

-- web.lua
require "xavante"
require "xavante.filehandler"

port = ...

xavante.HTTP {
  server = { host = "*", port = tonumber(port) },
  defaultHost = {
    rules = {
      {
        match = "/$",
        with = function(req, res)
          res.headers["Content-type"] = "text/html"
          res.content = "hello world, the time is: " .. os.date()
          return res
        end
      }, {
        match = ".",
        with = xavante.filehandler,
        params = { baseDir = "static/" }
      }
    }
  }
}

xavante.start()

In this file we create a web server with two simple rules. If you go to the path / then we say hello and show the time. Otherwise, we default to trying to serve files from the static/ directory in our app.

Go ahead and create the static/ directory now, and put something inside of it like a favicon or a html file.

If you have Xavante installed locally, we can test the app. (where 5000 is a port to bind to)

$ lua web.lua 5000
Xavante started on port(s) 5000

If not, go on to the next step.

Deploying The Web Server

Now that all the required code is written, the only thing left to do is to tell Heroku how to start it.

Heroku uses something called a Procfile to list the commands needed to start things like web severs and workers. We only need a single web server.

Create a file called Procfile and place inside of it:

web:     lua web.lua $PORT

Now we're ready to deploy. Commit and push once again.

$ git commit -a -m "..."
$ git push origin master

We can check and see if our app is running by typing into the console:

$ heroku ps

You'll probably see nothing running! It’s because we deployed before without a Procfile. Tell Heroku to start up our web server:

$ heroku scale web=1
Scaling web processes... done, now running 1

$ heroku ps
Process  State       Command                
-------  ----------  ---------------------  
web.1    up for 16s  bin/lua web.lua $PORT

If you still see nothing running you'll have to debug. Run heroku logs to see if anything failed.

Now our web server is running, navigate to the url of the app to see it live.

Don’t forget to try out some of the static files you included.

What’s Next?

What we've created here is fairly primitive. There are a lot of opportunities for expanding:

It’s also worth reading the the Lua buildpack’s README because it explains how and where Lua and it’s packages are installed.