Over the Christmas break I found myself with a bit of free time to play with Nancy. For a long time I’ve fancied writing a link shortener, I even bought the domain vfy.be to serve shortened links from. I originally had grand plans, it was going to be a social link shortener where links “trusted”/visited by your friends took you straight to them, otherwise you hit a landing page with the amount of hits, the real url and what Google thinks about it or I was going to iframe the page in with a toolbar. Anyway, twitter got in the link shortening business and I got another idea and decided to move on. But still how they worked intrigued me.
So I wrote one for fun using C#, mono 2.10 and Nancy. When looking at the Nancy docs, it is slightly lacking in how to host on Linux so I thought I’d do my bit by writing a quick overview.
There is a couple of options when hosting on Linux, one is to create your Nancy project as a mono ASP.NET project then serve it using xsp (the mono ASP.NET server) and proxying to it or using FastCGI. This is fairly well documented at the mono site and writing a Nancy app using ASP.NET for hosting is also well documented. However, I wanted to take a different approach to try and host it in the minimum amount of RAM on an LEB (LowEndBox), because I have a 256MB Xen Debian VPS just sat around doing nothing.
So to minimise RAM I went for self hosting, using pretty much the stock sample with a slight mod (see below). When self hosting the Nancy app will listen on the loopback address at a specified port so we are going to use Nginx to serve static content and forward all requests to our mono process and use Supervisord to monitor the process.
Pull it all together
For this you’ll need the following installed on the Linux machine:
- Mono 2.10
The first we’re going to do is configure Supervisord. Supervisord is a process monitoring application that can run any normal process as a daemon and automatically restart it if it crashes. I first came across this when working with Python sites to keep FastCGI processes running. The configuration should look something like:
The important bits are:
- command – this specifies the command believe it or not,
- user – by default supervisord runs all processes as root, this is bad for webapps.
- directory – this sets the working directory, so if you’re app needs anything off disc this needs to be correct.
As I said above I needed to make a tweak to the sample self hosting project. The sample uses Console.ReadLine() to stop the process from exiting, but under Mono when running as a daemon this returns EOF and causes the application to close. So I updated it to sleep (shamelessly stolen from xsp source ):
Moving on we need to configure Nginx. The strength of Nginx is serving up static content quickly so we’re going to intercept all requests for static files and then forward the rest to our Nancy app. The configuration below defines an ‘upstream’ which is typically used for load balancing we can use it here for just forwarding requests. Also note we are intercepting and serving requests for /Content using Nginx. At debug time the default conventions in Nancy will serve this up correctly so we get best of both worlds
How well does it do on our LEB?
Impressively, idle the combination of Debian Sid, Supervisord, Nginx and the Mono process takes up just 37MB of RAM, but the most important question is can it handle load? Beware completely unscientific results below
Lets take a look at hitting one of the json API methods* using ApacheBench (that is bundled with OSX ):
- 1000 continuos requests with a max of 10 concurrent connections peaks memory at 53MB
- 1000 continuos requests with a max of 25 concurrent connections peaks memory at 54MB but 18 out of the 1000 failed with connection reset by peer, which is more the box failing than the app
- 1000 continuos requests with a max of 50 concurrent connections peaks memory at 55MB but my own boardband gave up after 700 connection, clearly not enough upspeed
It’s important to note that this app is one static html page with ajax queries back to a JSON api served by Nancy
I hope someone finds my configuration snippets useful and it is worth noting that my LEB (£2.20 a month for 256MB Xen) failed before the my app did, so I find this very encouraging for it’s performance under Mono and Linux.
Source for the link shortener and conf files can be found at https://github.com/Dotnetwill/vfy.be The shortener running on Mono http://vfy.be