Installing Mono on VPS with nginx

From DreamHost
Revision as of 21:57, 9 April 2012 by Akroplax (Talk | contribs)

Jump to: navigation, search
The instructions provided in this article or section are considered advanced.

You are expected to be knowledgeable in the UNIX shell.
Support for these instructions is not available from DreamHost tech support.
Server changes may cause this to break. Be prepared to troubleshoot this yourself if this happens.
We seriously aren't kidding about this.

This tutorial is targeted at experienced Windows .NET developers with minimal Linux knowledge. This tutorial allows you to continue to run PHP sites you currently host in addition to .NET sites. Please excuse my lack of expertise on the subjects described below and feel free wiki talk or email me any constructive criticism or corrections (or just edit this document yourself). I'm documenting this all from memory and repetition of original research, so please forgive any omissions.

If you're an experienced Linux guru, please make appropriate edits or email me to discuss any issues. I would also be very interested in any tips regarding site security and hardening.

If you're experienced and just looking for a faster walkthrough and a script for Apache, the one in this blog looks to be pretty solid . An updated script for 2.6.7 is here

Also, I realize that this is in the commentary style of a blog post more than a wiki convention of factual assertions. Due to my lack of a blog and the accessibility of this wiki, it lives here (for now, at least).

Motivation

I'm a professional .NET developer who continues to spend his career in the Windows line of OSes. I've been using Dreamhost for 7 years primarily for a email and a few one-click installs. I have great respect for those who know PHP, but I don't have the time required to pick it up myself. I am also a big fan of Visual Studio 2010 with the ReSharper plugin. My wife recently began her own business that requires an online presence. While I've been wanting to use DreamHost for .NET hosting ever since I got it, this provided enough impetus to tackle the somewhat daunting task of hosting with Mono.

My wife's business includes the uploading of several photos. I use Gallery2, and it nearly always crashed my VPS during batch uploads. This lead me to do some research on site stability and scalability which lead me to converting from Apache to Nginx (pronounced "engine x"). I later discovered that the memory usage is due to the amount of memory necessary to load a JPEG into memory to allow for resizing. I'm still glad that I converted nonetheless.

Several walkthroughs I've seen include running custom scripts. While several of these scripts look very robust, my limited understanding of Linux makes me hesitent to execute someone else's script on my host. Also, some of DreamHost's internal customizations could conflict with script expectations.

Getting Started

  • Upgrade to VPS hosting or better - In DreamHost (and every shared hosting provider I'm aware of) a Virtual Private Server setup is the cheapest option for obtaining root access
  • Familiarity with a terminal, preferably SSH, to perform the actions below - I used [http://wiki.dreamhost.com/Putty PuTTY's SSH terminal}
  • Familiarity with a terminal text editor is very helpful too, but can be worked around through FTP and chmod (be sure to use UNIX line endings) - I used vi (installed by default). All you really need to know is that you can move around with your arrow keys, pgup and pgdn. Hit 'i' or 'a' to edit text where the cursor is. Then hit esc (to exit edit mode), colon, then 'wq' to save and quit (:wq). I used this tutorial.

Install JJs VPS Memory Manager

This is an optional step, but highly recommended. It automatically adjusts your VPS memory usage right before you need it. See the site here. Follow the installation instructions. It won't completely prevent all out of memory errors resulting from large spikes in server side processing (such as image resizing - which grabs a lot of memory in an instant), but it has added a tremendous amount of stability to my VPS at a very minimal cost.

Install Nginx

First, read through the following wiki page on nginx. Basically, you just set an option in your Panel. Of special note is that .htaccess files are not read by nginx. Access control is instead handled by .conf files. There are many good articles on this conversion, but I won't be going into any detail here. Be sure to familiarize yourself with the information under the "Configuration File Locations" heading.

As a side note, if you plan to continue hosting PHP for one-click installs or any custom work, you can execute the following script to upgrade your nginx PHP to 5.3: http://files.gimmesoda.com/php53-fpm.sh. I believe some other tweaks were necessary to pick up 5.3, but I don't have any record of those changes. If someone knows what they are, please edit this page or let me know via wiki talk or email. The wiki page on Php.ini may help.

Add an Admin User

As the above "Install Nginx" section mentions, you need to add an admin user to modify your config files as well as executing several of the commands later in this tutorial. Go to the Manage Admin Users page and create a user. When logged in with your admin account, you need to preceed commands with 'sudo' to assert your root-level credentials. Any command preceeded by 'sudo' has the potential to bring down all of the sites you are hosting, so always be careful of typos and confident in what you're executing before performing any of these commands.

Create a Cron Job to Support Nginx Recovery from Server Reboot

A 'gotcha' that isn't mentioned in the nginx article is the fact that nginx doesn't restart itself when your OS instance is restarted. This is most commonly associated with using more memory than you have allocated for your VPS. System-wide outages can also create this situation. I called this script "restartPhpNginx.scr".

#!/bin/bash

PGREP="/usr/bin/pgrep"
PHPD="php53.cgi" # or "php5.cgi" if you didn't upgrade to 5.3

$PGREP ${PHPD}

if [ $? -ne 0 ]; then # No php processes, restart nginx
/etc/init.d/nginx stop
/etc/init.d/nginx start
fi

(thanks to smc1979 from the thread http://discussion.dreamhost.com/thread-128870.html for creating this script)

If you're using PuTTY and vi, you can copy the above text and then login as your admin user and perform the following:

cd $home
vi restartPhpNginx.scr

Then simply hit "i", right-click in the PuTTY window to paste, then hit your "esc" key and type in ":wq" to save the new file and quit vi.

Since your admin user is inaccessible from the "Add New Cron Job" function of your Cron Jobs Panel page, we need to make our own Crontab. From your PuTTY shell, type the following:

sudo crontab -e

This opens your crontab in the "nano" editor. The following line executes the above script once every minute with locking. If you would like to change the interval, please see the Crontab wiki page. Copy the following line (or one with your modified interval) and the right-click in PuTTY to paste:

* * * * * /usr/local/bin/setlock -n /tmp/cronlock.1234567.123456 sh -c $'/bin/bash /home/adminusername/restartPhpNginx.scr'

Then replace adminusername and hit "ctrl-k" and then "x" to save and exit. To confirm your changes, type:

sudo crontab -l

At this point, I suggest rebooting your VPS, waiting a few minutes, and then verifying that one of your existing sites is still active. If you have difficulties and need to restore your site while troubleshooting type the following into your PuTTY terminal:

sudo /etc/init.d/nginx start

Prevent DreamHost from Resetting Customizations

In the Panel, go to the VPS Configure Server page. Before setting up Mono, I upgraded my Nginx PHP version to 5.3 (which isn't supported through the panel). So I'm not entirely certain as to what each of these items are necessary for this setup. If someone knows, please help me fill in my knowledge gap here. Note that these options are not available until after you have created your admin user.

  • Under "Web Server Configuration", uncheck "DreamHost Managed"
  • Under "PHP Configuration", uncheck "DreamHost Managed" (this may not be necessary if you're okay with PHP 5.2 for your non-mono sites).

After doing this, you will need to manually edit your nginx.conf file to add new domains. When you add a new domain, DreamHost is nice enough to add a sample config file in the same location as your nginx.conf file so that you can copy out the section created for your new "fully hosted" domain and paste it into your customized nginx.conf file. For more information on editing this file, see the section "Modify Nginx.conf". I'm not sure if there are other impacts to removing those two items from being managed by DreamHost. If there are, I haven't encountered them yet.

Update Apt-get Sources to Include Official Squeeze Packages

This may be entirely unnecessary as I used this while going down the path to install mono from apt-get. Before I executed the command though, I found a fairly simple way to get the latest stable version of mono instead of being stuck with an older version (2.6.7 at the time of this writing). If the proceeding installation of git isn't able to be found, then this step is necessary. If someone follows this tutorial, please email or post to my wiki talk page to let me know.

The Debian documention on apt-get sources.list file is here.

I suggest making a backup of the file first:

cd /etc/apt/
sudo cp sources.list sources.list.monobak
vi sources.list

Here are the lines I added to my sources.list file - based on this thread:

## Debian.org:
deb http://ftp.debian.org/debian/ squeeze main contrib non-free
deb-src http://ftp.debian.org/debian/ squeeze main contrib non-free

## Debian Official Repository Mirror squeeze:
deb ftp://debian.oregonstate.edu/debian/ squeeze main contrib non-free
deb-src ftp://debian.oregonstate.edu/debian/ squeeze main contrib non-free
deb ftp://debian.oregonstate.edu/debian/ squeeze-proposed-updates main contrib non-free
deb-src ftp://debian.oregonstate.edu/debian/ squeeze-proposed-updates main contrib non-free

## Debian US mirror:
deb ftp://ftp.us.debian.org/debian/ squeeze main contrib non-free
deb-src ftp://ftp.us.debian.org/debian/ squeeze main contrib non-free

Someone please confirm or deny the existence of the git package within the default sources.

Temporarily Increase your VPS Resources

Before running an installation, I like to increase my VPS resources to prevent it from rebooting itself. To do this, either edit the config.php file of JJ's Memory Manager or disable it and increase the amount under Manage Resources on your DreamHost Panel. I usually set it to max memory to be safe. You can verify that the increase has taken effect by refreshing the Manage Resources page.

Install Git

sudo apt-get update
sudo apt-get install git-core

It shouldn't take too long to execute.

Compile Newest Stable Mono Source

It may take close to an hour to exeucte the following commands. I walked away while they executed and didn't watch the clock. I selected version 2.10.8 since it is said to be the Latest Stable Version on Mono's official downloads page. The page specific to Debian is less clear about what is Latest Stable, and I didn't want to use 2.6.7.

Install the mono dependancies (this also may require the extra sources added to sources.list):

apt-get build-dep mono-fastcgi-server2

Once complete, we now get the mono source:

cd /usr/src
sudo git clone https://github.com/mono/mono.git
cd mono
sudo git checkout 2.10.8
sudo apt-get install autoconf libtool automake bison
sudo ./autogen.sh
sudo make
sudo make install

The above commands are from this blog. I'm not sure if the version number is necessary. Normally, not specifying a version would produce the latest version. But I don't know enough about git to be able to say for certain, so I left them in. I'm also not sure if all the commands are necessary in the bison line. What I do know is that this worked perfectly for me.

As new bulids become available, I imagine that the above lines can be executed again with the newest build number.

You can probably delete the /usr/src/mono directory once the installation is complete.

Please note that this process does not include libgdiplus. Other tutorials cover this if you're interested, but System.Drawing.dll is not normally referenced from within a web project.

Compile Newest Stable XSP Source

This is pretty much the same as above, except the latest version of xsp is 2.10.2 (I just worked my way down until I stopped getting a "not found" message)

cd /usr/src
sudo git clone https://github.com/mono/xsp.git
cd xsp
sudo git checkout 2.10.2
sudo ./autogen.sh
sudo make
sudo make install

To my best recollection, I did not execute any apt-get command for xsp.

Return your VPS Resources to their Original State

Now that we're done with the intense server usage, undo what you did in the 'Temporarily Increase your VPS Resources' section.

Modify nginx.conf

The official mono page for the configuration is here. As mentioned in the Nginx wiki page, the file is located at:

/dh/nginx/servers/httpd-psXXXXXX/nginx.conf

Create a backup as we did with sources.list and then open the original with sudo vi. I took the following snippit:

	server {
		listen x.x.x.x:80;

		server_name yourdomain.com www.yourdomain.com;

		access_log /home/yourhostinglogin/logs/yourdomain.com/http.xxxxxxxx/access.log combined;
		error_log /home/yourhostinglogin/logs/yourdomain.com/http.xxxxxxxx/error.log error;

		root /home/yourhostinglogin/yourdomain.com;

		index index.html index.htm index.php index.php5;
		include /home/yourhostinglogin/nginx/yourdomain.com/*;

And made it:

	server {
		listen x.x.x.x:80;

		server_name yourdomain.com www.yourdomain.com;

		access_log /home/yourhostinglogin/logs/yourdomain.com/http.xxxxxxxx/access.log combined;
		error_log /home/yourhostinglogin/logs/yourdomain.com/http.xxxxxxxx/error.log error;

		root /home/yourhostinglogin/yourdomain.com;

		index index.html index.htm default.aspx Default.aspx;
		# This is the starting location of the MVC 3 template.  
		#  You can change this to Default.aspx or whatever contains your starting page:
		fastcgi_index Home/Index;
		include /dh/nginx/etc/fastcgi_params;
		include /home/yourhostinglogin/nginx/yourdomain.com/*;

As you can see, one line is modified and two are added. The rest is included for context.

Then at the end of the server section I added:

		# Mono
               location / {
                       fastcgi_pass 127.0.0.1:9000;
               }

Replace yourdomain.com and yourhostinglogin. Note that this is NOT your admin login. Once complete, save and exit vi.

Modify fastcgi_params

Use sudo vi to make the required additions to your fastcgi_params file in your /dh/nginx/etc/ directory:

# mono
fastcgi_param  PATH_INFO        "";
fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

Build and Publish Your Web Application

I'm sure there are several ways to accomplish this. What I did was create a new MVC 3 web application with Razor. Then I right-clicked on the main project and selected Publish. I selected the "Publish method" of File System and set the Target Location to my local FTP upload directory.

Also note that you will need to set the following assemblies' Copy Local property to True. Those that don't appear in your current references list need to be added from the .NET references tab.

System.Web.Abstractions
System.Web.Helpers
System.Web.Mvc
System.Web.Razor
System.Web.Routing
System.Web.WebPages
System.Web.WebPages.Deployment
System.Web.WebPages.Razor

Upload Your MVC or ASP .NET site

Use your favorite SFTP client to upload your published target directory over to your domain hosting location.

Create and Install XSP Fastcgi Startup Script

This is almost a straight copy/paste from this site. The only change is fastcgi-mono-server2 becomes fastcgi-mono-server4 and the WEBAPPS line. I am including it here in case that page ever becomes unavailable before this one does.

Get to the correct directory and create a script we'll call monoserve:

cd /etc/init.d/
sudo vi monoserve

Then copy the following code, hit "i" within vi, then right-click to paste:

#!/bin/sh

### BEGIN INIT INFO
# Provides:          monoserve.sh
# Required-Start:    $local_fs $syslog $remote_fs
# Required-Stop:     $local_fs $syslog $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start fastcgi mono server with hosts
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/bin/mono
NAME=monoserver
DESC=monoserver

MONOSERVER=$(which fastcgi-mono-server4)
MONOSERVER_PID=$(ps auxf | grep fastcgi-mono-server4.exe | grep -v grep | awk '{print $2}')

WEBAPPS="www.domain1.xyz:/:/home/yourhostinglogin/domain1.xyz/,www.domain2.xyz:/:/home/yourhostinglogin/domain2.xyz/"

case "$1" in
        start)
                if [ -z "${MONOSERVER_PID}" ]; then
                        echo "starting mono server"
                        ${MONOSERVER} /applications=${WEBAPPS} /socket=tcp:127.0.0.1:9000 &
                        echo "mono server started"
                else
                        echo ${WEBAPPS}
                        echo "mono server is running"
                fi
        ;;
        stop)
                if [ -n "${MONOSERVER_PID}" ]; then
                        kill ${MONOSERVER_PID}
                        echo "mono server stopped"
                else
                        echo "mono server is not running"
                fi
        ;;
esac

exit 0

Change domain1.xyz, domain2.xyz (or remove the comma and everything to the closing quote), and yourhostinglogin. Then save and close vi.

We then need to add the appropriate rights:

sudo chmod +x /etc/init.d/monoserve

And install the script:

update-rc.d monoserve defaults

Conclusion

At this point, you should be able to reboot your VPS server. Be careful not to click on the new button that says "Reset state of psXXXXX now!", as that may be a new option if you recently created a VPS admin account. Give it a few minutes and then browse to your domain. You should see your .NET site up and running!

If you have any further difficulties specific to .NET, some great migration, setup and howto guides are found at the mono website

Originally created by Akroplax 22:20, 9 April 2012 (PDT)

See also

External links