Developing and Deploying ASP.NET MVC Applications On Ubuntu Linux with Mono, nginx and MySQL
2011-03-21 in web, asp.net
Mono is moving forward at an impressive pace: the team at Novell and the Mono community deserve some massive respect. In the more recent versions, support for ASP.NET MVC emerged and the new Microsoft library became a part of the core. Combined with XSP (the Mono web server) and its FastCGI server, it became possible to serve ASP.NET MVC applications from your Linux machines.
This post is a quick summary of my first steps in creating a development environment and setting up a server for ASP.NET MVC on Linux. Tools of the trade will be Ubuntu 10.04 (Lucid Lynx), the nginx web server and XSP’s FastCGI server. I’ll assume you have a working setup featuring nginx and MySQL on your server – configuring these is beyond the scope of this article.
Much of this was never tested in a production environment. I have yet to develop a non-trivial application running on top of all of this and I can’t guarantee everything is bug-free and 100% functional. People are using Mono in production, the whole thing looks and feels really solid, but definitely make sure you test everything before diving in.
Mono.GetLastVersion();
Ubuntu depends on Mono quite a lot, so don’t expect to find the latest and greatest version in your package manager. There is some comfort in the form of Badgerports, but it’s LTS-only, and it’s usually a bit behind the latest Mono stable. The solution is to compile Mono from source, which is actually a lot easier than it sounds.
If you feel you can live with an older version of Mono and are using a long-term supported release of Ubuntu, go ahead and grab the Badgerports repository and install their Mono packages. The crew is doing awesome work and the backport works great. Compiling stuff from scratch means you have to keep an eye out for security updates and recompile when necessary to keep your server safe, which can be stressful. If you really like living on the edge, follow the instructions below.
The whole process is made easy by a nice shell script written by Patrick McEvoy which does all the heavy lifting. The script is nicely written, so if you don’t like running random stuff from the web as root (and you shouldn’t!), feel free to take a peek, see what it does and do the whole thing by hand.
Clone the Git repo or fetch the script directly from GitHub and see what the script does by typing ./mono_build.sh -h
(you’ll have to chmod +x mono-build-sh
if you already didn’t). The choice between the correct flags depends on what you’re configuring:
- for my development machine, I chose to build “just Mono” (the -r flag), and then added gnome-sharp and monodevelop afterwards (-m mono-addins gnome-sharp gnome-desktop-sharp monodevelop);
- for my VPS, I chose to build “just Mono”, without any additional modules.
Run the script with your selected parameters (don’t forget to specify the prefix!) and grab a cup of coffee as it could definitely take a while.
You may get compile errors while installing MonoDevelop. Depending on your current Mono configuration, you may need to uncheck certain MonoDevelop packages in the configure phase: I only checked “main”, “extras/MonoDevelop.Database” and “extras/MonoDevelop.Debugger.Gdb”; the “extras/BooBinding” and “extras/MonoDevelop.MonoDroid” packages I tried to install caused the compiler to choke. If you make a mistake in this phase, go to the MonoDevelop source directory, and do a sudo ./configure --select
; choose the packages and then try to recompile with mono_build.sh
.
When finished, you should have a fully-functioning version of Mono in a directory of your own choice. Follow the instructions to enable and test your new installation, and buy Patrick a beer for his awesome work.
Setting up nginx and FastCGI
You don’t need to set up FCGI on your development machine – you can happily use the standalone XSP which was built as a development server. XSP loads automatically when you run your app from MonoDevelop.
XSP provides a FastCGI server, which is an excellent way to make Mono and nginx talk. For this to work, you’ll need to know the exact location of the fastcgi-mono-serverX
(where X is one of { “”, “2″, “4″ }, depending on the ASP.NET version you’d like to use). If you installed the Badgerports backport, it’s probably in your PATH
; if you compiled from source, it’s in $PREFIX/bin/fastcgi-mono-serverX
.
Now we need to point nginx to the FastCGI binary. Here’s a sample configuration file:
server {
server_name {SERVER};
access_log {ACCESSLOG};
root {ROOT};
# magick start!
location / {
index index.html index.htm default.aspx Default.aspx;
# DEFAULTROUTE is the default route of your app; e.g. Home/Index
fastcgi_index {DEFAULTROUTE};
# choose a free port; e.g. 9001
fastcgi_pass 127.0.0.1:{PORT};
include /etc/nginx/fastcgi_params;
}
# /Content contains just static files - we don't need
# no FCGI to serve those!
location /Content/ {
}
}
You can easily deploy your ASP.NET application to {ROOT} by using MonoDevelop’s “Deploy to Web” functionality (Tools – Deploy to Web).
Now, edit /etc/nginx/fastcgi_params and add the following two lines defining certain environment variables the FastCGI server expects to find:
fastcgi_param PATH_INFO "";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
Finally, start the FastCGI server itself:
$PREFIX/bin/fastcgi-mono-server2 /applications={SERVER}:/:{ROOT} /socket=tcp:127.0.0.1:{PORT} &
Restart nginx and your application should be ready at the server_name of your choice. However, manually starting up FCGI isn’t too exciting. Fortunately, there’s an awesome script written by Tomas Bosak which automates that part – follow Tomas’ instructions to install the script, but make sure to update the path to the FastCGI binary if you compiled from source.
Another option would be to use nginx to proxy requests to a standalone XSP instance: it should be fairly straightforward, but I didn’t try it at all.
Mono <3 MySQL and Fluent NHibernate
Web applications usually work with some kind of a database. There are several ADO.NET providers working with Mono for different database servers like MySQL, PosgreSQL and Microsoft SQL Server. MySQL provides the Connector/Net library, which is a fully-managed ADO.NET provider. Setting it up is easy: download the library, unzip and add a reference to mysql.data.dll
in MonoDevelop. Also note you’ll have to use the DLL from the “v2/” folder. There’s a quick & dirty tutorial on the Mono project website, and in-depth documentation on the MySQL website which should have enough information to get you up & running.
If you run into a “connection refused” message while trying to connect with MySQL, take a peek in your /etc/mysql/my.cnf: you should either have an uncommented line in there saying “skip-networking”, or a directive which says “bind_address = 127.0.0.1″, depending on your MySQL version.
If you’d like to use Fluent NHibernate with Mono – good news! It works perfectly without any hacks: just download Fluent NHibernate and reference it in your project. Here’s a sample CreateSessionFactory() method for MySQL:
private static ISessionFactory CreateSessionFactory() {
string connStr = "server=localhost;user={USER};database={DB};port={PORT};password={PWD}";
return Fluently.Configure()
.Database(
MySQLConfiguration.Standard.ConnectionString()
)
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.BuildSessionFactory();
}
Voilà.
ASP.NET MVC 3, WebMatrix, future…
Mono 2.10 should support ASP.NET MVC 3, although it’s not yet bundled with Mono as is the case with previous versions. There is also some preliminary support for WebMatrix in the form of WebMatrix.Data.dll and Razor. I didn’t have the time to play with any of these, so if you have some experience in setting it up, please share them in the comments.
I really like C# and ASP.NET MVC and I enjoy the idea of running .NET web applications on top of my preferred OS. This is something I’ll definitely be tinkering with in the future. For any questions, comments, advice or suggestions, feel free to use the comment form below, mention me on Twitter or contact me by e-mail on nikola@plejic.com.