Serving mbtiles tiles for slippy maps

I’m playing with TileMill (see my blog post here). TileMill publishes to an mbtiles file, a sqlite3 database that contains the rendered image tiles. One simple file, so nice! Now, how to serve it? The simplest solution is TileStream hosting, but I’m too cheap and hackish to pay the very reasonable $50 / month.

So I set up a tile server on TileStache instead, a Python system. You can see the setup on GitHub. It took about four hours to get working, even though none of it is too complex. Here’s my notes.

  1. Install TileStache via Python easy_install and configure. It’s pretty simple, the only subtle thing is that TileStache wants a cache. This may not be necessary with pre-rendered mbtiles bundles but it was easy enough to set up memcached and configure it.
  2. Set up TileStache to render via CGI, with a CGI script and a bit of Apache config. CGI is a bad way to serve things, but I’d hoped it was sufficient and it was easy to get going. Turns out to be unacceptably slow.
  3. I tried a couple of failed approaches for WSGI. First I tried TileStache’s built in WerkZeug server. This works and is faster than CGI, but lacks administrative scripts to wrap it. Then I tried Apache WSGI and ran into an error with no useful debug output. Gave up on that.
  4. Set up gunicorn, the excellent Python asynchronous server for WSGI. It’s easy to set up on Debian if you get version 0.13 from Backports, it comes with nice administration scripts. Just needs a little config file. I also installed python-gevent for an async worker.
Doing all this, my crappy old single CPU server with 1 gig of RAM can handle serving a map to a single user at acceptable speed. It can probably do more than that, I haven’t load tested it.
I left some things not done, this was intended as a quick hack:
  • gunicorn really wants a proxy HTTP server like nginx in front of it. Good idea, but I didn’t want to bother. The bummer is gunicorn doesn’t set any caching headers at all; really need those for a real deployment.
  • The cool kids building TileMill are doing everything with Node.js these days. Their TileStream server would be another option, but getting Node running on Debian was too much work for a quick hack.
It’s a little surprising that MBTiles is so complex to serve. It’s basically just a big archive of JPG images, it’d be nice to have a little C program to serve it blindingly fast. “mbserv foo.mbtiles –port 8989”. TileStache is a big program that does a lot of stuff, but even TileStream is 900+ lines of code and all it does is serve MBTiles.