Azure mod-rewrite to SSL doesn't work - iis

I have deployed an ASP.NET web application to Azure running in a web role. It is configured with a DNS name like 'myapp.cloudapp.net' and SSL (the certificate is self-signed, meaning we get a certificate warning but otherwise this is all set up and works fine)
I want to automagically route requests the come on http to https. So, I added an http endpoint and set up a rewrite rule as per the instructions here (second method):
http://blog.smarx.com/posts/redirecting-to-https-in-windows-azure-two-methods
It doesn't work properly.
Testing directly on the Azure machine (via remote desktop):
Access https://myapp.cloudapp.net - works
Access http://myapp.cloudapp.net - "Internet explorer cannot display the webpage"
So I go to IIS and 'browse' my site: this takes me there via the IP address:
Access https://[ipaddress] - works
Access http://[ipaddress] - works! Sends me to https://[ipaddress]
So what am I missing, that this works via IP address but not by host name?
I would like to hit http://myapp.cloudapp.net and be redirected to https://myapp.cloudapp.net.
For the record, here is the relevant parts of my configuration:
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="MyApp" />
<Binding name="Endpoint1" endpointName="MyAppHttp" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="MyApp" protocol="https" port="443" certificate="MYCERT" />
<InputEndpoint name="MyAppHttp" protocol="http" port="80" />
</Endpoints>
<Certificates>
<Certificate name="MYCERT" storeLocation="LocalMachine" storeName="My" />
</Certificates>
Can anyone help explain what I might be doing wrong?
Thanks in advance

Not a lot to go on, but one thing that jumps out at me is the 'name' of your bindings. Make them different.

Related

Deploying to new D-series Azure VM's

I'm trying to deploy a test instance of our Azure-based webservice to the new D-series Azure vm's. We make extensive use of temp files and are hoping we'll see some good performance improvements. Unfortunately we don't seem to be able to package or build using the new vmsizes. Our current csdef looks like this:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="WebAPI.Azure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-10.2.2">
<WebRole name="WebAPI" vmsize="Large">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="NonSSL Endpoint" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="NonSSL Endpoint" protocol="http" port="80" />
<InternalEndpoint name="InternalHttpIn" protocol="http" />
</Endpoints>
</WebRole>
</ServiceDefinition>
If I switch the vmsize from "Large" to "Standard_D3" and try to build or package for publishing, I get this error:
Error 2 The XML specification is not valid: The 'vmsize' attribute is invalid - The value 'Standard_D3' is invalid according to its datatype 'http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition:RoleSize' - The Enumeration constraint failed. C:\Users\ablack\Desktop\WebAPI.Azure\ServiceDefinition.csdef 3 34 WebAPI.Azure
How do I get this schema updated? Or is there a way to override XML validation during the build & package process?
Apparently the 2.4 SDK removes the vmsize constraint entirely (it accepts any values, including made-up values like "Supersize"), so we will have to upgrade to that to try any new size options. This will complicate benchmarking (we'll need to get fresh baselines with the updated SDK first), but c'est la vie.

Cannot access RoleEnviroment when running multiple Sites inside Cloud Service

I have got an existing solution which uses settings from RoleEnviroment in both the WebRole.OnStart and Global.asax Application_Start handlers. (This has been running well for months)
This all works fine when I have just one Site inside my role:
<WebRole name="WebRole" vmsize="ExtraSmall">
<Runtime executionContext="elevated" />
<Sites>
<Site name="Web1" physicalDirectory="..\..\..\Web1\">
<Bindings>
<Binding name="HTTP" endpointName="Public HTTP" hostHeader="web1.com" />
</Bindings>
</Site>
</Sites>
However when I add my second site, neither site can access RoleEnviroment??
<WebRole name="WebRole" vmsize="ExtraSmall">
<Runtime executionContext="elevated" />
<Sites>
<Site name="Web1" physicalDirectory="..\..\..\Web1\">
<Bindings>
<Binding name="HTTP" endpointName="Public HTTP" hostHeader="web1.com" />
</Bindings>
</Site>
<Site name="Web2" physicalDirectory="..\..\..\Web2\">
<Bindings>
<Binding name="HTTP" endpointName="Public HTTP" hostHeader="web2.com" />
</Bindings>
</Site>
</Sites>
I have tested this in the local azure emulator (full) and it works fine, but when deployed to an actual web role it throws:
[SEHException (0x80004005): External component has thrown an exception.]
RdGetApplicationConfigurationSetting(UInt16* , UInt16** ) +0
RoleEnvironmentGetConfigurationSettingValueW(UInt16* pszName, UInt16* pszDest, UInt64 cchDest, UInt64* pcchRequiredDestSize) +73
Microsoft.WindowsAzure.ServiceRuntime.Internal.InteropRoleManager.GetConfigurationSetting(String name, String& ret) +133
Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(String configurationSettingName) +109
Web1.Installer.Install(IWindsorContainer container, IConfigurationStore store) in c:\projects\Webs\Web1\Installer.cs:21
I have checked that the setting I am trying to access is there. When I remove the second Site it works fine. When I remove the first Site it also works fine. It looks to me like there is an issue with Azure providing access to the RoleEnviroment for web roles in multiple instances.
Okay, so after working on this for almost 2 days. The issue turned out to be mismatching Azure SDK version assemblies on the projects.
The older Site had Azure SDK 2.4, and for some reason the newer Site had SDK 2.3, this meant the RoleEnvironment could not be found when there was two sites (both version of the assembly) deployed.
I assume this is because they are looking for the RoleEnvironment differently, or are conflicting in how they access it.
I've read that this may be related to the 'Rd' environment variables that may cause RoleEnvironment to be IsAvailable = false.
So guys: Check your Azure SDK assembly versions are sync if you encounter this issue!

Azure ServiceDefinition file - ProgramEntryPoint, runtime IP address and Port

I'm running a command line program (happens to be Redis) inside a Windows Azure Worker Role using ProgramEntryPoint as follows
<WorkerRole name="Worker" vmsize="Small">
<Runtime executionContext="limited">
<Environment>
<Variable name="ADDRESS">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[#name='Redis']/#address" />
</Variable>
<Variable name="PORT">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[#name='Redis']/#port" />
</Variable>
</Environment>
<EntryPoint>
<ProgramEntryPoint commandLine="redis-server.exe" setReadyOnProcessStart="true" />
</EntryPoint>
</Runtime>
<Endpoints>
<InternalEndpoint name="Redis" protocol="tcp" port="6379" />
</Endpoints>
</WorkerRole>
So far, so good (it works).
I now want to run a slave instance of the server in another WorkerRole
<WorkerRole name="SlaveWorker" vmsize="Small">
<Runtime executionContext="limited">
<EntryPoint>
<ProgramEntryPoint commandLine="echo slaveof %ADDRESS% %PORT% | redis-server.exe -" setReadyOnProcessStart="true" />
</EntryPoint>
</Runtime>
<Imports>
<Import moduleName="Diagnostics" />
<Import moduleName="RemoteAccess" />
</Imports>
<Endpoints>
<InternalEndpoint name="Redis" protocol="tcp" port="6379" />
</Endpoints>
</WorkerRole>
You can see I need to tell the slave server where its master is using IP address and port; something that I don't know until Azure has allocated the network resources for that role. I've seen #smarx do something along these lines.
However I think there may be a couple of things wrong with this in my case
I'm setting environment variables in one role and hoping to use them in another - not going to work.
Even if the right data was available the way I need to pass it to the redis-server.exe is not recognized as a valid entry point with the echo at the beginning
Is the only way to know the runtime IP address and Port of another
worker role via code or is there a syntax I'm missing in the config
file?
If I manage to get the IP and Port, is the only way to make my
command line work to push it to a powershell script or batch file?
Thanks for your thoughts.
The only way one instance will know another's IP address will be if a.) it programmatically grabs it, or b.) the other instance publishes it to a wellknown location (e.g. table storage). In your case, it might be easiest to just have the slave role run a startup task that accesses the RoleEnvironment (via Powershell perhaps) and sets an Environment variable with the IP Address of the master. If you do this as a 'simple' type, I believe it will run before your ProgramEntryPoint does (blocking) and you can just use the env var in your command line there.
Couple thoughts here however:
How are you handling multi-instance within a role? Are you only planning on running a single instance?
Do you need two different roles? Why not a single role with 2 instances that decide via election which is master?

is it possible to hang a few web sites in one role at a port of Azure?

http://msdn.microsoft.com/en-us/library/windowsazure/gg433110.aspx
<Site name="ClientService" physicalDirectory="..\qwer.ClientService">
<Bindings>
<Binding name="ClientService" endpointName="EndpointClientService" hostHeader="ClientService.tsasdc.com" />
</Bindings>
</Site>
error
Error 1 The same local port '80' is assigned to input endpoints EndpointImageService and Endpoint1 in role qwer.Web. C:\Users\Administrator\Desktop\prohect\src\qwer.Azure\ServiceDefinition.csdef 1 1 qwer.Azure
You must use one and the same EndPoint for all the sites you need. That is the need for defining the "hostHeader" in each Binding. For example, if you want a port 80 HTTP endpoint - you may have only one endpoint per Hosted Service. And you just map all your sites to the same endpoint.
Endpoint1 is predefined HTTP input endpoint on port 80 when you have Web Role. You can either rename it to something more meaningful, or just use it for your second site, and never create second input endpoint on HTTP protocol and port 80.
You can have a few web sites, but they each have to point to their own unique port. If you had multiple on the same port, it wouldn't know which one to send the request to.
both of your sites should have the same endpoint name.
you got site with endpoint name Endpoint1;
the second site ( with the physicalDirectory attr) should go to the same endpoint with a hostHeader you already put.
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
<Site name="Web2" physicalDirectory="XXX">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="YOUR HOST HEADER" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
</Endpoints>`

Hostheader not working in Azure

I have a multi-site web role set up in Azure. In my service definition file I have the following:
<Sites>
<Site name="Web" physicalDirectory="..\ABC.WebUx">
<Bindings>
<Binding name="Abc" endpointName="Endpoint1" hostHeader="www.abc.com" />
</Bindings>
</Site>
<Site name="DEF" physicalDirectory="..\DEF.WebUx">
<Bindings>
<Binding name="Def" endpointName="Endpoint1" hostHeader="www.def.com" />
</Bindings>
</Site>
<Site name="Ghi" physicalDirectory="..\GHI.WebUx">
<Bindings>
<Binding name="Ghi" endpointName="Endpoint1" hostHeader="www.ghi.com" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
</Endpoints>
The hostheader works good when I try www.def.com and www.ghi.com however when entering www.abc.com it seems to ignore the physical directory and instead gives me a message like this:
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
The request for 'Home' has found the following matching controllers:
ABC.WebUx.Controllers.HomeController
DEF.WebUx.Controllers.HomeController
GHI.WebUx.Controllers.HomeController
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
Does anyone know why it seems to ignore the physical directory for the default "Web" which btw is the site that I have linked to my cloud service.
Your help would be much appreciated.
Nancy
If you're working with multiple websites I would recommend watching this Cloud Cover episode. During the episode they discuss that any site that has the name "Web" is treated as a special case by Azure and so properties like the physical directory are ignored. So to fix your specific problem change the name of your first site from "Web" to "ABC".
The default "web" site will always point to the project folder for the web role in your solution. You cannot overwrite it using the physicalDirectory attribute.

Resources