1
votes

I have an issue with the following setup.

  • Server: Windows Server 2016
  • Server Host: Google Compute Engine
  • My instance is running behind a Load Balancer (and SSL is attached at the Load Balancer level).

I have a site on www.example.org. I want the web.config to 301 redirect:

  • non-www to www
  • http:// to https://

I have the following rules in web.config:

<rewrite>
  <rules>
    <clear />
      <rule name="Force WWW" enabled="true" stopProcessing="true">
      <match url="(.*)" />
      <conditions>
        <add input="{HTTP_HOST}" negate="true" pattern="^(www\.)(.*)$" ignoreCase="true" />
        <add input="{HTTP_HOST}" pattern="localhost" negate="true" />
      </conditions>
      <action type="Redirect" url="https://www.example.org/{R:0}" appendQueryString="true" redirectType="Permanent" />
    </rule>
    <rule name="Force HTTPS" enabled="true" stopProcessing="true">
      <match url="(.*)" />
      <conditions>
        <add input="{HTTPS}" negate="true" pattern="^ON$" ignoreCase="true" />
        <add input="{HTTP_HOST}" pattern="localhost" negate="true" />
      </conditions>
      <action type="Redirect" url="https://www.example.org/{R:1}" appendQueryString="true" redirectType="Permanent"  />
    </rule>
  </rules>
</rewrite>

My problem is that the HTTPS rule results in an infinite loop. My theory is that this is down to the load balancer. I'm redirecting at 'site' (/server) level and it's looping back to the Load Balancer and everything is going "a little kaka" :)

Can anyone advise how/if it is possible to enforce HTTPS at the Load Balancer level on Google Compute Engine?!

I'm not amazingly competent at executing things in console (if that is the way to go) so any help would be greatly appreciated.

1

1 Answers

0
votes

Currently it’s not possible at the load balancer level. You have to do this at the instance level.

You'll want to utilize the user agent/X-Forwarded-Proto headers of each request to determine if you need to perform a redirect. The user agent is necessary to determine if the sender was the health checker (in which case, a redirect is not needed) and the X-Forwarded-Proto header is necessary to determine which protocol the client used to make the request. A simplified request flow looks like this:

Client (http or https) -> LB -> Instance (http)

For each instance, you'll want something like this (sorry i don't know asp) to handle the redirect:

server {
    listen 80;
    server_name _;

    if ($http_user_agent ~ "GoogleHC") {
        set $foo "foo";
    }

    if ($http_x_forwarded_proto != "https") {
        set $foobar "${foo}bar";
    }

    if ($foobar = "bar") {
        return 301 https://$host$request_uri;
    }

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

The above nginx config file listens on 80. If the sender was the health checker, the request is proxied to 8080 (or wherever your web server/api is running). If however, the user agent wasn't the health checker, then we ask which protocol the client used to hit the load balancer. If http was used, the user is redirected to https, otherwise we let them through.

Of course this only works if everything else was setup properly (which for brevity, i'm assuming to be true).

I have a script that tears down/creates a cross regional load balancer for my rest api. I know your setup will be different, but hopefully the following script logs help you cover your bases.

enter image description here