There are a number of web frameworks that are quite popular these days (Rails for Ruby, Django for Python, Yii or a number of others for PHP) but I have to say that even after working with all of those, ASP.NET MVC is probably my favorite. I’ve been writing C# for a number of years and have worked with ASP in everything from classic ASP in vbscript, to WebForms in C# and VB.Net and now to .Net MVC in C#. I’ve also been using Linux as a server platform for many years and I’m of the (possibly controversial) opinion that unless it’s *NIX, it doesn’t belong on a server. I’ve maintained Windows servers and I know how to do it, I just think there’s too much that the GUI and Registry try to hide from you in Windows. Give me /etc/ any day!
For awhile I stuck with web frameworks that were traditionally run on Linux for my personal projects (PHP, then Rails) but I just haven’t felt at home with them like I have with .Net MVC recently. I’m not sure if it’s because that’s what I work with on a daily basis at the office and I’m more familiar with it or what. Back at the end of 2012 (October 22, to be exact) the Mono Project released version 3. This is a significant release because Mono now supported C# 5.0 with asynchronous support and (here’s the part that I cared about most) they’re now shipping the open-source Microsoft frameworks with it by default. This means if you’re running Mono 3, you don’t need to do anything special to get MVC4 and EntityFramework 6. At that point I decided to try running my MVC4 apps in Linux so I’d be able to use a web framework I’m very familiar with on my personal projects.
The biggest problem I ran into, though, is that Mono 3 doesn’t actually seem to be getting into any stable package managers. It’s near impossible to find Mono 3 releases on the project website for Linux and at times I begin to wonder if it’s actually been released at all. Eventually I decided to buckle down and build it from source (from the GitHub repositories). It was a little more confusing than I had hoped the first time, so I figured I would write up a post on how to do it both because it will be a handy reference when I need to build it again and Brandon was asking for it. :)
Be Careful Building From Source
One thing you need to be careful of when building from source is that you’re either building from a known-stable build (whether it’s a tag, branch, or anything like that) or that you’re aware that you could be breaking your working code with some that doesn’t build at the time you pull the code down.
I ran into this once while running through the steps for this post. I had pulled down the code for Mono itself but it wasn’t building at the time, so I had to abandon the process and continue it later. For this post I’ll be targeting specific releases for each package, so you shouldn’t run into the same problem. If you do, however, you can take a look at the Mono build status page (https://wrench.mono-project.com/Wrench/, which funnily enough isn’t loading for me as I type this) to see if it’s a problem with the build itself or with your environment.
Originally I’d tried to build Mono 3 on one of my Arch Linux servers, but it seems like Arch has a newer version of autotools than Mono currently supports. I asked about it in #monodev on irc.gnome.org and someone else mentioned they’d created some patches to update autotools support, but that they weren’t accepted into the project because it might break backward compatibility. Hopefully it’ll be updated some day!
To try and make sure I don’t miss any steps of the process, I’ve set up a droplet on Digital Ocean using their Ubuntu 12.10 x64 Server image. I like Digital Ocean for one-off short-running servers because it’s pretty cheap to run (only $5/mo). For any of my normal servers I use Linode (full disclosure: I have my referral code on the Linode link). Anyway, I’m not sure if Digital Ocean has any additional packages installed from the base Ubuntu 12.10 image, but if you’re missing any binaries even after installing the prerequisites I mention that could be the cause. Before we get started, run this command to make sure you at least have the common build tools installed:
You may also want to set up a directory in your $HOME to keep your directory structure clean:
The first dependency that needs to be installed is libgdiplus. It provides a GDI+ compatible API on non-Windows platforms and is used by the System.Drawing library.
First of all, we need to clone the remote repository and check out the correct tag (2.10.8 as of this post):
Once the repository is on the correct revision, we need to install the dependencies. This sets up support for a number of image formats:
After the dependencies are installed, it’s time to set up the build scripts with the autogen.sh script. Based on the Linux Filesystem Hierarchy Standard, I usually install libraries and programs like this to /usr/local. To do this with the Mono build scripts, we specify it on the autogen.sh script with —prefix=/usr/local.
Next up are two commands that you’ll be familiar with if you’ve built software on Linux before:
Once the build is finished, it’s just a matter of installing it in /usr/local and going back to the base directory to get ready to install the next package, Mono itself:
The second of the three packages to compile and install is Mono itself. At the time of this post, the latest tag in the mono repository is for Mono 3.0.7, so that’s the one we’ll target. First step is to clone the mono repository (since all the dependencies are already installed) and then checkout the proper tag.
After checking out the correct version, it’s time to configure the build the same way we did with libgdiplus:
After this step, unlike libgdiplus, there’s an additional step before performing the actual build. Since we’re bootstrapping a new build of Mono (starting from scratch), it requires a minimal version of the Mono C# compiler to complete. There’s a package that the Mono project has for this purpose called monolite. To install this into the build directory, run:
Once the package is installed, it’s time to build Mono itself. One thing that’s different about this build than a normal ‘make’ build, though, is that we need to tell the build process where to find the monolite compiler with the EXTERNAL_MCS variable. Note that this is a make variable and not an environment variable.
Now that everything’s built, you’d install it as you did for libgdiplus and then go back to get ready to install XSP, the next package.
The last package to install is XSP, which is the package that contains Mono’s HTTP hosting modules. For now I’ll show you how to get it running in XSP itself, but XSP is really only intended for development. For a production site, you’d want to use either mod_mono for Apache or fastcgi with any fastcgi-supporting server (I prefer nginx).
The latest tag for the XSP repository at the time of this post is 3.0, so we’ll clone the repository and check out that one.
The rest of the build process is pretty much the same as with libgdiplus. If you want a refresher of why we’re running each command, take a look back at the steps for libgdiplus.
Serving a site with XSP is actually quite easy. The hardest part of it may be making sure that Mono supports all the libraries you’re using in your site. Since Mono is shipped with MVC4 and EntityFramework 6 right now, you’ll want to make sure you’re using those versions of the libraries to run your site. For testing, I started with an “Empty MVC4 Project” in Visual Studio 2012 to make sure it has the least amount of dependencies.
Update: Thanks to Ariex in the comments for the idea to provide the base MVC4 project I used. I’ve uploaded my project and made it available as mvctest.zip in the hopes it will remove that variable from the equation when you’re working on getting everything up and running.
Once you have a site built and uploaded to the server, navigate to the root directory of the site and just type:
This will start up the XSP server on port 8080 with the root of the site in the current directory.
One thing to note about running on Mono is that some Microsoft libraries were re-implemented by the Mono project. A specific issue I wanted to bring up is a possible exception in the Microsoft.Win32.KeyHandler namespace. If you run into this issue, be sure to remove the Microsoft.Web.Infrastructure assembly from the bin directory of your site. This is one of the assemblies that Mono has re-implemented, so you don’t need to provide your own.
And That’s It!
It took a little bit of work, but now you should have a fully functional MVC4 site running on Linux with the help of Mono. I will admit that I haven’t had a chance to run a full-featured MVC4 site on Mono yet, but the fact I can run MVC4 sites on Linux will lead me to doing more of my personal projects in .NET instead of an alternative framework.
The next step in hosting a .NET MVC4 site on Linux would be setting it up to run through a full-powered web server such as nginx or Apache. I plan to have a follow-up blog post at some point going over how to set up nginx as a proxy for the Mono fastcgi server, so watch for that coming up!