Configuring Lighttpd to use the FastCGI Mono Server

Table of Contents

Introduction

Lighttpd (pronounced "lighty") is a popular lightweight and easy to configure HTTP server. Adding ASP.NET support through fastcgi-mono-server is very quick and painless and can be done by modifying only three files.

Configuration Tested On...

General Warnings

Before doing anthing else, you should read "Important Information" on the main page.

Using Paths [Recommended]

Step 1: Enabling the FastCGI Module

The server is enabled through the FastCGI module. To enable the module, open /etc/lighttpd/modules.conf and search for the following block:

##
## FastCGI (mod_fastcgi)
##
#include "conf.d/fastcgi.conf"

If you find it, you need only uncomment the include line. If you don't find that line, or anything like it, simply the following line to end of the file:

include "conf.d/fastcgi.conf"

Step 2: Configuring the FastCGI Module

Now that the server is enabled, it takes just a handful of lines to configure it.

Your distribution should have included a file /etc/lighttpd/conf.d/fastcgi.conf in the installation, if not, add it. This is the largest and most important part of the configuration. It consists of three pieces, which will be discussed in detail, and by the time you are finished the file will look something like this:

server.modules += ( "mod_fastcgi" )

fastcgi.server = (
        "" => ((
                "socket" => "/tmp/fastcgi-mono-server",
                "bin-path" => "/usr/bin/fastcgi-mono-server",
                "max-procs" => 1,
                "check-local" => "disable"
        ))
)

So without further adu...

Part A: Adding the Module

This file must have the following line in it, otherwise it will not work:

server.modules += ( "mod_fastcgi" )

If the file was included in your distribution, it would be near the very top. If not, make sure you add it. This tells Lighttpd to load the module when it starts up.

Part B: Adding the Server

The next step is to add a server for the ".aspx" extension. Do a quick search for "fastcgi.server". If found, it will probably look something like the following:

fastcgi.server = (
	".php" => ((
		"socket" => "/tmp/php-fastcgi.socket",
		"bin-path" => "/usr/local/bin/php",
		"bin-environment" => (
			"PHP_FCGI_CHILDREN" => "16",
			"PHP_FCGI_MAX_REQUESTS" => "10000"
		)
	))
)

If you have it, you're going to want to add a new extension to it so it looks like the following:

fastcgi.server = (
	".php" => ((
		"socket" => "/tmp/php-fastcgi.socket",
		"bin-path" => "/usr/local/bin/php",
		"bin-environment" => (
			"PHP_FCGI_CHILDREN" => "16",
			"PHP_FCGI_MAX_REQUESTS" => "10000"
		)
	)),
	"" => ((
		# TO BE ADDED
		"check-local" => "disable"
	))
)

Otherwise, if it doesn't exist, just add the following block:

fastcgi.server = (
	"" => ((
		# TO BE ADDED
		"check-local" => "disable"
	))
)

This is the beginning of a server definition for the root directory. "" looks a little odd, but adding a trailing slash to the directory name dramatically alters how Lighttpd sends the request paths. You will be adding implementation specific settings where "# TO BE ADDED". The "check-local" line tells Lighttpd to send all requests to the Mono server regardless of whether or not the the file exists on disk. This is needed for some features of ASP.NET 2.0.

There are two recommended server implementations for the Mono server. The first has Lighttpd automatically spawn the child server when it starts and communicate over Unix sockets. This has the advantage of being easy to set up, being secure by limiting access to just Lighttpd, and having the performance boost provided by Unix sockets. The second has Lighttpd communicate via TCP sockets with an existing Mono server somewhere on the network. This has the advantage of being able to run the Mono server on an entirely different machine than Lighttpd and all the performance and logistical advantages associated with that.

If you're just setting up a personal server or not trying anything fancy, I would recommend using automatic spawning, and if you're using a high bandwidth, multimachine setup, I would recommend using TCP and running the server on another system.

Automatically spawning a new server

Where you previously added "# TO BE ADDED", replace it with the following:

		"socket" => "/tmp/fastcgi-mono-server",
		"bin-path" => "/usr/bin/fastcgi-mono-server",
		"max-procs" => 1,
Connecting to an existing server via TCP

Where you previously added "# TO BE ADDED", replace it with the following:

		"host" => "192.168.0.3",
		"port" => 9000,
		"docroot" => "/root/on/remote/machine",

Advanced Topics

Sending all requests to ASP.NET adds some extra overhead which may not be desirable for sending large static files. It additionally prevents PHP (and other scripts) from working. The following advanced topics overcome these obstacles by enclosing the fastcgi.server definition in a Conditional Configuration.

As this prevents requests from being handled by ASP.NET, the requests do not employ ASP.NET's security features and extra security measures should be applied.

Excluding Paths from ASP.NET

The following example prevents files in the /downloads/ and /images/ directories from being sent to ASP.NET:

server.modules += ( "mod_fastcgi" )

$HTTP["url"] !~ "^/(downloads|images)/" {
	fastcgi.server = (
		"" => ((
			"socket" => "/tmp/fastcgi-mono-server",
			"bin-path" => "/usr/bin/fastcgi-mono-server",
			"max-procs" => 1,
			"check-local" => "disable"
		))
	)
}

Limiting ASP.NET to Specific Virtual Hosts

The following example limits ASP.NET to running on www.example.com and example.com:

server.modules += ( "mod_fastcgi" )

$HTTP["host"] =~ "^(www\.|)example\.com$" {
	fastcgi.server = (
		"" => ((
			"socket" => "/tmp/fastcgi-mono-server",
			"bin-path" => "/usr/bin/fastcgi-mono-server",
			"max-procs" => 1,
			"check-local" => "disable"
		))
	)
}

Allowing PHP to Run in Parallel

The following example sends .php requests to a PHP FastCGI server and the rest to ASP.NET:

server.modules += ( "mod_fastcgi" )

$HTTP["url"] !~ "\.php$" {
	fastcgi.server = (
	        ""   => ((
	                "socket" => "/tmp/fastcgi-mono-server",
	                "bin-path" => "/usr/bin/fastcgi-mono-server2",
	                "max-procs" => 1,
	                "check-local" => "disable"
	        ))
	)
}

fastcgi.server = (
        ".php"   => ((
                "socket" => "/tmp/php-fastcgi",
                "bin-path" => "/srv/www/cgi-bin/php5",
                "bin-environment" => (
                        "PHP_FCGI_CHILDREN" => "16",
                        "PHP_FCGI_MAX_REQUESTS" => "10000"
                )
        ))
)

Using Extensions

Warnings

Using Extensions in place place of paths is NOT recommended. Please consult "Paths vs. Extensions" on the main page for an in depth explanation. If you decide to use this configuration, please bear in mind that it is less secure suffers additional disadvantages when compared to using paths.

Step 1: Enabling the FastCGI Module

The server is enabled through the FastCGI module. To enable the module, open /etc/lighttpd/modules.conf and search for the following block:

##
## FastCGI (mod_fastcgi)
##
#include "conf.d/fastcgi.conf"

If you find it, you need only uncomment the include line. If you don't find that line, or anything like it, simply the following line to end of the file:

include "conf.d/fastcgi.conf"

Step 2: Configuring the FastCGI Module

Now that the server is enabled, it takes just a handful of lines to configure it.

Your distribution should have included a file /etc/lighttpd/conf.d/fastcgi.conf in the installation, if not, add it. This is the largest and most important part of the configuration. It consists of three pieces, which will be discussed in detail, and by the time you are finished the file will look something like this:

server.modules += ( "mod_fastcgi" )

fastcgi.server = (
        ".aspx" => ((
                "socket" => "/tmp/fastcgi-mono-server",
                "bin-path" => "/usr/bin/fastcgi-mono-server",
                "max-procs" => 1,
                "check-local" => "disable"
        ))
)

fastcgi.map-extensions = (
        ".asmx"   => ".aspx",
        ".ashx"   => ".aspx",
        ".asax"   => ".aspx",
        ".ascx"   => ".aspx",
        ".soap"   => ".aspx",
        ".rem"    => ".aspx",
        ".axd"    => ".aspx",
        ".cs"     => ".aspx",
        ".config" => ".aspx",
        ".dll"    => ".aspx"
)

So without further adu...

Part A: Adding the Module

This file must have the following line in it, otherwise it will not work:

server.modules += ( "mod_fastcgi" )

If the file was included in your distribution, it would be near the very top. If not, make sure you add it. This tells Lighttpd to load the module when it starts up.

Part B: Adding the Server

The next step is to add a server for the ".aspx" extension. Do a quick search for "fastcgi.server". If found, it will probably look something like the following:

fastcgi.server = (
	".php" => ((
		"socket" => "/tmp/php-fastcgi.socket",
		"bin-path" => "/usr/local/bin/php",
		"bin-environment" => (
			"PHP_FCGI_CHILDREN" => "16",
			"PHP_FCGI_MAX_REQUESTS" => "10000"
		)
	))
)

If you have it, you're going to want to add a new extension to it so it looks like the following:

fastcgi.server = (
	".php" => ((
		"socket" => "/tmp/php-fastcgi.socket",
		"bin-path" => "/usr/local/bin/php",
		"bin-environment" => (
			"PHP_FCGI_CHILDREN" => "16",
			"PHP_FCGI_MAX_REQUESTS" => "10000"
		)
	)),
	".aspx" => ((
		# TO BE ADDED
		"check-local" => "disable"
	))
)

Otherwise, if it doesn't exist, just add the following block:

fastcgi.server = (
	".aspx" => ((
		# TO BE ADDED
		"check-local" => "disable"
	))
)

This is the beginning of a server definition for the ".aspx" extension. You will be adding implementation specific settings where "# TO BE ADDED". The "check-local" line tells Lighttpd to send all requests to the Mono server regardless of whether or not the the file exists on disk. This is needed for some features of ASP.NET 2.0.

There are two recommended server implementations for the Mono server. The first has Lighttpd automatically spawn the child server when it starts and communicate over Unix sockets. This has the advantage of being easy to set up, being secure by limiting access to just Lighttpd, and having the performance boost provided by Unix sockets. The second has Lighttpd communicate via TCP sockets with an existing Mono server somewhere on the network. This has the advantage of being able to run the Mono server on an entirely different machine than Lighttpd and all the performance and logistical advantages associated with that.

If you're just setting up a personal server or not trying anything fancy, I would recommend using automatic spawning, and if you're using a high bandwidth, multimachine setup, I would recommend using TCP and running the server on another system.

Automatically spawning a new server

Where you previously added "# TO BE ADDED", replace it with the following:

		"socket" => "/tmp/fastcgi-mono-server",
		"bin-path" => "/usr/bin/fastcgi-mono-server",
		"max-procs" => 1,
Connecting to an existing server via TCP

Where you previously added "# TO BE ADDED", replace it with the following:

		"host" => "192.168.0.3",
		"port" => 9000,
		"docroot" => "/root/on/remote/machine",

Part C: Mapping Extensions

ASP.NET uses many extensions for its many different features. It uses ".ashx" for handlers, ".soap" for SOAP, and you really don't want anyone downloading your ".dll" files, do you?

The hard way to add a new extension is to copy and paste what your server configuration, replacing ".aspx" with ".asmx", etc. The easy way is to add a extension map, so Lighttpd just treats ".asmx" as ".aspx".

As before, you are going to want to look for "fastcgi.map-extensions". If found, it will probably look something like the following:

fastcgi.map-extensions = ( ".php3" => ".php" )

If you have it, you're going to want to add a new extension to it so it looks like the following:

fastcgi.map-extensions = (
        ".php3" => ".php",
        ".asmx"   => ".aspx",
        ".ashx"   => ".aspx",
        ".asax"   => ".aspx",
        ".ascx"   => ".aspx",
        ".soap"   => ".aspx",
        ".rem"    => ".aspx",
        ".axd"    => ".aspx",
        ".cs"     => ".aspx",
        ".config" => ".aspx",
        ".dll"    => ".aspx"
)

Otherwise, if it doesn't exist, just add the following block:

fastcgi.map-extensions = (
        ".asmx"   => ".aspx",
        ".ashx"   => ".aspx",
        ".asax"   => ".aspx",
        ".ascx"   => ".aspx",
        ".soap"   => ".aspx",
        ".rem"    => ".aspx",
        ".axd"    => ".aspx",
        ".cs"     => ".aspx",
        ".config" => ".aspx",
        ".dll"    => ".aspx"
)

Step 3: Adding Index Pages

Once you have finished Step 2, you should have a working ASP.NET server with one exception, if you look at a folder like "/", you'll get a 404 error instead of "default.aspx". To fix this, you need to open /etc/lighttpd/lighttpd.conf and search for index-file.names. You'll probably see the following block:

index-file.names = (
  "index.xhtml", "index.html", "index.htm", "default.htm", "index.php"
)

You will need to modify it so it includes "index.aspx" and "default.aspx". For example,

index-file.names = (
  "index.xhtml", "index.html", "index.htm", "default.htm", "index.php", "default.aspx", "index.aspx"
)

Bada Bing!

You should now have ASP.NET working with Lighttpd. Enjoy!

- Brian Nickel <http://kerrick.wordpress.com>