I am interested in rewriting some personal websites using ASP.NET MVC because that is the technology I’m most comfortable using at the moment. Those sites are written in PHP and are hosted on a shared Linux hosting.

After I heard about the open sourced ASP.NET 5 and various recent advancements done in the field of running .NET code on Linux, I felt like it’s a good time to do some research. Because I feel that using Azure or some other Windows hosting is too overkill for the websites I have in mind.

So, let’s see what we need for hosting an ASP.NET 5 MVC site on Linux:

Setting up an Ubuntu VPS

I like DigitalOcean very much for their clutter-free and minimalistic experience and good performance/price ratio. If you look around the web or ask friends who may work with something like it, you may find some discount vouchers. The VPS-es they create are called “droplets”. The cheapest one is 5$ / month and offers you (at the moment) 512 MB RAM and 20GB SSD disk. For a lightweight Linux server used for prototyping, this is very good and I was quite happy with the VPS’s responsiveness. Also, the Linux distributions on the droplets are pre-configured to use the best mirrors for downloading packages and indeed they are downloaded very quickly.

I chose the Ubuntu 14.04 distribution for creating a new droplet.

Setting SSH access

Remote access to your VPS is nice and all, but security is a very big issue. There are a lot of bots / people on the web probing servers for remote access and weak SSH setups can be easily broken.

There is good info about SSH access in this AskUbuntu question page: http://askubuntu.com/questions/51925/how-do-i-configure-a-new-ubuntu-installation-to-accept-ssh-connections

If you are using DigitalOcean, you need to run these commands for setting up SSH from the in-browser console.

After you have set up your SSH server, you can use the PuTTY application on Windows. Enter your VPS IP for the “Host name” and the appropriate port (if you changed it from the default), then click “Open”. Credentials for logging in will be later asked by the remote VPS inside the console.

Setting up a .NET runtime

“Classic” Mono way (for ASP.NET < 5)

A few times in the past I’ve tried Mono and Mono Develop on Ubuntu, but just on the “Hello, world” level. I never got too much in detail. So, for a time now, a good part of code written for .NET has been working on Ubuntu, on top of the Mono framework. Including ASP.NET websites. But again, I didn’t attempt to create a web app on Mono. I was looking for a workflow on which I could write and test the app using Visual Studio on Windows (while making sure I’m not using things not available on Mono) and somehow deploy it to the Ubuntu server. That seemed quite time consuming to set up and I didn’t do it.

Install AspNet 5 directly

The following instructions are based on the ones at https://github.com/aspnet/Home/blob/dev/GettingStartedDeb.md with improvements and fixes for issues I encountered. I used Ubuntu Server 14.04.

! When you have the choice, choose to install the same beta version for each component, to have a bigger chance of things going together smoothly. At the moment of my writing, the best choice was choosing “beta-6” where possible, and not “latest”.

Get Mono

Mono is still required. Let’s install it.

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

Get and build libuv

The new web server for ASP.NET 5 (kestrel) requires this library.

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

! There’s a good chance that later on kestrel will not properly detect libuv. The command below made my kestrel detect libuv.

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

Get DNVM (.NET SDK version manager)

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

At this point, you can verify that dnvm installed correctly. To do that, just run:

dnvm

Add package sources to NuGet.Config

ASP.NET 5 is more heavily based on NuGet. Everything has been made more granular and thus in order to have a working ASP.NET 5 runtime, required packages would need to be downloaded from some NuGet sources. These sources include the traditional nuget.org and also the AspNetVNext section on myget.org.

But first we need to feed some sources to NuGet. There’s a good chance that NuGet has some default sources already configured, but we may need to tweak them a bit.

nano ~/.config/NuGet/NuGet.Config

… add the following text and save…

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <packageSources>
 <!--<add key="AspNetVNext" value="https://www.myget.org/F/aspnetvnext/api/v2/" />-->
 <add key="AspNetVNext" value="https://www.myget.org/F/aspnetlitedev/api/v2/" />
 <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
 </packageSources>
</configuration>


! I’ve commented out the first source (that was officially recommended) because I had issues with it later (some packages depending on Roslyn were not found) Instead, I am using the “aspnetlitedev” source.

Still, you may have issues with package sources. Be aware that web apps can have their own NuGet.Config which can override the source for asp vnext packages. They can revert to aspnetvnext which currently doesn’t work!
Solution: update project-level NuGet.Config with aspnetlitedev or remove the file completely.

Also, DNVM has its own package source settings for Stable and Unstable which can be overriden. I am not sure that overriding them is required. But if you have issues with restoring packages later on, you can also try to override the Unstable package source for DNVM:

export DNX_UNSTABLE_FEED=https://www.myget.org/F/aspnetlitedev/api/v2/

Upgrade the DNVM

Do this because the more recent version of DNVM has some references that are required.

dnvm upgrade -u

Optional – view installed .NET SDK-s and which one is active. You may need to install other SDK versions and mark them as active if something doesn’t work for you. This is the main issue with trying ASP 5 now, after all. Software is changing rapidly during this beta stage and many components need to go together well. From my experience, at this moment you should choose version beta-6 for any component that has such choice. If you choose “latest” for any of them, you may run into an issue, even though many online guides point you to retrieve code/packages from a folder/branch named “latest”. That’s because this very recent code may have some issues working together with slightly older components.

So, to view installed .NET SDK-s, you can run the following command.

dnvm list

Fix for NuGet restore process

! I needed to set the variable below for Mono to properly run HTTP connections for NuGet package restore. Otherwise, I had numerous HTTP timeout messages and quite some HTTP failures, as well. More info about this issue:
http://stackoverflow.com/questions/31973803/dnu-restore-gives-lots-of-http-request-timed-out

export MONO_THREADS_PER_CPU=2000

Now you’re ready to deploy a web app to the server. But we’ll take care of that in a separate section. Next, we’ll go a bit through yet another method to get ASP.NET 5 running on your Ubuntu VPS.

Other useful / interesting resources

GitHub Asp.Net Home: https://github.com/aspnet/home
Instructions from .NET foundation to install DNVM with CoreCLR to run Console applications: http://dotnet.github.io/core/getting-started/

Running ASP.NET 5 inside Docker

One other nice choice is to use Docker. It helps you “modularize” your server a little bit and have the .NET related concerns separated from your OS. Also, the deployment process is more automated, as different plugins and inter-connectivity apps exist that help you remotely manage Docker.

But still, I had to get through some trial and error with Docker, even while following the MSDN guide: http://blogs.msdn.com/b/webdev/archive/2015/01/14/running-asp-net-5-applications-in-linux-containers-with-docker.aspx

Install Docker

DigitalOcean provides Ubuntu + Docker VPS images for creating your VPS/droplet, so you can directly start with that, or you can install Docker manually on an Ubuntu VPS:
https://docs.docker.com/installation/ubuntulinux/

Initialize image and container for asp.net

Initializing Docker for the sample aspnet-Home project will also make Docker install the official aspnet image, which is marked as a dependency and inherited from.
So, we start with the web application source files (which include a Dockerfile), then let Docker do its job.

Make sure that you get the sample that corresponds to what DNVM runtime is active inside the Docker image / container. By now, it is beta6. (I tried using both latest sample and latest DNVM, but they kind of break in Docker, so let’s fallback to beta6, which works).

cd ~
git clone https://github.com/aspnet/Home.git aspnet-Home
cd aspnet-Home/samples/1.0.0-beta6/HelloWeb

This location should already have a Dockerfile file. Docker looks for it when running the build command. 

The “app-name” part must match [a-z0-9]+(?:[._-][a-z0-9]+)*
Seemingly no uppercase characters.

docker build -t app-name .

Now docker should do a lot of stuff that takes several minutes to complete. Mostly because it restores lots of packages from nuget.org, which is slow.

Troubles building the Docker image?

There may be some troubles along the way when building the Docker image. I went through each of them and fixed them when installing DNX directly. If issues appear with Docker, it’s more tricky to fix them, because it has its setting files and apps sandboxed inside the Docker images. Especially nasty is the problem with Mono failing some HTTP connections on NuGet package restore,

For troubleshooting, it is good to know that Docker runs Linux processes sandboxed in “containers”. These containers have a default shell that you can attach to, or you can even launch new shells that run inside the sandbox. That way, you have access to the container’s processes and files. But you should bear in mind that Docker containers are in fact instances of Docker images and when you spawn a new container from an installed image, it would not have the changes that you previously made in the previous container. Not by default, at least. However, you can commit your changes done to a container by running a Docker command (named commit).

Attach shell to Docker containers

Attach to default shell:

sudo docker attach containerId | containerName

or (to allow multiple instances of the shell):

sudo docker exec -i -t containerId | containerName bash

! After attaching to the Docker container’s shell for troubleshooting, you can try running some of the commands from the previous section, that apply to a direct ASP.NET 5 installation.

Run the Docker container

Note that the “80:5004” argument below means that TCP port 80 open inside the sandbox (guest) should map to a 5004 TCP port open on the host. So, the web app will listen to port 80 by configuration, which Docker then maps to port 5004 on the host machine. In the end, you can access your app at hostname:5004.

docker run -t -d -p 80:5004 myapp

Other resources

Asp.Net Docker image source on GitHub: https://github.com/aspnet/aspnet-docker

Deploying an application

On plain ASP.NET 5 (no Docker)

Well, this is not really deployment, but it’s a way to get a web app running:

Get a web application project

git clone git@github.com:aspnet/Home.git aspnet-home
cd aspnet-home/samples/1.0.0-beta6/HelloWeb

Restore NuGet dependencies for the project

This command just fetches packages which are not already downloaded (cached locally).

dnu restore

or

Use –no-cache if you want to fetch anew all required packages from NuGet sources.

dnu restore --no-cache

Run the server

dnx kestrel

! Note: the syntax for this command varies from one beta version of DNX to another. Some DNX versions need a reference to the folder, like “dnx . kestrel”

! Second Note: This command runs the server directly and blocks the console.

The web application should now be accessible at http://machine:5004

To see the actual IP & port that are used, take a look at project.json inside the app’s folder:

cat project.json

Deploying with Docker

You first need to make your Docker accessible from the outside. But this can be very dangerous if not properly secured. Otherwise, anybody could send commands to your Docker images, just by using the Docker API.

Docker security setup

There is an article about securing your Docker deployment in Docker’s documentation: https://docs.docker.com/articles/https/

The following are excerpts from the article, with some additional comments. You can follow the excerpts for a quick setup. This commands need to be run on the host machine running Docker.

openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr
echo subjectAltName = IP:10.10.10.20,IP:127.0.0.1 > extfile.cnf
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
 -CAcreateserial -out server-cert.pem -extfile extfile.cnf

openssl genrsa -out key.pem 4096

openssl req -subj '/CN=client' -new -key key.pem -out client.csr

echo extendedKeyUsage = clientAuth > extfile.cnf

openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
 -CAcreateserial -out cert.pem -extfile extfile.cnf

Clean files up and increase security

rm -v client.csr server.csr
chmod -v 0400 ca-key.pem key.pem server-key.pem
chmod -v 0444 ca.pem server-cert.pem cert.pem

Make Docker commands on the VPS always use the TLS connection.

Copy the above pem files to a “.docker” folder in the user profile and set some env variables.

mkdir -pv ~/.docker
cp -v {ca,cert,key}.pem ~/.docker
export DOCKER_HOST=tcp://$HOST:2376 DOCKER_TLS_VERIFY=1

Start the Docker daemon with TLS enabled

First make sure that no other Docker daemon is already running.

docker daemon --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem \
 -H=0.0.0.0:2376

Note: The default Docker daemon startup command is: /usr/bin/docker daemon -H fd:// This command uses the default Unix socket as reference for the “H” (host listening interface) parameter.

Test connection to the Docker daemon for remote management

Run this command to run a Docker client which checks the Docker server’s version. You can run this from the Docker host or from another host, remotely. The command syntax should be the same both on Linux and Windows. Be sure to replace the $HOST variable with your Docker server’s host.

docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem \
 -H=$HOST:2376 version

Set default Docker startup options on the server

These commands apply to Ubuntu < 15:

Edit the default Docker settings file

sudo nano /etc/default/docker

Add (or edit) this entry:

DOCKER_OPTS="--tlsverify --tlscacert=/userdir/.dockerd/ca.pem --tlscert=/userdir/.dockerd/server-cert.pem --tlskey=/userdir/.dockerd/server-key.pem -H 0.0.0.0:2376"

As you can see, references to pem files should use the full path to them. Replace userdir with the appropriate value.

If Docker daemon is running using the above initialization parameters, commands you send to Docker from inside the server itself need to know to which socket to be directed. So you will need to add the “-H” parameter to them. You will also need to use “–tlsVerify” to conform to the daemon’s use of TLS.

Instead of sending “–tlsVerify” and “-H” with each such command, which is very tedious, you can set the following environment variables:

export DOCKER_HOST=tcp://127.0.0.1:2376 DOCKER_TLS_VERIFY=1

Afterwards, Docker commands will automatically use these parameters by reading them from the environment.

You can persist them between system restarts, by putting them inside the “environment” file:

sudo nano /etc/environment
DOCKER_HOST=tcp://127.0.0.1:2376
DOCKER_TLS_VERIFY=1

Docker client setup on Windows

Installation is very straightforward if you are using Chocolatey:

choco install docker

Note: For more information about installing Docker on Windows, see: https://docs.docker.com/installation/windows/

docker --tlsverify -H tcp://yourhost:2376 info

Install Docker tools for Visual Studio 2015

These tools are in the preview stage at the moment and it looks like they are only officially available for Visual Studio 2015, although I may be wrong. If you are interested in developing for ASP.NET 5, then maybe you are going to use VS 2015 anyway, which offers support for them out of the box.

Download the tools from:  https://visualstudiogallery.msdn.microsoft.com/0f5b2caa-ea00-41c8-b8a2-058c7da0b3e4?SRC=Featured

Some more information:  https://azure.microsoft.com/en-us/documentation/articles/vs-azure-tools-docker-hosting-web-apps-in-docker/

Troubleshooting errors with Docker: publishing: https://msdn.microsoft.com/library/azure/mt125442.aspx

After installing the Docker tools, you can get default Dockerfiles from: C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\Windows Azure Tools\Docker

Publish web app from Visual Studio 2015 to Docker

You can publish web app projects built with ASP.NET 5 from Visual Studio by choosing Docker as Publish target, then choose to fill in details for custom docker server.

Note that during publishing, built project is stored temporarily at: C:\Users\username\AppData\Local\Temp\PublishTemp

Epilogue

As you can see, getting things setup required a lot of mingling. I did a lot of trial and error and spent quite a few nights with this. Luckily, I managed to document my steps so the existence of this article was made possible.

Things are still quite shaky and I feel that I need to experiment a lot more to get more accustomed to them.

Hopefully, by the time ASP.NET 5 has a final release, setting up will have less hurdles and definitive official guides should make things easier and clearer.

My attempts to rewrite the before mentioned websites have come to a halt when getting to the point of choosing a DB and a DB client implementation. I was hoping for a lightweight DB and a nice API from within ASP.NET v5.

Sqlite with EF would have been ideal, but I needed to use EF 7 with ASP.NET v5, which did not have effective support for Sqlite save for some workarounds, at the time I tried those things.

Meanwhile I decided it’s best to wait for ASP.NET v5 and EF 7 to come to a stable release.

Happy coding and deploying with ASP.NET 5 and Linux!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.