Self-Hosted Web API 2 over SSL with OWIN using http returns 503 status

May 12, 2014 at 5:06 PM
Edited May 12, 2014 at 5:11 PM
I’ve used this tutorial: http://www.asp.net/web-api/overview/hosting-aspnet-web-api/use-owin-to-self-host-web-api to successfully create the self-hosted application using ASP.NET Web API 2 using OWIN. I’ve also set up a self-signed SSL certificate and used the following netsh commands to reserve the URL and bind my certificate to the port number:
netsh http add urlacl url=https://+:9443/ user=Everyone
netsh http add sslcert ipport=0.0.0.0:9443 certhash=HASH appid={GUID}
I’ve also modified the the baseAddress in the original tutorial code to use https like this:
string baseAddress = "https://+:9443/";
instead of the original:
string baseAddress = "http://localhost:9000/";

Once the server is up and running, I can connect to it through Fiddler without problems using https, but if I try to use http then I get a timeout and a 504 status code.

Note that I have added a DelegatingHandler-derived class to intercept the use of plain http and return a response to the user to ask them to use https (see https://github.com/WebApiContrib/WebAPIContrib/blob/master/src/WebApiContrib/MessageHandlers/RequireHttpsHandler.cs), but this code is never hit, so I'm assuming the problem is somewhere in the hosting aspect of things. The new message handler is also added to HttpConfiguration:

config.MessageHandlers.Add(new RequireHttpsHandler());

Can someone please help?
Coordinator
May 12, 2014 at 5:10 PM
You need to register for both http and https addresses (on different ports) for this to work. registering for just https will only allow you to accept requests for https.
May 12, 2014 at 5:22 PM
Thank you for the very quick response. Although I'm not a novice developer by any means, this is my first time looking at ASP.NET technologies so I didn't quite understand your answer.

My plan is to catch any client access to my Web API that doesn't use https (it's possible someone might misspell it and forget the "s", i.e. use http://localhost:9443/api/... instead of https://localhost:9443/api/...) and show a polite error message in the response. In your opinion, what is the best way to achieve this? I'd appreciate a small example. For instance, will this require extra code or extra actions with netsh?
Coordinator
May 12, 2014 at 5:30 PM
Edited May 12, 2014 at 5:30 PM
You can't host HTTP and HTTPs on the same port number (9443), the SSL/TLS negotiation needs to happen before any HTTP/s protocol. Most servers use the following setup:
http://+:80/
https://+:443/

If you only register https://+:443/ then clients that try to access http://hostname:443/ will fail to connect because they're not using SSL/TLS. There's nothing you can do to help them on this port. If you want to host any regular http pages, even just an error page, then you need to do so on a separate port (http://+:80/).
Marked as answer by djikay on 5/12/2014 at 11:29 AM
May 12, 2014 at 5:59 PM
It's still not very clear to me, but the gist of your answer seems to be that what I want to achieve isn't realistic, which will have to be good enough for now I guess.

By the way, I won't be hosting any non-SSL endpoints, i.e. all communication with my REST service must be over SSL. The error message would be sent back in the response body. My server doesn't return pages, just json data in standard response messages.

There appear to be a number of such examples with "traditional" IIS hosting, e.g. the GitHub link I copied in my original question (using a message handler) and http://bitoftech.net/2013/12/03/enforce-https-asp-net-web-api-basic-authentication/ (using a filter) to mention but a few, so I naively assumed this would be possible in the self-hosting world without any code or netsh changes.

If you happen to have any (links to) examples to demonstrate how to achieve what you're saying in the self-hosting world, I'd be very grateful. Otherwise, I'll just have to rely on the standard behaviour (i.e. return 503 status code after timeout), which is not great.
Coordinator
May 12, 2014 at 6:08 PM
IIS normally registers addresses for both HTTP and HTTPs on different ports (http://+:80/, https://+:443/). You need to do the same in self-host if you want to provide a graceful error for HTTP users. See StartOptions.Urls.

IIS's management UI also takes care of the netsh registration for you. There are some 3rd party UI tools for doing registrations with self-host: https://katanaproject.codeplex.com/wikipage?title=Selfhosting
May 12, 2014 at 6:29 PM
Aha! StartOptions.Urls did the trick. I added both URLs as you suggested and now the server is listening (and responding) to requests coming in from both port 9443 and 80, as shown below (in case someone else reads this):
var options = new StartOptions();
options.Urls.Add("https://+:9443/");
options.Urls.Add("http://+:80/");

// Start OWIN host.
using (WebApp.Start<Startup>(options))
. . .
I didn't have to add another netsh for port 80, so I suspect my development machine is already set up for this.

All this means that my message handler is now being called properly and returns the intended, polite error response.

Many thanks for your help and patience.
May 13, 2014 at 8:34 AM

Hi!

Just a quick note to netsh – you can actually look at the entries as well. „netsh http show urlacl“. If your app is run by different non administrative accounts, you might want to change the acl (the SDDL parameter), so that the administrator can give all users access to the port.

Markus

Von: djikay [email removed]
Gesendet: Montag, 12. Mai 2014 20:29
An: Essl, Markus
Betreff: Re: Self-Hosted Web API 2 over SSL with OWIN using http returns 503 status [katanaproject:545123]

From: djikay

Aha! StartOptions.Urls did the trick. I added both URLs as you suggested and now the server is listening (and responding) to requests coming in from both port 9443 and 80, as shown below (in case someone else reads this):

var options = new StartOptions();
options.Urls.Add("https://+:9443/");
options.Urls.Add("http://+:80/");
 
// Start OWIN host.
using (WebApp.Start<Startup>(options))
. . .

I didn't have to add another netsh for port 80, so I suspect my development machine is already set up for this.

All this means that my message handler is now being called properly and returns the intended, polite error response.

Many thanks for your help and patience.

May 13, 2014 at 9:36 AM
Thanks for your response, thunder7553.

I'm aware of the "show" command for netsh, but its output isn't always very clear to me. Regarding user access, I added my own port (9443) with user=Everyone. I haven't changed the port 80 netsh list at all, because I don't entirely understand what I need to do (if anything). Since it works for now, I'm relatively happy. Once it gets to the deployment stage, then I might need to play around with the server (Server 2008 R2) settings; I'm currently working on my Win7 dev box. At that time, though, I should hopefully have help from the server admin guys that should know more about this. I'm also planning to convert my command-line self-host application to a Windows service, so it starts/stops automatically when the server is rebooted.