When using an AWS Load Balancer (ELB), the load balancer will recieve the client requests and forward those requests to your EC2 instance. The ELB will make http port 80 requests, regardless of whether the client used http or https. If you need to ensure that all client requests are ssl, https requests over port 443, you need to check the requests coming in at the EC2 instance level, and redirect http requests to https. However, since all requests from the ELB will be over port 80, this can cause a redirect loop. To remedy this, the ELB adds headers to its requests to let the EC2 instance know what protocol the client used originally. You can use these headers to determine if you need to make the redirect or not.
Below is the code that will handle this scenario. This code belongs in your Global.asax.cs file. I have also added logic to handle localhost requests and an appsetting to force ssl or not.
//Global.asax.cs
protected void Application_BeginRequest()
{
string url = HttpContext.Current.Request.Url.ToString();
//redirect to https
bool forceSSL = false;
bool.TryParse(System.Configuration.ConfigurationManager.AppSettings["Web.ForceSSL"], out forceSSL);
//ignore rule on localhost
if (url.Contains("localhost") == false
&& forceSSL == true)
{
//check if AWS EBS X-Forwarded-Proto header is available
//if AWS EBS X-Forwarded-Proto header == https, cancel redirect
var headers = HttpContext.Current.Request.Headers;
for (int x = 0; x < headers.Count; x++)
{
string header = headers.GetKey(x);
if (header == "X-Forwarded-Proto")
{
foreach (string value in headers.GetValues(x))
{
if (value == "https")
{
forceSSL = false;
break;
}
}
}
}
if (forceSSL)
{
string scheme = HttpContext.Current.Request.Url.Scheme;
if (!url.StartsWith("https://"))
{
string newUrl = url.Replace("http://", "https://");
Response.Redirect(newUrl);
}
}
}
}