diff --git a/browserid/app.js b/browserid/app.js
index c646a2bc75950cc45829ca212c92ed6eb5831459..e3fc71968311e34b1701a466ecb18b9baa729254 100644
--- a/browserid/app.js
+++ b/browserid/app.js
@@ -14,48 +14,49 @@ const         url = require('url'),
           secrets = require('./lib/secrets.js'),
                db = require('./lib/db.js');
 
-const STATIC_DIR = path.join(path.dirname(__dirname), "static");
+// looks unused, see run.js
+// const STATIC_DIR = path.join(path.dirname(__dirname), "static");
 
 const COOKIE_SECRET = secrets.hydrateSecret('cookie_secret', VAR_DIR);
 
 const COOKIE_KEY = 'browserid_state';
 
-function handler(request, response, next) {
-  // dispatch!
-  var urlpath = url.parse(request.url).pathname;
+function internal_redirector(new_url) {
+  return function(req, resp, next) {
+    req.url = new_url;
+    return next();
+  };
+}
 
-  if (urlpath === '/sign_in') {
-    // a little remapping!
-    request.url = "/dialog/index.html";
-    next();
-  } else if (urlpath === '/register_iframe') {
-    request.url = "/dialog/register_iframe.html";
-    next();
-  } else if (/^\/wsapi\/\w+$/.test(urlpath)) {
-    try {
-      var method = path.basename(urlpath);
-      wsapi[method](request, response);
-    } catch(e) {
-      var errMsg = "oops, error executing wsapi method: " + method + " (" + e.toString() +")";
-      console.log(errMsg);
-      httputils.fourOhFour(response, errMsg);
-    }
-  } else if (/^\/users\/[^\/]+.xml$/.test(urlpath)) {
-    var identity = path.basename(urlpath).replace(/.xml$/, '').replace(/^acct:/, '');
-
-    webfinger.renderUserPage(identity, function (resultDocument) {
-      if (resultDocument === undefined) {
-        httputils.fourOhFour(response, "I don't know anything about: " + identity + "\n");
-      } else {
-        httputils.xmlResponse(response, resultDocument);
+function router(app) {
+  // simple redirects (internal for now)
+  app.get('/sign_in', internal_redirector('/dialog/index.html'));
+  app.get('/register_iframe', internal_redirector('/dialog/register_iframe.html'));
+
+  app.all('/wsapi/:method', function(req, resp, next) {
+      try {
+        wsapi[req.params.method](req, resp);
+      } catch (e) {
+        var errMsg = "oops, error executing wsapi method: " + method + " (" + e.toString() +")";
+        console.log(errMsg);
+        httputils.fourOhFour(response, errMsg);
       }
     });
-  } else if (urlpath === "/code_update") {
-    console.log("code updated.  shutting down.");
-    process.exit();
-  } else {
-    next();
-  }
+
+  app.get('/users/acct\::identity.xml', function(req, resp, next) {
+      webfinger.renderUserPage(req.params.identity, function (resultDocument) {
+          if (resultDocument === undefined) {
+            httputils.fourOhFour(resp, "I don't know anything about: " + req.params.identity + "\n");
+          } else {
+            httputils.xmlResponse(resp, resultDocument);
+          }
+        });
+    });
+
+  app.get('/code_update', function(req, resp, next) {
+      console.log("code updated.  shutting down.");
+      process.exit();
+    });
 };
 
 exports.varDir = VAR_DIR;
@@ -79,7 +80,8 @@ exports.setup = function(server) {
     }
   });
 
-  server.use(handler);
+  // add the methods
+  router(server);
 
   // a tweak to get the content type of host-meta correct
   server.use(function(req, resp, next) {
diff --git a/run.js b/run.js
index ff7ed63abaf4f4f0f3d83134d6b557f304ce69a8..24fdd5908e5ccd99b4622769b67fb72c3d9347d6 100755
--- a/run.js
+++ b/run.js
@@ -166,6 +166,8 @@ function formatLink(server, extraPath) {
 }
 
 console.log("Running test servers:");
+
+var port_num=10000;
 dirs.forEach(function(dirObj) {
   if (!fs.statSync(dirObj.path).isDirectory()) return;
   // does this server have a js handler for custom request handling?
@@ -185,7 +187,7 @@ dirs.forEach(function(dirObj) {
   var so = {
     path: dirObj.path,
     server: undefined,
-    port: "0",
+    port: port_num++,
     name: dirObj.name,
     handler: runJS.handler,
     setup: runJS.setup,