Charlton's Blog

Build a Simple IP Echo Service With Lighttpd and Mod_magnet

A delightful 5 minute project

Published: Jul 5, 2017
Category: Programming, Projects
Tags: ,

Assuming you’ve done most any work in the tech space, you’ve undoubtedly come across the myriad of free services that will tell you your external IP address. These are especially useful for a number of reasons, with some examples including checking whether a VPN connection is working correctly, configuring DNS records, and determining whether traffic on your network is NATed.

Now, there are many providers of this service (with whatismyip.com and Google’s own service being among the most popular), but they’re often plastered with ads and tracking, somewhat slow, and worst of all- difficult for scripts to parse! Wouldn’t it be better to have a simple solution available that you can host yourself?

As it happens, this problem is very easy to solve using the mod_magnet component of Lighttpd web server. So, as part of this post, I’ll assume you’re at least passively familiar with Lighttpd, the fact that Lighttpd can load modules, and very basic HTTP transactions. If not, it’s OK! I’ve done my best to break it all down for you.

What is mod_magnet?

Mod_magnet is a module available for Lighttpd which exposes a powerful interface for extending Lighttpd’s request handling using the Lua language, providing the user a much higher degree of customizability than that found in Lighttpd’s built-in routing facilities. Essentially, mod_magnet is a means of running your own custom Lua scripts on HTTP requests, in place of Lighttpd.

Setting it up

Whether or not all of this above sounds like a steaming pile of jargon matters very little, because the technical nitty-gritty of mod_magnet is far beyond the scope of this post. I’m also not a fan of just telling people where to paste things, so we’ll instead focus on breaking down the very simple 3-line Lua script I’ve put together for this purpose, along with the tiny snippet of Lighttpd configuration that makes it all run:

Here’s what happens in that 3 line script:

lighty.content = { lighty.env["request.remote-ip"] }
lighty.header["Content-Type"] = "text/html"
return 200
  1. We fill the server’s response content with the client’s IP address, which we read from the script’s environment variables.
  2. We make sure that the MIME type of the response is set to text/html, because we’re just nice people.
  3. We return a `200 OK` status code with the response .

And, in that 6-line Lighttpd configuration:

server.modules += ( "mod_magnet" )
$HTTP["host"] =~ "ip.ctis.me" {
  magnet.attract-physical-path-to = ("/var/www/ipecho/ip.lua")
  server.document-root = "/var/www/ipecho/"
  accesslog.filename = "/dev/null"
}
  1. We load the mod_magnet module (if it isn’t already loaded, otherwise you should comment this out).
  2. We create a virtual host (my hostname is ip.ctis.me, though you can use any domain you control, or even a custom path [e.g. yoursite.com/ip]).
  3. We give the mod_magnet module the path to the Lua script it should run when this particular host recieves a request.
  4. We set the document root of this vhost to wherever you’ve put the Lua script (update 3 and 4 accordingly, of course).
  5. Set the access log to /dev/null because I don’t care to keep logs about this particular endpoint.

So, to set it all up, all you really have to do is put the .lua file in your web root somewhere, and then updating your Lighttpd configuration accordingly using my template as a guide. Simple, isn’t it?

As per usual, a live example of this in action can be found here.

Enjoy!