In my day job, I work as an infrastructure developer for a small company. While I wouldn’t call us a Microsoft shop by any stretch (we actually make web design tools), we do maintain a large code base in C#, which includes our website and a number of web-based administrative tools. In planning for a future project, I recently spent some time figuring out how to host our existing ASP.NET-based web site on a Linux server. After a great deal of research, and just a bit of trial and error, I came up with the following steps:
The server is going to run in a virtual machine, primarily because I don’t have any available hardware to throw at the problem right now. This has the added benefit of being easily expandable, and our web hosting company will actually accept *.vdi files, which allows us to easily pick up the finished machine and put it live with no added hassle. In our case, the host machine was a Windows Server 2008 machine, but these steps would work just as well on a Linux host.
I started off with VirtualBox 3.2.10 r66523, although like I said, grabbing the OSE edition from your repositories will work just as well. The host machine that we’re using is a bit underpowered, so I only gave the virtual machine 512MB of RAM and 10GB of dynamically expanding storage. One important thing – because I’ll want this server to live on our LAN and interact with our other machines, I was careful to change the network card settings to Bridged Adapter and to make sure that the Ethernet adapter of the host machine is selected in the hardware drop down. This is important because we want the virtual machine to ask our office router for an IP address instead of using the host machine as a private subnet.
Installing the Operating System:
For the initial install, I went with the Ubuntu 10.10 Maverick Meerkat 32-bit Desktop Edition. Any server admins reading this will probably pull out their hair over the fact, but in our office, we have administrators who are very used to using Windows’ Remote Desktop utility to log into remote machines, and I don’t feel like training everybody on the intricacies of PuTTy and SSH. If you want to, you can install the Server version instead, and forgo all of the additional overhead of a windowing system on your server. Since all of my installation was done from the terminal, these instructions will work just as well with or without a GUI.
From VirtualBox, you’ll want to mount the Ubuntu ISO in the IDE CD-ROM drive, and start the machine. When prompted, click your way through Ubuntu’s slick new installer, and tell it to erase and use entire disk, since we don’t need any fancy partitioning for this setup. When I went through these steps, I opted to encrypt the home folder of the vm, mostly out of habit, but that’s up to you. Once you make it to a desktop, install VirtualBox Guest Additions.
From Terminal, type sudo apt-get upgrade to apply any patches that might be available.
Setting up a Static IP Address:
From a terminal, type ifconfig and find the HWaddr entry for your ethernet card, usually eth0. It will probably look something like 08:00:27:1c:17:6c. Next, you’ll need to log in to your router and set it up so that any device with this hardware address (also called a MAC address) is always given the same IP address. In my case, I chose to assign the virtual server an IP address of 192.168.1.10 because it was easy to remember. There are other ways that you can go about setting up a static IP, but I find this to be the easiest.
Getting Remote Desktop support up and running:
As I mentioned above, the guys in our office are used to administering remote machines by logging in via Windows’ remote desktop client. In order to provide this functionality, I chose to set up the xrdp project on my little server. Installing this is as easy as typing sudo apt-get install xrdp in your terminal. The installation process will also require the vnc4server and xbase-clients packages.
When the installation has completed, the xrdp service will run on startup and will provide an encrypted remote desktop server that runs on port 3389. From Windows, you can now connect to 192.168.1.10 with the standard rdp client. When prompted for login, make sure that sesman-Xvnc is selected as the protocol, and you should be able to log in with the username and password combination that you chose above.
Installing a Graphical Firewall Utility:
Ubuntu ships with a firewall baked into the kernel that can be accessed from the terminal with the ufw
tool. Because some of our administrators are afraid of the command line, I also chose to install a graphical firewall manager
. In the terminal, type sudo apt-get install gufw
to install an easy to use gui for the firewall. Once complete, it will show up in the standard Gnome menu system under System > Administration > Firewall Configuration.
Let’s do a bit of setup. Open up the Firewall Configuration utility, and check off the box to enable the firewall. Below that box, make sure that all incoming traffic is automatically denied while all outgoing is allowed. These rules can be tightened up later, but are a good starting point for now. To allow incoming remote desktop connections, you’ll need to create a new rule to allow all TCP connections on port 3389. If this server is to be used on the live Internet, you may also consider limiting the IP addresses that these connections can come from so that not just anybody can log in to your server. Remember, defense in depth is your best friend.
Adding SSH Support:
Unlike my coworkers, I prefer to manage my server machines via command line. As such, an SSH server is necessary. Later, the SSH connection can be used for SFTP or a secure tunnel over which we can communicate with our source control and database servers. In terminal, type sudo apt-get install openssh-server to start the OpenSSH installation process. Once it’s done, you’ll want to back up its default configuration file with the command cp /etc/ssh/sshd_config /etc/ssh/sshd_config_old. Next, open up the config file your text editor of choice (mine is nano) and change a couple of the default options:
- Change the Port to 5000, or some other easy to remember port. Running an SSH server on port 22 can lead to high discoverability, and is regarded by some as a security no-no.
- Change PermitRootLogin to no. This will ensure that only normal user accounts can log in.
- At the end of the file, add the line AllowUsers <your-username> to limit the user accounts that can log in to the machine. It is good practice to create a user account with limited privileges and only allow it to log in via SSH. This way, if an attacker does get in, they are limited in the amount of damage that they can do.
Back in your terminal, type sudo /etc/init.d/ssh restart to load the new settings. Using the instructions above, open up your firewall utility and create a new rule to allow all TCP connections on port 5000. Once again, if this server is to be used on the live Internet, it’s a good idea to limit the IP addresses that this traffic can originate from.
With this done, you can log in to the server from any other Linux-based machine using the ssh command in your terminal. From Windows, you’ll need a third-party utility like PuTTy.
Installing Apache and ModMono:
For simplicity’s sake, we’ll install both Apache (the web server) and mod_mono (a module responsible for processing ASP.NET requests) from Ubuntu’s repositories. The downside is that the code base is a bit older, but the upside is that everything should just work, and the code is stable. These instructions are a modified version of the ones found on the HBY Consultancy blog. Credit where credit is due, after all. From your terminal, enter the following:
$ sudo apt-get install monodevelop mono-devel monodevelop-database mono-debugger mono-xsp2 libapache2-mod-mono mono-apache-server2 apache2
$ sudo a2dismod mod_mono
$ sudo a2enmod mod_mono_auto
With this done, Apache and mod_mono are installed. WE’ll need to do a bit of configuration before they’re ready to go. Open up mod_mono’s configuration file in your text editor of choice with something like sudo nano /etc/apache2/mods-available/mod_mono_auto.conf. Scroll down to the bottom and append the following text to the file:
MonoPath default “/usr/lib/mono/3.5”
MonoServerPath default /usr/bin/mod-mono-server2
AddMonoApplications default “/:/var/www”
Finally, restart the Apache web server so that the changes take effect with the command sudo /etc/init.d/apache2 restart. This configuration will allow us to run aspx files out of our /var/www/ directory, just like html or php files that you may have seen hosted in the past.
Having a Beer:
That was a fair bit of work, but I think that it was worth it. If everything went well, you’ve now got a fully functional Apache web server that’s reasonably secure, and can run any ASP.NET code that you throw at it.
The one hiccup that I encountered with this setup was that Mono doesn’t yet have support for .NET’s Entity Framework, which is the object-relational mapping framework that we use as a part of our database stack on the application that we wanted to host. This means that if I want to host the existing code on Linux, I’ll have to modify it so that it uses a different database back end. Its kind of a pain, but not the end of the world, and certainly a situation that can be avoided if you’re coding up a website from scratch. You can read more about the status of Mono’s ASP.NET implementation on their website.
Hopefully this helped somebody. Let me know in the comments if there’s anything that isn’t quite clear or if you encounter any snags with the process.