CGI is the most widely supported web server application interface. ASP.NET (and Mono) has a relatively long startup time and requires a relatively large amount of initial memory that makes it unsuitable to be used as a CGI application in the traditional way because CGI requires the web server to create a new application process for each request.
Both mod_mono and fastcgi-mono-server are using a persistent separate process that is processing the requests thus eliminating the performance impact of long startup time and reducing overall memory requirements.
Shared hosing environments usually use Apache that only has support for CGI out of the box. Both mod_mono and FastCGI support require installing modules that can only be done by server administrators.
cgi-fcgi is a CGI to FastCGI bridge also capable of starting a FastCGI application that has support for a wide range of platforms. cgi-fcgi along with fastcgi-mono-server enables ASP.NET on any web server that has support for CGI without noticeable performance impact.
Table of contents
Installing Mono and cgi-fcgi
The following sample configuration assumes installation prefixes used here to configure cgi-fcgi and mono. If you use different prefixes you also will have to modify the sample files:
$ tar xzf fcgi-2.4.0.tar.gz $ cd fcgi-2.4.0 $ ./configure --prefix=/home/username/fcgi $ make $ make install ... $ tar xjf mono-2.4.tar.bz2 $ cd mono-2.4 $ ./configure --prefix=/home/username/mono $ make $ make install ... $ tar xjf xsp-2.4.tar.bz2 $ cd xsp-2.4 $ export PATH=/home/username/mono/bin:$PATH $ export PKG_CONFIG_PATH=/home/username/mono/lib/pkgconfig:$PKG_CONFIG_PATH $ ./configure --prefix=/home/username/mono $ make $ make install
You also may compile them on a compatible development machine using the same installation prefixes and upload the binaries to the web server.
If you have no shell access to the web server you can use PHP Shell that is a lightweight remote shell wrapper to extract compressed files, monitor or kill your processes or execute arbitrary commands.
Handler CGI script (/home/username/public_html/cgi-bin/mono-cgi):
#!/home/username/fcgi/bin/cgi-fcgi -f -connect /home/username/tmp/mono-fcgi.sock /home/username/bin/mono-fcgi
Using this configuration cgi-fcgi will create a listening socket and pass it to a new mono-fcgi process when unable to connect to the socket that will avoid race conditions and will result in less overhead than using a shell script. For more information see cgi-fcgi documentation.
A separate shell script (/home/username/bin/mono-fcgi) is required to start fastcgi-mono-server because cgi-fcgi has no support for setting environment variables or passing arguments to the FastCGI application. CGI variables also have to be removed to avoid falling back to them:
#!/bin/sh umask 0077 exec >>/home/username/tmp/mono-fcgi.log exec 2>>/home/username/tmp/mono-fcgi.err echo $(date +"[%F %T]") Starting fastcgi-mono-server2 cd / chmod 0700 /home/username/tmp/mono-fcgi.sock echo $$>/home/username/tmp/mono-fcgi.pid # stdin is the socket handle exec env -i \ PATH="/home/username/mono/bin:$PATH" \ LD_LIBRARY_PATH="/home/username/mono/lib:$LD_LIBRARY_PATH" \ TMP="/home/username/tmp" \ MONO_SHARED_DIR="/home/username/tmp" \ /home/username/mono/bin/fastcgi-mono-server2 \ /root=/home/username/public_html /applications=/:/home/username/public_html
This script also logs stdout and stderr and creates a pid file.
You may want to use name based virtual hosts or define more applications on command line. For more information see How Applications are Handled.
Recycling the FastCGI server
The FastCGI server can be recycled by removing the socket file that will allow pending requests to be processed by the existing server process while new requests will be routed to a new server process created by cgi-fcgi.
The following script (/home/username/bin/recycle-mono-fcgi) can be used in a cron job to recycle the FastCGI server periodically:
#!/bin/sh SOCKETFILE=/home/username/tmp/mono-fcgi.sock PIDFILE=/home/username/tmp/mono-fcgi.pid PID=0 if [ -e $PIDFILE ]; then PID=$(cat $PIDFILE 2>/dev/null) if [ -z "$PID" -o -z "$(ps --pid $PID -o pid=)" ]; then PID=0 fi fi if [ $PID -ne 0 ]; then # New requests will be routed to a new server process rm -f $PIDFILE rm -f $SOCKETFILE # Wait for pending requests sleep 2 kill $PID # Wait for graceful shutdown sleep 2 if [ -n "$(ps --pid $PID -o pid=)" ]; then # Kill if failed to terminate kill -9 $PID fi fi
For security reasons you should execute this script using the user account of the FastCGI server to avoid terminating processes of other users.
To improve security you should disable access to CGI script source code (/home/username/public_html/cgi-bin/Web.config):
<configuration> <system.web> <httpHandlers> <add verb="*" path="mono-cgi" type="System.Web.HttpForbiddenHandler" validate="true"/> </httpHandlers> </system.web> </configuration>
A simple Apache configuration file (/home/username/public_html/.htaccess):
Action mono-cgi /cgi-bin/mono-cgi AddHandler mono-cgi .aspx .asmx .ashx .ascx .asax .axd .config .cs
You may want to handle other extensions with ASP.NET. For more examples on configuration see Manual Mod_Mono Configuration.
To improve security you should protect ASP.NET Application Folders:
Redirect 404 /bin Redirect 404 /App_Browsers Redirect 404 /App_Code Redirect 404 /App_Data Redirect 404 /App_GlobalResources Redirect 404 /App_LocalResources Redirect 404 /App_WebReferences
Non-existent files can also be handled with Apache 2.2:
Action mono-cgi /cgi-bin/mono-cgi virtual AddHandler mono-cgi .aspx .asmx .ashx .ascx .asax .axd .config .cs
Or handle all requests with ASP.NET:
Action mono-cgi /cgi-bin/mono-cgi SetHandler mono-cgi
You also will have to create a configuration file (/home/username/public_html/cgi-bin/.htaccess) to avoid server error resulting from circular dependency:
<Files mono-cgi> Options +ExecCGI SetHandler cgi-script </Files>
You also may have to use this to enable CGI script execution.
Author: Kornél Pál <http://www.kornelpal.com/>