Hosting ASP.NET 5 web application on GNU / Linux

Jan 18, 2015

The brand new version ASP.NET 5 (a.k.a ASP.NET vNext) can be developed and hosted on all three major platform - Windows, Linux and MacOS.

Getting started with ASP.NET 5 (TODO: Link to be updated with new Post for .NET tools) is not so hard after all and is definitely fun to play early. The biggest break through that comes to .NET and ASP.NET world is the capability to write and host anywhere.

Yes you can now develop and host a ASP.NET Web application - MVC or WebAPI even SignalR on any platform - Windows, Linux and MacOS. This has always been the de-facto standard for windows since long using Visual Studio (prior VS2015) but it can be fun on Linux and MacOS also using your favourite editors or Visual Studio Code.

Following step needs to be performed on a brand new spinning Linux box to develop or host a ASP.NET 5 (vNext) web application:

Note: For the sake of writing I am using a Ubuntu 14.04 Trusty x64 - DigitalOcean droplet (highly recommended for Linux based hosting).

SSH into your Linux box and lets get started...

Step (optional, but recommended): Let us first update / upgrade the Linux

sudo apt-get update
sudo apt-get upgrade

Step: Install some pre-requisite packages that will be required for the following setup to work

sudo apt-get install make -y
sudo apt-get install zip unzip curl git libtool autoconf automake build-essential zsh gyp -y

Step: ASP.NET 5 runs on top of Mono Framework (.NET equivalent for non-windows platform) using .NET tools (DNVM, DNU and DNX.

First, let us install Mono Framework

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
    
echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list

Update / Upgrade apt-get package manager references:

sudo apt-get update

Install Mono Framework:

sudo apt-get install mono-complete -y

Once the installation completes you can check the Mono version that was installed:

mono --version

output should be similar to following (version number might vary)

Mono JIT compiler version 4.0.3 (Stable 4.0.3.20/d6946b4 Tue Aug  4 09:43:57 UTC 2015)

Step: Import few certificates to CERT manager for URL(s) that the .NET tools (DNVM / DNU / DNX) and your application may connect and need SSL trust to work properly (may not work in all cases):

sudo yes | certmgr -ssl -m -v https://go.microsoft.com
sudo yes | certmgr -ssl -m -v https://nugetgallery.blob.core.windows.net
sudo yes | certmgr -ssl -m -v https://myget.org
sudo yes | certmgr -ssl -m -v https://nuget.org
sudo yes | certmgr -ssl -m -v https://www.myget.org/F/aspnetvnext/
sudo mozroots --import --sync --quiet

IMP note: There is no IIS on Linux (you awll know that aay) so ASP.NET 5 uses webserver package Kestrel to run the application and serve request.

This is a development ready / internal self host web server that initiates from the application and host the ASP.NET 5 web application. If you follow this article step-by-step completely then Kestrel will be proxy hosted with Nignx to serve request publically (general practice followed by other frameworks on Linux like node)

Kestrel package uses Libuv cross-platform asynchronous I/O library to self host ASP.NET 5 web application. This package may or may not be present or setup on your machine

Step: (Optional if Libuv is already present) Setup Libuv package on Linux [Reference ASP.NET github home repo docs]:

curl -sSL https://github.com/libuv/libuv/archive/v1.7.0.tar.gz | sudo tar zxfv - -C /usr/local/src
cd /usr/local/src/libuv-1.7.0
sudo sh autogen.sh
sudo ./configure
sudo make
sudo make install
sudo rm -rf /usr/local/src/libuv-1.7.0 && cd ~/
sudo ldconfig

At the time of this writing the latest version of Libuv was 1.7.0. Above command should be updated for the version of Libuv you are installing.

You can find your currently installed Libuv version installed in /usr/lib/libuv.so.x.x.x location.

Step: Install and setup .NET tools (DNVM, DNU, DNX), you can follow the instructions on ASP.NET Home github repo or continue here. (Remember K tools are older versions of .NET tools before the big rename)

sudo apt-get install unzip
curl -sSL https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.sh | DNX_BRANCH=dev sh && source ~/.dnx/dnvm/dnvm.sh

Get latest version of .NET execution environment (DNX) for MONO / Linux:

dnvm upgrade

At the time of writing dnvm upgrade installed dnx-mono.1.0.0-beta6. On dnvm list shows following output:

Active	Version			Runtime		Arch		OperatingSystem		Alias
------	-------			-------		--------			-----		-----
*		1.0.0-beta6		mono						linux/darwin	default

Step: (Optional if do not want to publically host ASP.NET 5 web application) - Install Nignx and configure to proxy host - ASP.NET 5 web application which runs using Kestrel, .NET Tools (DNVM, DNX, DNU), Mono Framework.

sudo apt-get update
sudo apt-get install nginx -y

This should install Nignx web server. To start / stop Nginx web server following command can be used:

sudo service nginx start
sudo service nginx stop

This command helps to check if currently Nignx is running or not:

ifconfig eth0 | grep inet | awk '{ print $2}'

Configure Nginx to start on machine start or reboot:

update-rc.d nginx defaults

Create a Nginx specific configuration for your ASP.NET 5 application:

sudo nano /etc/nginx/conf.d/<domain-name>.conf

Replace <domain-name> with your public domain name on which you want your ASP.NET 5 web application to be hosted.

In the NANO editor paste / write following code:

server {
	listen 80;
    server_name <domain-name> www.<domain.name>;
    client_max_body_size 10M;
    location / {
    	proxy_pass http://localhost:5004/;
        proxy_redirect off;
        proxy_set_header HOST $host;
        proxy_buffering off;
    }
}

Note: Replace <domain-name> with your actual domain name

Create cache directory for Nignx webserver:

sudo mkdir /var/cache/nginx
sudo chown www-data:www-data /var/cache/nginx

Create a web root directory for your ASP.NET 5 web application to reside:

sudo mkdir /var/www
sudo chown www-data:www-data /var/www
sudo mkdir /var/www/<domain-name>
sudo chown www-data:www-data /var/www/<domain-name>

Note: Replace <domain-name> with your actual domain name. This is the folder where your application will reside.

Should also remove default file if found in any of the following directories: /etc/nginx/conf.d/, /etc/nginx/sites-available/ or /etc/nginx/sites-enabled/ using sudo rm -rf <directory or filename>

Also do not forget to restart Nginx after the changes made using sudo service nginx restart to take effect.

Step: Create the simplest form of ASP.NET web application to get started - will display brand new ASP.NET 5 vNext welcome page

cd /var/www/<domain-name>/
sudo nano project.json

Paste the following code in the newly created project.json file:

{
  "dependencies": {
      "Kestrel": "1.0.0-beta6",
      "Microsoft.AspNet.Diagnostics": "1.0.0-beta6",
      "Microsoft.AspNet.Hosting": "1.0.0-beta6",
      "Microsoft.AspNet.Server.WebListener": "1.0.0-beta6",
      "Microsoft.AspNet.StaticFiles": "1.0.0-beta6"
  },
  "frameworks": {
  	 "dnx451": { },
     "dnxcore50": { },
  },
  "commands": {
      "kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5004"
  }
}

This should do the minimal required for the web application to run. Currently at the time of writing ASP.NET 5 is in BETA-6 (most stable beta), should update the package version accordingly if required.

Next create Startup.cs file:

sudo nano Startup.cs

Paste following code in newly created Startup.cs file and save the file with Ctrl + x => Yes => Enter:

using Microsoft.AspNet.Builder;
namespace HostKWebOnLinux
{
    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.UseStaticFiles();
            app.UseWelcomePage();
        }
    }
}

Run dnu restore to download and restore all packages mentioned in the project.json file.

Last and the final step to BOOM start it all dnx . kestrel - hit your <domain-name> and wallah, you see the default ASP.NET 5 vNext Welcome page.

Updates [18th March, 2015] - Article updated to use Mono 3.12.1, ASP.NET beta-3 and libuv-v1.4.2 (thanks to JUNSUI - for reaching out - refer comments).

Updates [19th March, 2015] - For Linux VM user on Azure, who wish to make their ASP.NET application publically accessible, need to enable or add entry of specific endpoints in Azure management portal.

Following screenshot explains this part while creating VM:
ASP.NET 5 - Linux VM - Azure Endpoint configuration

Things to understand here:

  • The cloud service DNS name (configuration [1]): example junsui-test.cloudapp.net is a default domain name assigned to this VM by Azure DNS service and can be used as your so called domain name to access anything hosting on this VM

  • To make anything accessible from public (on Azure), you need to enable ENDPOINTS for it.

  • If you followed the NGINX path from the above walkthrough then you should enable configuration [2] marked red in above screenshot. Considering that your /etc/nginx/conf.d/<domain-name>.conf has listen:80. In this case our project.json localhost:5004 should remain the same.

  • If you do not want to use the NGINX server as public webserver or proxy host your application, then you should try using configuration [3] in above screenshot: use PUBLIC PORT as whatever you wish to access with and the PRIVATE PORT as 5004 as mentioned in your application's project.json file. In this case you need to use public IP Address provided by Azure instead of localhost at following line in project.json
    "kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://<azure-public-ipaddress>:5004"

    You can find the Public (Virtual) IP Address of your VM in that VM's dashboard page in Microsoft Azure Management Portal:

Azure portal - Public IP Address

Umm:

  • Why do I need Nignx and Kestrel, that is two webserver, right? Can't I just host the application using dnx . kestrel and point to public URL?

    Yes you can, but Kestrel is ASP.NET 5 specific in-place self hosting web server. This may or may not contain ways to configure many of the generic web server configuration. Even if it does then you need to change / set them in your application or somewhere in your project.json.

    Nginx play the role of middleman and takes care of the generic webserver request serving stuffs. Also enables to host more than one web application (any other web application - node.js, aspnet 5, php or wordpress) along side of your ASP.NET 5 web application.

    Kestrel takes care of the ASP.NET specific and application specific stuffs in that case. This is much similar to hosting CoreCLR based application (web command) in IIS / IIS Express using IIS Helios hook.

  • Where is the frameworks node in project.json file?

    As noted on Github ASP.NET Home repository:

    NOTE: There is no Core CLR currently available on OSX/Linux. There is only a single platform (mono45) and a single architecture (x86).

    I removed the frameworks node and it still works, sue me.

    Update [11th May, 2015] - Sorry don't sue me, framework node was optional on Linux / MONO till beta-3 but now its mandatory or else you would encounter error similar to following when you dnx . kestrel:

    System.InvalidOperationException: Failed to resolve the following dependencies for target framework 'DNX,Version=v4.5.1':

  • There is so much commands to just get up and running, arrggh

    Yes there is. Most of them are pretty straight forward. There is also a shell script created by Punit Ganshani (Unfortunately not updated since 6th Dec, 2014 - try or modify at your own risk) to do most of the stuffs automatically for your. Use it with few modification / update if you feeling lazy or big fan of Automation. Also should give a look at Chef, Puppet and Docker if you feel automation is your way. There is ASP.NET 5 Preview Docker Image and way to configure it which you can use to run ASP.NET 5 vNext application in Microsoft Azure Linux Docker Image.

  • Anything else Mr. Umm?

    Yes, use DNX_TRACE environment variable if anything related to .NET tools (DNVM, DNU, DNX) / Kestrel has gone bananas. Export environment variable on Linux using export DNX_TRACE=1. Also look for dnu pack / dnu help pack to create deployment packages for your ASP.NET 5 web application and then you can x-copy / FTP your package where you wish to host your application.

Updates [11th May, 2015] - Article updated to use Mono 4.0.1, ASP.NET 5 beta-4 and libuv-v1.5.0.

Updates [17th August, 2015] - Article updated to use Mono 4.0.3, ASP.NET 5 beta-6 and libuv-v1.7.0.

Request to come up with suggestion, improvements, questions, critics or throw eggs, will appreciate it except for eggs (comments below).

Happy coding !!