Reputation: 1288
I am trying to deploy for the firt time on Azure my nodejs app.
I start two servers :
// public server
publicServer.listen(publicServerPort, function() {
console.log('Public server started and listening on port ' + publicServerPort);
});
// API server
var credentials = {
key : fs.readFileSync(key, 'utf8'),
cert: fs.readFileSync(cert, 'utf8')
};
https
.createServer(credentials, serverAPI)
.listen(serverAPIPort, function(){
console.log('API server started and listening on port ' + serverAPIPort);
});
I read that Azure is handling himself the redirection to HTTPS and also I can't have two servers because only one port is open.
If I use for both process.env.PORT
, I get (logically):
Unaught exception: Error: listen EADDRINUSE
If I use for the public process.env.PORT
and for the HTTPS 443
:
Unaught exception: Error: listen EACCES
Can I have two servers? If not how to properly handle routing (different for http and https) ? Via protocol detection for example?
Thank you for your help.
Upvotes: 3
Views: 2628
Reputation: 7080
I run an Azure cloud service (using Node.js) that has HTTP and HTTPS endpoints. The trick is to let IIS handle the SSL termination for you so that your Node.js app only listens on HTTP (using process.env.PORT).
I've uploaded my certificate to the Windows Azure portal and then my ServiceDefinition.csdef file looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="my-cloud-service-name" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="my-cloud-service-name" vmsize="Small">
<Imports />
<Startup>
<Task commandLine="setup_web.cmd > log.txt" executionContext="elevated">
<Environment>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
</Variable>
<Variable name="RUNTIMEID" value="node;iisnode" />
<Variable name="RUNTIMEURL" value="http://az413943.vo.msecnd.net/node/0.8.4.exe;http://az413943.vo.msecnd.net/iisnode/0.1.21.exe" />
</Environment>
</Task>
<Task commandLine="node.cmd ..\startup.js" executionContext="elevated" />
</Startup>
<Endpoints>
<InputEndpoint name="Web" protocol="http" port="80" />
<InputEndpoint name="WebSSL" protocol="https" port="443" certificate="my-certificate-name" />
</Endpoints>
<Certificates>
<Certificate name="my-certificate-name" storeLocation="LocalMachine" storeName="CA" />
</Certificates>
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Web" endpointName="Web" />
<Binding name="WebSSL" endpointName="WebSSL" />
</Bindings>
</Site>
</Sites>
</WebRole>
</ServiceDefinition>
Then in the iisnode element of my Web.cloud.config file I made sure to promote the HTTPS server variable:
<iisnode debuggingEnabled="false" devErrorsEnabled="false" loggingEnabled="false" node_env="production" promoteServerVars="HTTPS" />
That allowed me to set the x-forwarded-proto header using a bit of Express.js middleware which is the de facto standard for identifying the originating protocol of an HTTP request: http://en.wikipedia.org/wiki/List_of_HTTP_header_fields
exports.xForwardedProto = function(req, res, next) {
if(!req.headers['x-forwarded-proto']) {
if(req.headers['x-arr-ssl'] || req.headers['x-iisnode-https'] === 'on') {
req.headers['x-forwarded-proto'] = 'https';
}
}
next();
};
Then, when I want to redirect HTTP requests to HTTPS I use this bit of Express.js middleware:
exports.httpsOnly = function(req, res, next) {
if(req.protocol === 'http' && process.env.NODE_ENV && process.env.NODE_ENV != 'development') {
return res.redirect(301, 'https://' + req.get('host') + req.url);
}
next();
};
Upvotes: 4