Configuring SSL endpoints for node.js worker roles on Azure - node.js

I've set up a node.js app to run on worker roles (not web roles) on Azure cloud services. Everything was working fine with the standard app running on HTTP.
Now I'm trying to get it running over SSL on HTTPS, and have successfully followed the instructions at http://www.windowsazure.com/en-us/develop/nodejs/common-tasks/enable-ssl-worker-role/ but it has not produced the correct results!
Now when accessing the url over either HTTP or HTTPS the connection times out and nothing is returned.
Is there anything I might be missing or any steps that aren't in the guide linked above?
One thing I did notice in the guide was whether the line...
<InputEndpoint name="HttpIn" protocol="tcp" port="443" />
... should in fact be HttpsIn instead? Though changing this doesn't seem to make a huge amount of difference.
Update: here are some of my configuration files
ServiceConfiguration.cloud.cscfg
<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" serviceName="*removed*" osFamily="2" osVersion="*" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
<Role name="WorkerRole1">
<ConfigurationSettings />
<Instances count="1" />
<Certificates>
<Certificate name="certificateName" thumbprint="*removed*" thumbprintAlgorithm="sha1" />
</Certificates>
</Role>
</ServiceConfiguration>
ServiceDefinition.csdef
<?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="*removed*" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WorkerRole name="WorkerRole1" vmsize="ExtraSmall">
<Startup>
<Task commandLine="setup_worker.cmd > log.txt" executionContext="elevated">
<Environment>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/#emulated" />
</Variable>
<Variable name="RUNTIMEID" value="node" />
<Variable name="RUNTIMEURL" value="http://az413943.vo.msecnd.net/node/0.8.4.exe" />
</Environment>
</Task>
<Task commandLine="node.cmd .\startup.js" executionContext="elevated" />
</Startup>
<Endpoints>
<InputEndpoint name="HttpIn" protocol="http" port="80" />
<InputEndpoint name="HttpsIn" protocol="https" port="443" certificate="certificateName" />
</Endpoints>
<Certificates>
<Certificate name="certificateName" storeLocation="LocalMachine" storeName="My" />
</Certificates>
<Runtime>
<Environment>
<Variable name="PORT">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[#name='HttpIn']/#port" />
</Variable>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/#emulated" />
</Variable>
</Environment>
<EntryPoint>
<ProgramEntryPoint commandLine="node.cmd .\server.js" setReadyOnProcessStart="true" />
</EntryPoint>
</Runtime>
</WorkerRole>
</ServiceDefinition>
I have also tried various variations on these (with fewer extra tags and attributes) and nothing seems to work.

The protocol values you provided are HttpIn and HttpsIn. You shall use these values only for ASP.NET Web Roles!! When you run 3rd party web servers on Worker Roles you shall only use tcp as value for protocol attribute!! changing this is the easiest way to make things not working! Could you switch them back to tcp, remove the certificate attribute from the Https Endpoint and try again?
Also, the default sample app server.js listens to only one port. Which is being passed by the environment value PORT defined for the startup task. There you shall reference the HttpsIn endpoint if you want HTTPS traffic. Unfortunately I don't know whether node.js can handle both http AND https traffic with this simple setup.
UPDATE
Please use the following .csconfig file (replace the content of all .csconfig files you see in the folder with the content I provide):
<?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="*removed*" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WorkerRole name="WorkerRole1" vmsize="ExtraSmall">
<Startup>
<Task commandLine="setup_worker.cmd > log.txt" executionContext="elevated">
<Environment>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/#emulated" />
</Variable>
<Variable name="RUNTIMEID" value="node" />
<Variable name="RUNTIMEURL" value="http://az413943.vo.msecnd.net/node/0.8.4.exe" />
</Environment>
</Task>
<Task commandLine="node.cmd .\startup.js" executionContext="elevated" />
</Startup>
<Endpoints>
<InputEndpoint name="HttpsIn" protocol="https" port="443" />
</Endpoints>
<Certificates>
<Certificate name="certificateName" storeLocation="LocalMachine" storeName="My" />
</Certificates>
<Runtime>
<Environment>
<Variable name="PORT">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[#name='HttpsIn']/#port" />
</Variable>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/#emulated" />
</Variable>
</Environment>
<EntryPoint>
<ProgramEntryPoint commandLine="node.cmd .\server.js" setReadyOnProcessStart="true" />
</EntryPoint>
</Runtime>
</WorkerRole>
</ServiceDefinition>
Also, please provide the code in your server.js file - at least the first 10 lines where the binding is done. And also after the changes, please execute the following command line and tell us what is the result:
c:>telnet [your_cloud_service].cloudapp.net 443
And also please confirm that you have the .pfx file in the folder where you are executing the powershell commands.

Related

Azure Cloud Service - no environment variables being set

The roles in my Cloud Service aren't getting any custom environment variables set. --Meaning if I enumerate the results of a call to Environment.GetEnvironmentVariables(), only the standard environment variables are set (things like PATH or the user id).
When I debug the Cloud Service locally using the emulator, the envvars are there, so I'm kind of at a loss here.
The relevant .csdef:
<WebRole name="..." vmsize="Small">
<ConfigurationSettings>
<Setting name="FirstSetting" />
<Setting name="AnotherSetting" />
</ConfigurationSettings>
<Runtime>
<Environment>
<Variable name="FirstSettingEnvVar">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='FirstSetting']/#value" />
</Variable>
<Variable name="SecondSettingEnvVar">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='SecondSetting']/#value" />
</Variable>
</Environment>
</Runtime>
and the relevant .cscfg:
<Role name="...">
<Instances count="2" />
<ConfigurationSettings>
<Setting name="FirstSetting" value="ABCD" />
<Setting name="SecondSetting" value="WXYZ" />
</ConfigurationSettings>
</Role>

The XML specification is not valid:

The XML specification is not valid: The element 'WebRole' in namespace 'http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition' has incomplete content. List of possible elements expected: 'Sites' in namespace 'http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition'.
Here is the XML file
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="AzureCloudService1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
<WebRole name="Web" vmsize="Small">
<Startup>
<Task commandLine="StartUp.cmd" executionContext="elevated" taskType="background" />
</Startup>
</WebRole>
</ServiceDefinition>
As the error says.... Your <WebRole> tag must include a <Sites> node.
When you create a Azure Cloud Service project, there will be a default ServiceDefinition.csdef in Solution Explorer with the content below,
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="AzureCloudService1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
<WebRole name="WebRole1" vmsize="Small">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" />
<Setting name="StorageConnectionString" />
</ConfigurationSettings>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
</Endpoints>
</WebRole>
<WorkerRole name="WorkerRole1" vmsize="Small">
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" />
</ConfigurationSettings>
</WorkerRole>
</ServiceDefinition>
So, you are missing a <Sites> node.

Azure Cloud Service does not pass runtime environment variables to startup tasks

I have created a Cloud Services definition with several start-up tasks. I have a common set of Environment variables that I want to be available from each task, for example if it's running in the emulator. For that I used the the following documentation: https://azure.microsoft.com/nl-nl/documentation/articles/cloud-services-startup-tasks-common/#differentiate-between-running-in-the-emulator-and-the-cloud
The problem is that I do not get any variables from the runtime block passed into my tasks. Any variables declared at the task level are passed normally.
My definition looks like this:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="Portal.CloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
<WebRole name="Portal" vmsize="Small">
...
<LocalResources>
<LocalStorage name="StartupLog" sizeInMB="100" cleanOnRoleRecycle="false"/>
</LocalResources>
<Runtime>
<Environment>
<Variable name="ComputeEmulatorRunning">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/#emulated" />
</Variable>
<Variable name="CurrentEnvironment">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='Environment']/#value" />
</Variable>
<Variable name="StartupLogPath">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[#name='StartupLog']/#path" />
</Variable>
<Variable name="testvar" value="test"/>
</Environment>
</Runtime>
<Startup>
<Task commandLine="AddCertToTrustedRootCA.cmd" executionContext="elevated" taskType="simple" />
<Task commandLine="ConfigureIIS.cmd" executionContext="elevated" taskType="simple">
<Environment>
<Variable name="taskvar" value="test"/>
</Environment>
</Task>
</Startup>
...
</WebRole>
</ServiceDefinition>
I'm debugging ConfigureIIS.cmd at the moment. I get passed the %taskvar%-variable defined at task level, but the runtime variable %testvar% is not available, like all the other runtime environment variables.
What I have tried so far:
Set only the most simple variable (%testvar%) and remove the RoleInstanceValue variables
Set the <Runtime>-element to <Runtime executionContext="elevated"> to match the tasks execution level
Remove the executionContext from the tasks
As far as I can see my code is equal to the example as given by Microsoft and yet it does not work. Did I make a mistake in my definitions, or am I missing something?

RoleEnvironment.Changing event doesn't trigger in WorkerRole

So, I have Azure project with 3 WebRoles and 1 WorkerRole. In each project I have subscription on RoleEnvironment.Changing and RoleEnvironment.Changed events. In WebRole everything is fine, but in WorkerRole these events don't want to trigger.
Мoreover when I change setting of some WebRole, WorkerRole is also recycling everytime
WorkerRole run another x86 proccess inside and script on startup
Azure SDK 1.7 is used
<WorkerRole name="MyService" vmsize="Medium" enableNativeCodeExecution="true">
<Startup>
<Task commandLine="startup.cmd" taskType="simple" executionContext="elevated" />
</Startup>
<Runtime executionContext="elevated" />
<Imports>
<Import moduleName="Diagnostics" />
<Import moduleName="RemoteAccess" />
</Imports>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="8081" />
<InputEndpoint name="TCPEndpoint" protocol="tcp" port="10101" localPort="10100" />
<InternalEndpoint name="InternalEndpoint" protocol="http" />
</Endpoints>
<ConfigurationSettings>
<Setting name="StorageConnectionString" />
<Setting name="TransactionLogsBlobContainer" />
</ConfigurationSettings>
<LocalResources>
<LocalStorage name="DiagnosticStore" cleanOnRoleRecycle="false" sizeInMB="8192" />
</LocalResources>
</WorkerRole>
Does anybody have any idea what could be going on?
Thanks
I've had a similar issue and found that changing the taskType of the Startup Task from elevated to background solved my problem. I'd recommend starting there.
<Startup>
<Task commandLine="startup.cmd" executionContext="elevated" taskType="background"></Task>
</Startup>
For worker roles, you must define an internal endpoint (even if you don't actually use it), in order to get certain events.
IE, add this to your CSDef:
More details here: http://blogs.msdn.com/b/windowsazure/archive/2011/01/04/responding-to-role-topology-changes.aspx

Publish-AzureServiceProject Node.js to Windows Server 2012

I'm trying to publish a Node.js package to Azure using the Powershell "Publish-AzureServiceProject" cmdlet.
With the default osFamily="2" (Windows Server 2008 R2) it works as expected but when I publish using osFamily="3" (Windows Server 2012) I get the following error:
The feature named NetFx35 that is required by the uploaded package is
not available in the OS * chosen for the deployment.
Obviously I'm not using .Net but 3.5 is the default that prevents me to upload the package.
To specify .Net 4.5 I read that I need to create a roleproperties.txt file containing:
TargetFrameWorkVersion=v4.5
and pass it via a /rolePropertiesFile to cspack.
However since I'm not calling cspack myself, how can I pass that option through Publish-AzureServiceProject to cspack? Or is there another workaround?
Currently my ServiceDefinition looks like this:
<?xml version="1.0"?>
<ServiceDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Foo" upgradeDomainCount="1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WorkerRole name="Bar">
<Imports>
<Import moduleName="RemoteForwarder" />
<Import moduleName="RemoteAccess" />
</Imports>
<Startup>
<Task commandLine="setup_worker.cmd > log.txt" executionContext="elevated">
<Environment>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/#emulated" />
</Variable>
<Variable name="RUNTIMEID" value="node" />
<Variable name="RUNTIMEURL" value="http://nodertncu.blob.core.windows.net/node/0.6.20.exe" />
</Environment>
</Task>
</Startup>
<Endpoints>
<InputEndpoint name="HttpIn" protocol="tcp" port="80" />
</Endpoints>
<Runtime>
<Environment>
<Variable name="PORT">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[#name='HttpIn']/#port" />
</Variable>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/#emulated" />
</Variable>
</Environment>
<EntryPoint>
<ProgramEntryPoint commandLine="runnode.cmd" setReadyOnProcessStart="true" />
</EntryPoint>
</Runtime>
</WorkerRole>
</ServiceDefinition>
So currently, there's a bit of work you need to do to get OSFamily=3 working with non-.Net roles. Essentially, you need to run cspack yourself to create a package and specify a roleProperties file that allows you to target .Net 4.5 (yes, even though you're not using .Net at all, you need to convince the cspack tool that you're using .Net 4.5).
Here are the steps:
Go create a new node project with a web role.
Modify the cscfg to set OS Family = 3.
Drop the below roleproperties.txt into the root of the service.
Launch the "Windows Azure Command Prompt" and then go the service root folder.
Run this command: cspack ServiceDefinition.csdef /role:WebRole1;WebRole1 /sites:WebRole1;Web;WebRole1 /rolePropertiesFile:WebRole1;RoleProperties.txt /out:package.cspkg
Log in to the portal and create a service / upload the cspkg manually
The contents of roleproperties.txt:
TargetFrameworkVersion=v4.5
As Node SDK builds the package without using cspack.exe (to keep platform independent architecture) you can not use "/rolePropertiesFile" option.
As workaround, you can setup the targetFrameworkVersion setting using Runtime -> EntryPoint -> NetFxEntryPoint -> targetFrameworkVersion="v4.5" in your ServiceDefinition as below example:
<?xml version="1.0"?>
<ServiceDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="NodeAvkash" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WebRole1" vmsize="ExtraSmall">
<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://nodertncu.blob.core.windows.net/node/0.6.20.exe;http://nodertncu.blob.core.windows.net/iisnode/0.1.21.exe" />
</Environment>
</Task>
</Startup>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
</Endpoints>
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
<Runtime executionContext="elevated">
<EntryPoint>
<NetFxEntryPoint assemblyName="WebRole1.dll" targetFrameworkVersion="v4.5" />
</EntryPoint>
</Runtime>
</WebRole>
</ServiceDefinition>

Resources