As a web developer, I tend to have a lot of projects just hanging around on my hard drive, waiting for me to pay attention to them. And one of the things that becomes onerous over time, especially if you're like me and a bit undisciplined about the whole folders, projects, and so on thing of keeping stuff in the right places, is keeping track of where all of them are.

Most of my projects are individual web emplacements: wordpress designs, or extensions of the narrator software package I wrote and have been using to deploy my stories since 1994 or so. (It's been through three languages in that time-- started as Perl, was re-written as Python, briefly converted to Ruby, and now is back to Python again.) But how to keep track of them all?

I decided to experiment with Nginx, a popular and powerful reverse proxy engine. A reverse proxy accepts connections from the outside world as if it were your head webserver, and then forwards those requests to the appropriate server. Nginx (pronounced "Engine X") is also capable of acting as a high-performance webserver in its own right, so it can serve media files out, and it uses a PCRE engine with variable substitution and a limited conditional language allowing you to make content delivery decisions based on header information long before you invoke the machinery of a heavy back-end like PHP, Django, or Rails.

I would call the experiment a modest success. My idea is eventually to have the ElfSternberg.com website front-ended with nginx and running a number of different back-ends, such as the wordpress install with Apache, other dynamic content via Django or Rails, and static content via Nginx itself.

One thing I did after installing Nginx on my dev box was to write a little CGI script that looked at the configuration file and generated a local index of projects. My Nginx configuration file is reasonably regular, and looks like this with one proxy_pass command per line for the location section:

location ~ /projects/so2006/(.*) { proxy_pass http://127.0.0.1:8001/$1; break; }  # Steppin' Out to Stop Domestic Violence
location ~ /projects/pw2007/(.*) { proxy_pass http://127.0.0.1:8002/$1; break; }  # Pendorwright 2007
location ~ /projects/kk2006/(.*) { proxy_pass http://127.0.0.1:8004/$1; break; }  # Karen Keiser 2006
location ~ /projects/sp2006/(.*) { proxy_pass http://127.0.0.1:8005/$1; break; }  # Sound Podcast Production & Consulting
location ~ /projects/ssb2007/(.*) { proxy_pass http://127.0.0.1:8006/$1; break; } # Shay Schual-Berke 2006
location / { proxy_pass http://127.0.0.1:81; } # Home

This makes writing a script to spew out all of my projects in a nice, clean table a trivial job of parsing the configuration.  As a benefit, it also analyzes the output of netstat and determines whether or not or or more servers Nginx is expecting to proxy might be down. Decorating the table with something from the Open Source Web Design project is left as an exercise.

#!/bin/env python
import re
import sys
from subprocess import Popen, PIPE

re_match = re.compile(r'^\s+location \~ (.*?)\s*\{.*http://([^\:]+)\:(\d+)/.*#([^#]+)$')
loc = open('/etc/nginx/nginx.conf')

ns_match = re.compile(r'^tcp\s+\d+\s+\d+\s+(0.0.0.0|127.0.0.1):(\d+)')
output = Popen(["netstat", "-an", "--protocol=inet"], stdout=PIPE).communicate()[0]
ports = []
for proc in output.split('\n'):
        g = ns_match.match(proc)
        if not g: continue
        ports.append(int(g.group(2)))

projects = []
for line in loc:
        g = re_match.match(line)
        if not g: continue
        (loc, site, port, proj) = g.group(1, 2, 3, 4)
        loc = loc.replace('(.*)', '')
        proj = proj.strip()
        projects.append((proj, loc, site, port, bool(int(port) in ports)))

print "Content-Type: text/html\r\n\r\n"
print "<html><body><table>"
for i in projects:
        print ('<tr><td><a href="%s">%s</a></td><td>'
               '<a href="http://%s:%s">Direct link</a></td><td>%s</td></tr>') % (
                i[1], i[0], i[2], i[3],
                (i[4] and '<span style="color: green">Up</span>'
                 or '<span style="color: red">Down</span>'))
print "</table></body></html>"