Redirect all http requests behind Amazon ELB to https without using if

Solution 1:

  1. Setup your AWS ELB mapping ELB:80 to instance:80 and ELB:443 to instance:1443.
  2. Bind nginx to listen on port 80 and 1443.
  3. Forward requests arriving at port 80 to port 443.
  4. Health check should be HTTP:1443. It rejects the HTTP:80 because the 301 redirect.

aws elb setup

NGINX Setup

    server {
       listen         80;
       server_name    www.example.org;
       rewrite        ^ https://$server_name$request_uri? permanent;
    }

    server {
       listen         1443;
       server_name    www.example.org;
   } 

Solution 2:

If it's working correctly like that, don't be scared of it. http://wiki.nginx.org/IfIsEvil

It is important to note that the behaviour of if is not inconsistent, given two identical requests it will not randomly fail on one and work on the other, with proper testing and understanding ifs can be used. The advice to use other directives where available still very much apply, though.


Solution 3:

This solution uses conditional logic, but as the accepted answer suggests, I also think this is ok. Ref: https://stackoverflow.com/questions/4833238/nginx-conf-redirect-multiple-conditions

Also, this doesn't require opening any additional ports in the aws security settings for the image. You can terminate ssl in the AWS LB, and route https traffic to http port 80 on your instance.

In this example the LB health check hits /health on port 80 which routes to the app server, so the health check validates both nginx and your app are breathing.

server {
  listen 80 default deferred;

  set $redirect_to_https 0;
  if ($http_x_forwarded_proto != 'https') {
    set $redirect_to_https 1;
  }
  if ($request_uri = '/health') {
    set $redirect_to_https 0;
  }
  if ($redirect_to_https = 1) {
    rewrite ^ https://www.example.com$request_uri? permanent;
  }
  ...
}