Over the last few days I have been setting up a new build/web server. I’m replacing the Windows 2003 dedicated server I have been using for the past few years. I was initially going to go with another windows server - it was noticing the new Windows based Rackspace cloud servers that got me started looking at options - but since I’m running quite a few open source components and I don’t need to worry about setup fees, I decided to try a linux server.

1. The starting point

My starting point for this install is a new Rackspace cloud server running Ubuntu 9.10. I have installed MySQL, Apache, Rails and PHP, using the instructions on http://cloudservers.rackspacecloud.com/. I moved the apache default site from /var/www to /var/www/default in order to handle virtual hosts better.

For editing config files I am using nano:

nano [filename]

2. Subversion

The first component to install is a subversion server and something to manage it with. I used Jose Prado’s instructions (Roll your own Subversion server) to set up svn and Warehouse with a couple of changes to suit use with Ubuntu and Apache.

Installing:

aptitude install subversion
mkdir /var/svn/repositories
svnadmin create /var/svn/repositories/test1`

To get automatic startup:

Edit /etc/init.d/subversion:

#!/bin/sh
#
# start/stop subversion daemon.

test -f /usr/bin/svnserve || exit 0

OPTIONS="-d -r /var/svn/repositories"

case $1 in

start)

echo -n "Starting subversion daemon:"

echo -n " svnserve"

start-stop-daemon --start --quiet --oknodo --user root --exec /usr/bin/svnserve$

echo "."

;;

stop)

echo -n "Stopping subversion daemon:"

echo -n " svnserve"

start-stop-daemon --stop --quiet --oknodo --exec /usr/bin/svnserve

echo "."

;;

reload)

;;

force-reload)

$0 restart

;;

restart)

$0 stop

$0 start

;;

*)

echo "Usage: /etc/init.d/subversion {start|stop|reload|restart}"

exit 1

;;

esac

exit 0

Now allow the file to run as a script and set it up to be called on system startup/shutdown:

chmod +x /etc/init.d/subversion

update-rc.d subversion defaults

To start svnserve manually, use

/etc/init.d/subversion start

3. Mono

My first attempt at installing Mono didn’t go well. The official package is Mono 2.4, and includes a bug in xbuild that makes it incompatible with TeamCity.

To get mono 2.6 you will need to download the source and build it. Fortunately that’s not quite as scary as it sounds thanks to a script from Patrick McEvoy (Install Mono 2.6.x parallel environment on Ubuntu 9.10).

I did need to make a couple of modifications to the script - the version below isn’t quite the same as the one on Patrick’s site. In particular, I had to stop it from excluding mod_mono with the output “Skipping mono-tools”.

code removed - a better version is available on github

Once this finishes running (it takes a while) you need to tell the system to use the new version. Since it is installed parallel rather than replacing the default version, the system doesn’t know where to find it.

export PATH=/opt/mono-2.6/bin:$PATH
export PKG_CONFIG_PATH=/opt/mono-2.6/lib/pkgconfig

Setting PATH will get you the right version when you run any of the mono commands from the shell. pkg-config is used by TeamCity to detect the version and location of Mono to use. You can check that it worked using

pkg-config --modversion mono

If it returns “2.4” or can’t find the package, something went wrong.

The next step is to test that ASP.NET is working. Create a simple ASP.NET MVC app, build it, and copy it to /var/www/MVCTest1.

First test it with XSP, which is a standalone server for development use:

cd /var/www/MVCTest1
xsp

Go to http://servername:8080/ and you should see your app working. At this point the default mono package would give an error finding System.Web.MVC.

If that worked, it’s time to set up Apache with mod_mono.

Edit /etc/apache2/sites-available/mvctest1:

<VirtualHost *:80>
ServerName  mvctest1.orangeguava.com
ServerAlias www.mvctest1.orangeguava.com
DocumentRoot /var/www/MVCTest1
DirectoryIndex index.html index.aspx

MonoDocumentRootDir "/var/www/MVCTest1"

MonoServerPath mvctest1 "/opt/mono-2.6/bin/mod-mono-server2"

MonoApplications mvctest1 "/:/var/www/MVCTest1"

<Directory /var/www/MVCTest1>

MonoSetServerAlias mvctest1

SetHandler mono

AddHandler mod_mono .aspx .ascx .asax .ashx .config .cs .asmx

allow from all

</Directory>

</VirtualHost>

Enable mono and the new site:

a2enmod mod_mono
a2ensite mvctest1
/etc/init.d/apache2 restart

You should now have an ASP.NET MVC application running through Apache on port 80.

4. TeamCity

The last component to install is TeamCity.

TeamCity includes a Tomcat web server, but not Java, so you need to install java first:

aptitude install default-jre
export JAVA_HOME=/usr/lib/jvm/default-java
export PATH=$PATH:$JAVA_HOME/bin

Download TeamCity and extract it to /var/TeamCity.

Enable TeamCity to connect to Apache by editing /var/TeamCity/conf/server.xml and uncommenting the line

<Connector port="8109" protocol="AJP/1.3" redirectPort="8543" />

Create an Apache virtual host for TeamCity. Edit /etc/apache2/sites-available/teamcity:

<VirtualHost *:80></code>

ServerName  teamcity.orangeguava.com

<Proxy *>

AddDefaultCharset Off

Order deny,allow

Allow from all

</Proxy>

ProxyPass / ajp://localhost:8109/

ProxyPassReverse / ajp://localhost:8109/

</VirtualHost>

Enable mod_proxy_ajp and the new site:

a2enmod proxy_ajp
a2ensite teamcity

Since the apache site is a proxy and only works when the TeamCity Tomcat server is running, we need to set up startup scripts. Edit /etc/init.d/teamcity:

#!/bin/sh
#
# /etc/init.d/teamcity -  startup script for teamcity</code>

export JAVA_HOME=/usr/lib/jvm/default-java

export PATH=/opt/mono-2.6/bin:$PATH:$JAVA_HOME/bin

export PKG_CONFIG_PATH=/opt/mono-2.6/lib/pkgconfig

case $1 in

start)

/var/TeamCity/bin/runAll.sh start
;;

stop)

/var/TeamCity/bin/runAll.sh stop

;;

esac

exit 0

Install the init script:

chmod +x /etc/init.d/teamcity
update-rc.d teamcity defaults`

Start TeamCity manually with:

/etc/init.d/teamcity start

At this point, TeamCity should be available on both ports 8111 and 80, and configuration is much the same as it is on Windows.

If you decide to block port remote access to port 8111, you will need to update the server url setting in the server configuration setting of the TeamCity webapp.

To be compatible with the build agent, you need to set the build configuration to MSBuild/Mono xbuild/x64.

If you get the error

MSBUILD0005: Property name and value expected as /p:<prop name>=<prop value>

TeamCity is using the wrong version of Mono.

TeamCity works with its own embedded database, but recommends connecting to a real database.

Install the MySQL JDBC driver

aptitude install libmysql-java

Make the driver available to TeamCity

ln -s /usr/share/java/mysql-connector-java.jar /var/TeamCity/webapps/ROOT/WEB-INF/lib/mysql-connector-java.jar

Create a database and user in MySQL:

create database teamcity;

CREATE USER 'teamcity'@'localhost' IDENTIFIED BY 'password';

GRANT ALL ON teamcity.* TO teamcity@localhost;

Create a TeamCity database config file

cp ~/.BuildServer/config/database.mysql.properties.dist ~/.BuildServer/config/database.properties

Edit ~/.BuildServer/config/database.properties:

driverName=com.mysql.jdbc.Driver
connectionUrl=jdbc:mysql://localhost/teamcity
connectionProperties.user=teamcity
connectionProperties.password=password`

Restart TeamCity and it should be using the MySQL database.