Friday, April 11, 2014

IIS Reverse Proxy to multiple sites running under a single Node.js instance

Subtitled: How to setup Node.js to handle multiple sites and to run on Windows while IIS still occupies port 80


I did this on a Window 7 machine which was running IIS 7.5

 

Setting up your local box for testing

In your HOSTS file add some sites to test:
127.0.0.1     node1.com
127.0.0.1     node2.com
127.0.0.1     node3.com


IIS

Create a new web site in IIS:
Open IIS.
Right click on Sites.
"Add Web Site..."
Site Name: MyReverseProxy
Physical Path: C:\inetpub\wwwroot (can be anything as we're not going to use it)
Host name: node1.com
Now click on Bindings under Actions on RHS
Click Add.
Host name: node2.com
Click Add.
Host name: node3.com
Close.
You now have 3 host names running on port 80 on IIS and your HOSTS file will direct all local requests to this web site.

Click on MyReverseProxy on left panel. If the URL Rewrite widget is not under IIS then you might need to install it and might also need to add Application Request Routing (ARR). I can't remember if it came installed by default on IIS 7.5 or if I added it.

Open the URL Rewrite widget and click on Add Rule(s)...
Select a Reverse Proxy rule and click OK.
Server name: localhost:3000/ (or where the Node server is running.)
If you're using relative URLs in the Node.js code then you don't have to rewrite the domain names of the links in the HTTP responses. If you are using absolute names then you're in trouble if you're handling multiple domains as you won't know at this stage which one it's for. The only solution I have for this is to use relative URLs and DO NOT check the option to "Rewrite the domain names..."

Now start your Node.js application on port 3000 and try and access the sites node1.com, node2.com, and node3.com and they should all return the contents of your site running on port 3000.

We're not done yet. If, in Node.js/Express, you take a look at the req.headers.host value you will see that it reads "localhost:3000" and has not passed through the value you were expecting which was one of node1.com/node2.com/node3.com

To get this to work you need to go to this folder with an Administrator command prompt:
C:\Windows\System32\inetsrv
and run this command:
appcmd.exe set config -section:system.webServer/proxy /preserveHostHeader:"True" /commit:apphost

What this command will do is open this file:
C:\Windows\System32\inetsrv\config\applicationHost.config
and find the section called <system.webServer> and change this:
        <proxy enabled="true" />to this:
        <proxy enabled="true" preserveHostHeader="true" />
Recycle the app pool on your reverse proxy site in IIS and try and access it again. The host "head" property will be correctly set.

Now the final "thing" you want to do is to be able to handle multiple sites from your Node.js/Express application.

Here is some basic middleware in app/server.js that will switch between sites:
app.use(function(req, res, next) {
    console.log('Domain is: ' + req.headers.host);
    switch(req.headers.host) {
        case 'node1.com':
            break;
        case 'node2.com':
            break;
        case 'node3.com':
            break;
        default:
            console.log('Unknown domain: ' + req.headers.host);
            break;
    }
    next();
});

You would then setup routes that appropriately handled routes for each host that you were expecting. Where routes are ambiguous you would put a switch statement like above in there to arbitrate among domain functionality.

You could also put a node-proxy in front of these sites to switch between different node apps but then you're defeating the purpose of IIS which can already do that and more efficiently so I can't see the need for a node-proxy.

Some of the answers from this Stackoverflow question might help readers of this topic.

 

Friday, April 4, 2014

ExpressJS and MongoDB End to End

Short URL for this blog post: http://x.co/dcc2014

This blog post accompanies the presentation called ExpressJS and MongoDB End to End at Desert Code Camp 2014.1.

If you want to follow along with this presentation then there are three items you need:
  1. Install Node.
  2. Install MongoDB.
  3. Clone the ExpressJS Sample.
Once you've cloned the sample this locally you should be able to run it using:
node app.js
If MongoDB is running on the default port then it should work.

Give me feedback when the presentation is over: Guy on Speaker Rater

Resources from presentation:

Saturday, February 22, 2014

Fluent 2014 NodeJS Express Presentation

Short URL for this blog post: http://x.co/fluent2014



If you want to follow along with this presentation then there are three items you need:
  1. Install Node.
  2. Install MongoDB.
  3. Clone the ExpressJS Sample.
Once you've cloned the sample this locally you should be able to run it using:
node app.js
If MongoDB is running on the default port then it should work.

Give me feedback when the presentation is over: Guy on Speaker Rater

Resources from presentation:

O'Reilly Fluent 2014 presentation: Introduction to ExpressJS

Wednesday, February 5, 2014

Roof Bug Fixing

Great blog post by Anna Shipman on Roof Bug Fixing.

She doesn't have comments enabled so I'll comment here.

I bought a newly built house in 2007 and after the buyer's inspection and the small fixes they did to it I was happy until the monsoons arrived and we had horizontal driving rain. This exposed leaks in the sealing around the windows.

I called the builders back in, explained what had happened and they fixed the leak and let me know it was done. I walked into the front yard and took the hosepipe and with a nozzle on the front of it sprayed the windows ten times harder than any monsoon could ever deliver water against them. This was my Black Friday load testing.

Of course it leaked and the repairers were standing inside my sitting room watching the water come through the seals around the window. The next day after it had dried they got back to work fixing it again. I was working upstairs and I could hear them spraying the window before they called me back to subsequently show me that it was fixed.

When someone comes around to fix something in my house my standard question before they start work is "how will you know that it's fixed?" and "how will you show me that it's fixed?" Sometimes this is moot and doesn't need to be answered.

Sunday, December 15, 2013

GoDaddy Resellers is hiring awesome software engineers



Yes, that's JCVD!

As director of engineering for the GoDaddy Resellers product I'm in the process of building an awesome team of software engineers to deliver the next version of GoDaddy's Reseller product. If you're a rock-star developer and interested in working on our team at GoDaddy then please apply for a position with us.

I was reading the Joel Test and thought I'd score the position against this test and annotate what we're doing.
  1. Do you use source control?
    1. Yes, Git. Any open source code we create we publish to our public GitHub account and internally we have GitHub Enterprise. (1)
  2. Can you make a build in one step?
    1. Not yet but we're working on it. (0)
  3. Do you make daily builds? 
    1. Not yet but we're working on it. (0)
  4. Do you have a bug database? 
    1. Yes, we use Jira. (1)
  5. Do you fix bugs before writing new code? 
    1. Generally yes, bugs go into Jira and get prioritized in order of importance. (1)
  6. Do you have an up-to-date schedule? 
    1. Yes, it's in Jira. (1)
  7. Do you have a spec? 
    1. Yes, we're very agile so the spec is continuously evolving and developing with the features and the product. The product and features are managed through Jira. (1)
  8. Do programmers have quiet working conditions? 
    1. Yes. Developers work in an open start-up like layout (we've gotten rid of about half the cubes and scheduling the rest to go in 2014). If it's too noisy and we need to block out the sound then there are a number of options from noise canceling headphones, huddle rooms, and working from home. (1)
  9. Do you use the best tools money can buy? 
    1. Yes. I'm not aware of any reasonable tool request that's been turned down. (1)
  10. Do you have testers? 
    1. Yes and No. We're phasing out testers and the developers will be responsible for putting automated testing in place and be accountable for the quality of the product. (1)
  11. Do new candidates write code during their interview? 
    1. Yes (1)
  12. Do you do hallway usability testing? 
    1. We have a UX engineering who works with the team to determine the design and flow of the product. We also have a dedicated usability team at GoDaddy that does this type of work for multiple teams in the company. (1)
Based on the Joel Test I believe that we score a 10/12 and we are working on the other 2 items. The plan is to have those continuous integration and continuous deployment (CI/CD) items taken care of in the next six months.

















Update on 2/5/2014: New GoDaddy Reseller Blog for you to keep up-to-date on what we're doing.


Wednesday, December 11, 2013

How many Friday 13ths in a Year in JavaScript

Inspired by a code golf question on codegolf.stackexchange.com asking for code that counted the number of Friday 13ths in a year I came up with this inefficient NodeJS/JavaScript solution. Both the solutions below can be dropped into a .js file and run from the command line by NodeJS.

// To run:
// node friday13.js <2013>
// <2013> is the year which you want a count of Friday 13ths in

// Add a day incrementer to the Date prototype
Date.prototype.addDays = function (num) {
    var value = this.valueOf();
    value += 86400000 * num;
    return new Date(value);
}

var year = process.argv[2];
if(!year){
 console.log('Was year the first param? Received: ' + year);
 return;
}

var startDate = new Date(year,0,1);
console.log(startDate);

var endDate = new Date(year,11,31);
console.log(endDate);

var counter = 0;
while(startDate <= endDate) {
 if(startDate.getDay() === 5 && startDate.getDate() === 13) {
  counter++;
 }
 startDate = startDate.addDays(1);
}

console.log(counter + ' Friday 13ths in ' + year);

Someone else came up with another JavaScript solution which takes advantage of some of the idiosyncrasies of JavaScript which I thought was interesting:

var year = process.argv[2];

var numFridays = function(year) {
 var count=0;
 for(month=12;month--;) {
  count += !new Date(year,month,1).getDay();
 }
 return count;
}

console.log('Number: ' + numFridays(year));

Here are the interesting parts:
  1. The for loop on line 5 relies on the fact that when the value of month hits zero it will evaluate to false.
  2. On line 5 month will be evaluated for truthiness before it's decremented and that it will be decremented before the body of the for loop is evaluated.
  3. We only have to loop through the 12 months of the year as there can only be one Friday 13th in each month so no need to go through every day.
  4. The JavaScript getDay() method of the Date object returns a 0 for Sunday, 1 for Monday etc. If the month has a Friday 13th then by definition the first day of the month is a Sunday. i.e. if the value of getDay() on the 1st of the month is 0 (equivalent to false) then count this month. To do that we ! (not) the return value which gives us true which will evaluate as the value of 1 when added to an integer.

The Turning Point to becoming a Software Engineer

I started my career as an accountant and one of my first jobs was to do the bank reconciliations (by hand) for the 56 bank accounts this manufacturing company had. Three weeks each month were spent doing this.



I asked management for a PC, a modem to connect to the banks, and access to the mainframe where the cash book was stored. Using one of the original C compilers and dBase III to store the data I pulled the statements from the bank and the mainframe. After several evenings and weekends of work I managed to automate the reconciliation process such that I could finish in a morning what had previously taken me three weeks to do. Although I had dabbled in software previously at school and university this was the turning point that I realized that I could really make a difference being a software engineer.

To give context to this I had written software in Apple BASIC and IBM/Microsoft BASIC to create trivial and contrived toy programs and to do college assignments. This was the first time that I saw the power of automation where so much time could be saved.

Since then I've worked for a number of different companies in various software development roles and for the last few years I've been managing teams of software developers. Excluding my family, the only thing I love more than solving complex problems through software is helping my team members develop and reach their full potential.

What took you into software engineering?