Home » Microsoft TechnologiesRSS

Azure messing with port numbers - creates a problem

Hello,

The Azure service appears to be running behind a proxy server that is changing the headers of the http requests.  For example, I make a request over port 80, but the server receives a request on port 20000 or something like that.  The problem with this is that the server then sends links out with port 20000, which then no longer work.  Since everything is in a virtual machine, I cannot think of a valid reason that this would be required.  It will be less 'breaking' for customers if the Azure service did not change the port number of the inbound request.

This causes an issue for me, because the first reaction is to simply output all urls as relative urls, which works well on the site, but some forms of feeds (ie: sitemap protocol) require full urls.  The second approach would be to assume to output all urls with port 80, but then my API won't work when tested in Cassini, which uses many dynamic ports, and it would also not work well in the Azure dev fabric.

My opinion is that the firewalls and load-balancers that are operating in the Azure service should be transparent and should not modify the request headers nor change the port numbers that the sites are operating on.

Is there any way this is going to be fixed?

Are there any other solutions that will work in Cassini, IIS, Dev Fabric, and Azure?

Thanks,
Shan
 

13 Answers Found

 

Answer 1

Hello, can you post some code? What kind of requests  are you making? We do have some problems with WSDL files, in which the links such as soap:address.location are incorrect. But for other scenarios, the port  number should not be changed. I suggest you to put all static URLs in the configuration file, so you can modify them in one place.
 

Answer 2

The root of the problem  is that I am building a framework that can be used on multiple websites.  As such, I cannot hard-code all the urls in my framework and I emit urls based on building urls from the inbound request.  Relative urls are used whereever possible, but for some urls, like Sitemap protocol, the urls have to be full urls.  As such, I get the scheme, host and port  from the current request.  The problem is that Azure modifies these.  For example, if I browse to http://myapp.cloudapp.net/ , the browser request is over port 80, but Azure changes this to another port, such as port 20000.  The ASP.NET page sees the request as http://myapp.cloudapp.net:20000/.  This is inconsistent with IIS behavior. 

The problem is now if I use the current scheme, host, and port, the urls that I emit in my site map will have the extra port information, and therefore will not work (these ports are not allowed into Azure, and many client firewalls won't allow outbout http  over port 20000 anyways.  If I take another approach and hard-code to port 80, the site will not emit proper urls suitable to run properly in the dev fabric (which is typically over port 81, but can be any port really), and if my framework is used in Visual Studio and run in the development server  (cassini), again it will not emit proper urls.

The root of the problem is that the Azure network configuration with the load-balancing firewalls in front of Azure mess with the inbound request to the web server by changing  the port numbers.  I would like Microsoft to reconsider the network configuration so that our requests  coming in on port 80 stay on port 80.

Thanks,
Shan McArthur
www.shanmcarthur.net
 

Answer 3

This is a known issue.  For a couple workarounds, check out David Lempher's post: http://blogs.msdn.com/davidlem/archive/2009/01/27/windows-azure-accessing-the-request-url-property.aspx and my comment at the bottom.

We'll of course still work on a fix, but I don't know when to expect it, so I'd recommend using a workaround for now.
 

Answer 4

Thanks Steve,

The blog article definately describes the same problem  I am having, but as I indicated in my previous posts, the solution is not acceptable.  The solution that is given is to build the url without the port  information.  That will work in production Azure, but will break on the dev fabric as well as if the site is hosted in Cassini (Visual Studio Development Server).  The port number in the url is a critical component of the uri and I cannot just skip it, especially considering this is a framework and not just a single website that I am building.

But you might be able to offer me a little more information - is the port number ALWAYS 20000?  If so, perhaps I can add some additional checks in my code to see if it is 20000 and skip it if it is (assuming this scenario will always mean it is being hosted in Azure) otherwise I could include the port number (so it can also run everywhere else).  Is it always 20000?

Is this something the team is going to fix soon, or should I proceed with this hack?  I really don't like adding hacks to my product, but I cannot wait forever for another solution either.

Thanks,
Shan
 

Answer 5

Shan,
 You don't have to use a hack that crude. The SDK provides you with an API to know if you are running under Fabric (DevFabric or real one) by using the "RoleManager.IsRoleManagerRunning()" function. That way you can tell when you are running within Windows Azure environment vs. Casini. If you want to differentiate across DevFabric and real fabric, you can use the environment variables (such as ComputerName) to tell where you are running.

There's already a basic framework to differentiate between Fabric, Casini and CLR in the "HelloFabric/Common/ApplicationEnvironment.cs" that can be expanded upon.

In general, the problem  is due to being in a farm environment behind an LB, so it's not unique to Windows Azure.
 

Answer 6

If I used RoleManager.IsRoleManagerRunning(), I would take a dependency on the Azure DLLs.  Do we have redist rights to these DLLs for when I distribute our CMS to clients?  Without the redist rights, I cannot package the DLLs, and without the DLLs, my product won't run in clients that are using IIS or are not running in Azure.

I understand the problem  is because of the load balancer, but it is the configuration of the load balancer that is causing the issue.  I have my stuff running behind many client load balancers with no issues.  In most cases, each of their instances gets a new IP address, but they keep the port  on port 80.  The Azure load balancer is changing  the port number to 20000 for which I see no valid justification, and as it is apparent in this thread, this definately complicates things.  A transparent load balancing configuration would be far more appreciated.

Thanks,
Shan

 

Answer 7

The reason why you are seeing port  20000 is that ASP.NET builds the request url using a IIS server  variable SERVER_PORT, and this is taken from the physical receiving port number on the VM where the role instance is running, not the port on the load balancer (or, under development fabric, the value is 5100 not 81).  We have a workaround fix for this ready (by setting the SERVER_PORT) but it didn't make into our most recent refresh, but we hope our next SDK refresh will get this problem  fixed.

I think that the port number in the variable HTTP_HOST is the correct one sent to the load balancer so you can use that.

Zhe
 

Answer 8

Yup, that's why I use the HOST header as Zhe suggests (or see my comment on David Lempher's blog post).  This gives me exactly what the client requested, since it's passed through unmodified through routers/LBs.

 

Answer 9

Yes, I just tested all permutations of environments (IIS, Azure Dev, Cassini, Azure Prod) and it looks like I can build a reliable url using the HTTP_HOST variable.  It is too bad the standard request url did not work, but I can get a solution together with this.  It will be less hacky than hard-coding ports 20000 and 5100 in the solution.

Thanks for the suggestion.

Shan
 

Answer 10

Azure is not unique in having port  forwarding relays for load balancing.  Any ASP.NET site or service  that needs to send absolute URLs to itself back to the outside world needs to take special care to do so accurately so it works in any environment.

This file has what I came up with that seems to accurately predict the outside-facing absolute URL in every environment people have used it in, with relevant snippet included below.

/// <summary>
/// Gets the public facing URL for the given incoming http  request.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="serverVariables">The server  variables to consider part of the request.</param>
/// <returns>
/// The URI that the outside world used to create this request.
/// </returns>
/// <remarks>
/// Although the <paramref name="serverVariables"/> value can be obtained from
/// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them
/// in so we can simulate injected values from our unit tests since the actual property
/// is a read-only kind of <see cref="NameValueCollection"/>.
/// </remarks>
internalstaticUriGetPublicFacingUrl(HttpRequestrequest,NameValueCollectionserverVariables){
Contract.Requires<ArgumentNullException>(request!=null);
Contract.Requires<ArgumentNullException>(serverVariables!=null);

// Due to URL rewriting, cloud computing (i.e. Azure)
// and web farms, etc., we have to be VERY careful about what
// we consider the incoming URL. We want to see the URL as it would
// appear on the public-facing side of the hosting web site.
// HttpRequest.Url gives us the internal URL in a cloud environment,
// So we use a variable that (at least from what I can tell) gives us
// the public URL:
if(serverVariables["HTTP_HOST"]!=null){
ErrorUtilities.VerifySupported(request.Url.Scheme==Uri.UriSchemeHttps||request.Url.Scheme==Uri.UriSchemeHttp,"Only HTTP and HTTPS are supported protocols.");
stringscheme=serverVariables["HTTP_X_FORWARDED_PROTO"]??request.Url.Scheme;
UrihostAndPort=newUri(scheme+Uri.SchemeDelimiter+serverVariables["HTTP_HOST"]);
UriBuilderpublicRequestUri=newUriBuilder(request.Url);
publicRequestUri.Scheme=scheme;
publicRequestUri.Host=hostAndPort.Host;
publicRequestUri.Port=hostAndPort.Port;// CC missing Uri.Port contract that's on UriBuilder.Port
returnpublicRequestUri.Uri;
}else{
// Failover to the method that works for non-web farm enviroments.
// We use Request.Url for the full path to the server, and modify it
// with Request.RawUrl to capture both the cookieless session "directory" if it exists
// and the original path in case URL rewriting is going on. We don't want to be
// fooled by URL rewriting because we're comparing the actual URL with what's in
// the return_to parameter in some cases.
// Response.ApplyAppPathModifier(builder.Path) would have worked for the cookieless
// session, but not the URL rewriting problem.
returnnewUri(request.Url,request.RawUrl);
}
}
 

Answer 11

This issue is still not fixed with Windows Azure SDK 1.1. Any plans to fix this in upcoming releases?

Thanks,

--

Satish

 
 

Answer 13

Hi Andrew,

I'm curious to know how to use this as I've also encountered the same issue even with the latest Azure SDK. Would you be able to provide a sample for this? and also does this covers the CSS, JS, etc. request which are also affected by the concatenated port?

Thanks in Advance. :)

 
 
 

<< Previous      Next >>


Microsoft   |   Windows   |   Visual Studio   |   Follow us on Twitter