nginx as a reverse-proxy to Apache+Sinatra

I was recently developing a Sinatra app that wanted to host from home — setting it up Heroku would have meant migrating from SQLite to Postgres, and I’m lazy. The problem was that I already happened to have an Apache server at home to serve some other content, specifically some calendars through the WebDAV module.

The solution I used was simple: instead of having Apache listening on port 80, I set up nginx to listen to port 80 and redirect to either Apache (set to listen on port 8080 instead) or Sinatra (port 9393) depending on the URL.

 

Nginx configuration was dead simple (after a few tries). The gist of it being these few lines:

location / {
    proxy_pass   http://127.0.0.1:8080/;
}
location /reorg {
    proxy_pass http://127.0.0.1:9393;
}

The configuration in its entirety is available here.

 

After setting up this solution, I realized Apache’s mod_proxy would have done the trick without the need for nginx. And that mod_rack (Phusion Passenger) could probably have eliminated the need for running a specific ruby process for Sinatra at all. Live and learn!

Startup Items: launch services at boot

This post is a follow-up on the setup of your own Apache web server (although the technique can be used to start about anything of course).

Unlike classical Linuces that stock programs to launch at boot in a /etc/init.d folder for example; OS X uses a mechanism called Startup Items. These items can be found in /Library/StartupItems/, ~/Library/StartupItems and /System/Library/StartupItems.

One particular strength of the Startup Items is that you can specify in which order to launch them.

Let’s say I’ll make a startup item called MyApache. I’ll start by create the folder:

mbp:~ florent$ sudo mkdir /Library/StartupItems/MyApache

This folder will contain at least two files: an executable script called MyApache, and a file called StartupParameters.plist.

The script will be called at startup and shutdown, and will look like this:

#!/bin/sh

## Apache Web Server ; custom install ##

. /etc/rc.common
StartService (){
    ConsoleMessage "Starting Apache"
    /usr/local/apache2/bin/launchctl start
}

StopService (){
    ConsoleMessage "Stopping Apache"
    /usr/local/apache2/bin/launchctl stop
}

RestartService (){
    ConsoleMessage "Restarting Apache"
    /usr/local/apache2/bin/launchctl restart
}

RunService "$1"

The StartupParameters.plist file will contain data about the information to launch. It’s an XML file that will look like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Description</key>
    <string>My own Apache webserver</string>
    <key>Messages</key>
    <dict>
        <key>start</key>
        <string>Starting my Apache</string>
        <key>stop</key>
        <string>Stopping my Apache</string>
    </dict>
    <key>Preference</key>
    <string>Late</string>
    <key>Provides</key>
    <array>
        <string>MyApache</string>
    </array>
    <key>Requires</key>
    <array>
        <string>Network</string>
    </array>
    <key>Uses</key>
    <array>
        <string>Disks</string>
    </array>
</dict>
</plist>

We can see that Apache Requires the networks to be up, and will use Disks.

Let’s imagine I want to launch my Apache after my Jabber server for some reason. I’ll just create a StartupItem called “Jabber”, the same way as we just did, then add the following line to MyApache’s StartupParameters.plist “Requires” section:

                <string>Jabber</string>

Now at startup, OS X will launch Jabber and wait until it’s up and running before launching Apache.

Compiling and installing Apache on Mac OS X

Update: instead of the completely manual method, I’d now recommend using the most excellent Homebrew. The “missing package manager for OS X” will automatically download and compile the latest version and verify the checksums, amongst other niceties. It’s awesome, and only gaining more momentum.

Original post:

As you may already know, Apple bundles a version of Apache into Mac OS X. This httpd can be started in System Preferences > Sharing > Web Sharing. Its configuration files are located in /etc/apache2/.

Unfortunately, given Apple’s habit of not releasing patches too often, OS X’s Apache might lag a few versions behind. For example, bundled version on Snow Leopard at the time I’m writing this is 2.2.13; while the latest version is 2.2.15. It contains some (small to medium-ish depending on your setup) security fixes.

Hence, here I’m going to speak about building and installing your own Apache on OS X.

First, let’s get our hands on the sources: download the latest version from the Apache Foundation. Save it somewhere and check the integrity of the archive using MD5:

mbp:~ florent$ md5 ~/Downloads/httpd-2.2.15.tar.bz2
MD5 (/Users/florent/Downloads/httpd-2.2.15.tar.bz2) = 016cec97337eccead2aad6a7c27f2e14

Or SHA1:

mbp:~ florent$ shasum ~/Downloads/httpd-2.2.15.tar.bz2
5f0e973839ed2e38a4d03adba109ef5ce3381bc2  /Users/florent/Downloads/httpd-2.2.15.tar.bz2

These computed hashes should match the values given on the Apache website1.

Now time to configure our httpd.

Untar the archive, `cd` into the installation folder, and:

mbp:httpd-2.2.15 florent $ ./configure --prefix=/my/path

Here, the prefix we choose is the folder where apache will be installed. By default, it is set to /usr/local/apache2.

Now we just have to build and install Apache:

mbp:httpd-2.2.15 florent$ make && sudo make install

All set!

You can use apachectl to start the newly installed server:

mbp:~ florent$ sudo /usr/local/apache2/bin/apachectl start

1. If they don’t, you have quite a big problem: try downloading the archive again. If still no match, you may be the victim of a Man in the Middle attack; but a sloppy one (if you’re being tricked into downloading a fake archive, the attacker should be able to send you fake hashes too). Or more probably an infected mirror. Or even more probably you’re not reading the right hashes on the Apache website. : )