123

I want to redirect all the HTTP request to https request on ELB. I have two EC2 instances. I am using nginx for the server. I have tried a rewriting the nginx conf files without any success. I would love some advice on it.

informatik01
  • 16,038
  • 10
  • 74
  • 104
Amit Badheka
  • 2,677
  • 4
  • 19
  • 29
  • 1
    It seems that the Internet cannot agree on a single, complete and working solution to this problem. Hopefully you can get some help [here in my post](http://thehunk.blogspot.in/2017/11/how-to-force-redirect-http-to-https-in.html). I had to jump through hoops to come up with this, finally. – ADTC Nov 12 '17 at 00:08
  • 1
    [This ans](https://stackoverflow.com/a/51540255/1724809) has the latest solution, not the accepted anser – AsifM Feb 22 '19 at 12:17

12 Answers12

126

AWS Application Load Balancers now support native HTTP to HTTPS redirect.

To enable this in the console, do the the following:

  1. Go to your Load Balancer in EC2 and tab "Listeners"
  2. Select "View/edit rules" on your HTTP listener
  3. Delete all rules except for the default one (bottom)
  4. Edit default rule: choose "Redirect to" as an action, leave everything as default and enter "443" as a port.

Native redirect listener rule

The same can be achieved by using the CLI as described here.

It is also possible to do this in Cloudformation, where you need to set up a Listener object like this:

  HttpListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Port: 80
      Protocol: HTTP
      DefaultActions:
      - Type: redirect 
        RedirectConfig:
          Protocol: HTTPS
          StatusCode: HTTP_301
          Port: 443

If you still use Classic Load Balancers, go with one of the NGINX configs described by the others.

Ulli
  • 2,107
  • 1
  • 12
  • 10
  • 1
    Very useful to know its easier now. But this would be a better answer with more info about what to configure instead of just a link. – John Rees Aug 07 '18 at 20:20
  • 1
    @JohnRees edited the answer accordingly, hope this helps – Ulli Aug 09 '18 at 08:13
  • Nice. I upvoted you to get you to zero. You deserve more. – John Rees Aug 09 '18 at 09:26
  • 3
    @florian you seem to be using a Classic Load Balancer. Switch to Application Load Balancer to get that option – Ulli Nov 13 '18 at 08:09
  • how do I assign the Application Load Balancer to my instance ? (as there is no `instances` tab) – Florian Ludewig Nov 14 '18 at 18:14
  • @FlorianLudewig ALBs are a bit more complicated. They have an additional layer in between Load Balancer and instances, called Target Groups. So create a Target Group, add your instance to that, then edit your Load Balancer HTTPS listener to forward data to that Target Group. – Ulli Nov 16 '18 at 07:33
  • Is this work for forwarding http to https for asp.net core that host at ec2 with docker container, listening on port 5000/5001? – Richie86 Nov 20 '19 at 00:41
  • Would just like to add. If you already have a listener for Https, do not delete that. Instead add a Http listener with that single rule to redirect to Https – Wiz May 19 '21 at 16:18
  • Awesome answer. I was using the web-interface and it took me forever to realize that this setting can only be changed on the EC2 interface of loadbalancers. You can see rules in your Elastic Beanstalk under a specific environment's configuration in the Load Balancers tab... But this is NOT where you want to be! You actually want to go through the EC2 -> Load Balancers and select the load balancer in question. The rules will be in the tabs below the main window. – Eric Jun 22 '21 at 21:00
110

ELB sets X-Forwarded-Proto header, you can use it to detect if original request was to HTTP and redirect to HTTPS then.

You can try this in your server conf:

if ($http_x_forwarded_proto = 'http') {
    return 301 https://yourdomain.com$request_uri;
}

Take a look at ELB docs.

Dmitry Mukhin
  • 6,649
  • 3
  • 29
  • 31
  • 3
    Where does one do this configuration? – ericpeters0n Mar 10 '16 at 00:44
  • 2
    @ericpeters0n the snippet in the answer is for `nginx` config, but the principle is applicable to any web server. – Dmitry Mukhin Mar 10 '16 at 09:26
  • 1
    if you're using beanstalk with passenger-standalone, follow this link for how-to on changing nginx configuration. http://qiita.com/tak_nishida/items/cf30a2d373744943b943 – Yeonho Apr 15 '16 at 06:35
  • 3
    Make sure you have HTTP and HTTPS listeners on your load balancer. – Gavin Palmer May 13 '16 at 01:19
  • How can I do this when balancing TCP connections with ELB? – boom Jul 27 '16 at 04:36
  • This works well, thanks! Also, straight from the horse's mouth (and if you want to check via an .htaccess file): https://aws.amazon.com/premiumsupport/knowledge-center/redirect-http-https-elb/ – cdwyer Oct 28 '16 at 15:07
  • I was confused adding a server block to configure 443 ssl but it's not necessary. – Francisco Quintero Mar 27 '17 at 16:31
  • How to achieve this for Tomcat server? – MasterCode Aug 22 '17 at 06:04
  • @MasterCode, you probably will be better off if you look for the tomcat specific question on how to make conditional redirects depending on incoming headers. – Dmitry Mukhin Aug 25 '17 at 14:42
  • This solution not worked for me , i am using passenger standalone , i created custom file `/config/nginx_custom_config.conf` for include this code , and included this file in `$(passenger-config about resourcesdir)/templates/standalone/config.erb` first line of `server {**}`, but it is going in infinite loop. am i doing something wrong ? – Vishal Nov 08 '17 at 11:39
  • If you are on Elastic Beanstalk, then https://stackoverflow.com/a/38751648/888970 is a great answer for how to modify your apache configs to do this. – Rahul Gupta-Iwasaki Jan 17 '18 at 09:51
  • Is there a solution where we don't have to change the backend at all, just with AWS? – devssh May 21 '18 at 04:54
  • @devssh nope, AWS own "official" solution involves redirect on your backend: https://aws.amazon.com/premiumsupport/knowledge-center/redirect-http-https-elb/ – Dmitry Mukhin May 30 '18 at 10:35
  • So what this means is I have to allow an unknown service to run on my container to allow https that will spy on me. hmmm – devssh May 30 '18 at 11:01
  • No that does not mean that at all. How are you coming to this bizarre conclusion? – Dmitry Mukhin May 30 '18 at 16:27
  • Hi, server means the instances under the load balancer right? It seems that I can't login directly to the load balancer instance. – Rav Jan 02 '19 at 04:38
  • 1
    @Ronald, by server conf in the response I mean nginx server on ec2 instances that are running behind ELB. – Dmitry Mukhin Jan 30 '19 at 10:37
37

I had the same problem, in my situation HTTPS was handled entirely by ELB and I didn't know my source domain ahead of time so I ended up doing something like:

server {
  listen 81;
  return 301 https://$host$request_uri;
}

server {
  listen 80;
  # regular server rules ...
}

And then of course pointing the ELB 'https' to the instance port 80 and then the 'http' route to the instance port 81.

TylerFowler
  • 568
  • 4
  • 8
16

The Amazon Elastic Load Balancer (ELB) supports a HTTP header called X-FORWARDED-PROTO. All the HTTPS requests going through the ELB will have the value of X-FORWARDED-PROTO equal to “HTTPS”. For the HTTP requests, you can force HTTPS by adding following simple rewrite rule. For me it works fine!

Apache

You can add following lines in your .htaccess file:

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI}

Or if you use vhost.conf for managing multiple domains in same EC2 web server then you can add following to the vhost.conf (add it to the domain you want to use https for it):

<VirtualHost *:80>
...
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI}
...
</VirtualHost>

IIS

Install IIS Url-Rewrite module, using the configuration GUI add these settings:

<rewrite xdt:Transform="Insert">
<rules>
<rule name="HTTPS rewrite behind ELB rule" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{HTTP_X_FORWARDED_PROTO}" pattern="^http$" ignoreCase="false" />
</conditions>
<action type="Redirect" redirectType="Found" url="https://{SERVER_NAME}{URL}" />
</rule>
</rules>
</rewrite>

Read more here

Iman Sedighi
  • 7,624
  • 4
  • 48
  • 55
  • We had the issue of having our instance redirect normal http traffic because the header was not even present. I solve it by making the condition: `RewriteCond %{HTTP:X-Forwarded-Proto} !(https|^$)` – natronite Jul 27 '16 at 09:15
  • This is causing infinite redirects. I am using IIS with windows server. – It's a trap Oct 25 '16 at 04:56
  • @It'satrap : For IIS if it didn't work then try the script in this URL: http://stephen.genoprime.com/2012/01/01/aws-elb-ssl-with-iis.html – Iman Sedighi Oct 25 '16 at 12:29
5

The htaccess solutions above caused ELB health check to fail. I had some trouble finding the solution until I discovered an article online in which someone had the same issues I had. His solution was to add this to the beginning of the htaccess file instead:

RewriteEngine on 
RewriteCond %{HTTP:X-Forwarded-Proto} ^http$
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

To allow this and other local requests over HTTP while redirecting external requests through the ELB to HTTPS, adjust the rewrite condition to match on http instead of a negative match on https.

Source: Redirecting HTTP to HTTPS with AWS and ELB

omikes
  • 8,064
  • 8
  • 37
  • 50
  • "adjust the rewrite condition to match on http instead of a negative match on https" that's the part I was trying to fix. Thank you! – Merricat Mar 21 '19 at 21:12
4

It may not be the solution you might be looking for, but another option could be to use AWS CloudFront in addition to ELB. CloudFront gives the option to redirect all incoming HTTP traffic to HTTPS.

MojoJojo
  • 3,897
  • 4
  • 28
  • 54
  • 1
    See [Example: Generating an HTTP Redirect (Generated Response)](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html#lambda-examples-http-redirect). – Amir Aug 08 '17 at 12:00
4

Based on @Ulli's answer If you want to configure it using Terraform, here is an example >

resource "aws_alb_listener" "web" {
  load_balancer_arn = "${aws_alb.web.arn}"

  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

Source

callmemath
  • 8,185
  • 4
  • 37
  • 50
3

I had strange problem with nginx and ELB configuration. My setup included 3 different services inside one nginx behind ELB. And I had mixed content issue: when your request to ELB is https, but inside ELB http only, and server create relative path to static using http, so browser fails with 'mixed content' issue. And I must create solution for both http/https work without any redirects.

Here is config located in nginx/conf.d/ folder:

# Required for http/https switching
map $http_x_forwarded_port $switch {
  default   off;
  "80"    off;
  "443"   on;
}

This means that we will have knowledge what real client protocol is. As you can see, we will have it in $switch var. And at this moment you use this in all location where you need it:

location ~ /softwareapi/index.php {
  fastcgi_param HTTPS $switch;
  .. other settings here ..
}

With HTTPS setting php application will automatically detect right protocol and carefully build relative path for preventing mixed content issue.

Best regards.

3

I just went through the process and tested redirects (from ec2 instance shell) with command

curl -Iv [your url]

ex: curl -Iv http://example.com

Requirement

  1. set up Hosted zone for DNS and Name server in AWS Route 53

  2. get certificate using AWS Certificate Manager

  3. add listener on load balancer for port 443 pick the certificate from 2. and the SSL

    • Elastic Beanstalk --> click environment --> Configuration --> Find Load Balancer then click Edit --> Add listener; use SSL Policy of 2016-08 (others may give errors)

What I did is:

  1. Redirect http://yourwebsite.com --> https://www.yourwebsite.com (step 2)
  2. Redirect http://www.yourwebsite.com --> https://www.yourwebsite.com (step 2)
  3. Redirect https://yourwebsite.com --> https://www.yourwebsite.com (step 3)

Steps

1. Went to EC2 Load Balancer

2. Go in to Listener ID HTTP : 80 (Click View/edit rules underneath the Rules column)

Edit default action: (click pencil icon on top, use "Switch to full URL", it will be greyed out until you enter #{port})

  1. change THEN block to Redirect to https://#{host}:443/#{path}?#{query}
  2. Status code:HTTP_301

Add one more action (click + sign on top)

  1. choose IF block Host header is yourwebsite.com
  2. change THEN block to Redirect to https://www.#{host}:443/#{path}?#{query}
  3. Status code:HTTP_301

enter image description here

3. Go back and go in to Listener ID HTTPS : 443 (Click View/edit rules)

Add one more action (click + sign on top)

  1. choose IF block Host header is yourwebsite.com
  2. change THEN block to Redirect to https://www.#{host}:443/#{path}?#{query}
  3. Status code:HTTP_301

Do not edit default action on HTTPS

enter image description here

xinthose
  • 3,213
  • 3
  • 40
  • 59
ACHEER
  • 31
  • 2
0

Here you go with exact answer : Create this file with following name and put the following content in it.

redirect-to-https.json

[
  {
      "Type": "redirect",
      "RedirectConfig": {
          "Protocol": "HTTPS",
          "Port": "443",
          "Host": "#{host}",
          "Path": "/#{path}",
          "Query": "#{query}",
          "StatusCode": "HTTP_301"
      }
  }
]

Use this awscli command to create a listener rule on port 80 with HTTP protocol which will redirect all traffic to HTTPS port.

aws elbv2 create-listener --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:12345678910:loadbalancer/app/demo1-alb/b4d5fbc78965417f --port 80 --protocol HTTP --default-actions file://redirect-to-https.json

SIddharth
  • 11
  • 3
0
  1. Navigate to the AWS Load Balancer Dashboard.
  2. Visit the cert-manager attached to the Load Balancer Dashboard.
  3. Open Settings for HTTP:80
  4. Open Edit listener of HTTP:80 of aws Dashboard.
  5. Remove the default details from Redirect info tab details.
  6. Add New Rule with Protocol : HTTPS and PORT: 443
  7. And Add/Select Status 301-Permanently moved.
  8. Update the settings and wait for sometime, Redirect should work when we type http with website it will redirect to the https.
Pravin Pagare
  • 159
  • 1
  • 3
-2

Create a file .ebextensions/00_forward_http_to_https.config with the following content:

files: 
  /tmp/deployment/http_redirect.sh:
    mode: "000755"
    content: |
      APP_URL=`/opt/elasticbeanstalk/bin/get-config environment --output yaml | grep -oP 'APP_URL: \K([^\s)\"](?!ttp:))+'`
      sed -ie 's@$proxy_add_x_forwarded_for;@$proxy_add_x_forwarded_for;\n        if ($http_x_forwarded_proto = 'http') { return 301 https://'"$APP_URL"'$request_uri; }@' /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf

container_commands:
  http_redirect:
    command: "/tmp/deployment/http_redirect.sh"

Make sure to set the APP_URL environment variable from the AWS management console beforehand.

Andres
  • 161
  • 1
  • 5
  • How can I do this when balancing TCP connections with ELB? – boom Jul 27 '16 at 04:37
  • 1
    I don't see where your answer fits the question ... you are talking about elastic bean stalk and the question is about nginx inside an EC2. – jvarandas Aug 15 '16 at 19:29