81

I can't seem to force https on the free usage tier of elastic beanstalk.

I have tried the following suggestion at How to force https on amazon elastic beanstalk without failing the health check

Using this Apache rewrite rule

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{REQUEST_URI} !^/status$ 
RewriteCond %{REQUEST_URI} !^/version$ 
RewriteCond %{REQUEST_URI} !^/_hostmanager/ 
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

When I try that, http requests do not get redirected to https as I would like. Instead, the http page loads normally. I've also tried to use the X-Forwarded-Port header with the same result.

I've also tried the following rewrite rule

RewriteCond %{SERVER_PORT} 80
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

And this rule causes a redirect loop. So it would seem that the apache rewrite rules don't pick up the Elastic Load Balancer headers X-Forwarded-Port and X-Forwarded-Proto, but also a redirect loop isn't what I am going for either.

Please help. I am new to AWS, Elastic Beanstalk, and not very familiar with Apache rules. I am not too sure where to go from here. Thanks.

Community
  • 1
  • 1
landland
  • 1,997
  • 3
  • 18
  • 25
  • After sleeping on it, it appears the rewrite rules now detect the X-Forwarded-Proto header. Not entirely sure why, but it works now. – landland Feb 05 '13 at 17:52
  • 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
  • Can anyone know how can I change it to redirect www to non-www RewriteEngine On RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L] – Mahendra Garg Sep 29 '18 at 16:09
  • Also see [How can I redirect HTTP requests to HTTPS using an Application Load Balancer?](https://aws.amazon.com/premiumsupport/knowledge-center/elb-redirect-http-to-https-using-alb/) on Amazon's knowledge center. No server config required on the instance. – djvg Jan 26 '21 at 08:35

22 Answers22

181

This answer assumes you have already enabled https in the load balancer security group, added the SSL certificate to the load balancer, have both ports 80 and 443 being forwarded by the load balancer, and pointed your domain name at the Elastic Beanstalk environment with Route 53 (or equivalent DNS service).

Option 1: Do the redirect with Apache

This is only possible if you are on an Elastic Beanstalk environment that uses Apache. It may not work for a docker-based deployment.

Amazon Linux 2

Most AWS Linux version 2 based platforms have the option to pick Apache as your proxy host. This can be done by going to "Configuration" > "Software" > "Container Options" and setting "Proxy Server" to "Apache".

Having done that, add a configuration file named .platform/httpd/conf.d/ssl_rewrite.conf to your codebase (relevant AWS docs) with the following contents:

RewriteEngine On
<If "-n '%{HTTP:X-Forwarded-Proto}' && %{HTTP:X-Forwarded-Proto} != 'https'">
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</If>

Amazon Linux 1

All you need to do is add the following to one of your .config files in the .ebextensions directory of your project:

files:
    "/etc/httpd/conf.d/ssl_rewrite.conf":
        mode: "000644"
        owner: root
        group: root
        content: |
            RewriteEngine On
            <If "-n '%{HTTP:X-Forwarded-Proto}' && %{HTTP:X-Forwarded-Proto} != 'https'">
            RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
            </If>

Explanation

This is moderately straight forward outside of Elastic Beanstalk. One usually adds an Apache rewrite rule like the following:

RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

Or, if behind a load balancer, like we are in this case:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]

However, these configurations only work within a <VirtualHost> block. Changing the RewriteCond to an <If> block allows it to work properly outside of a <VirtualHost> block, allowing us to put in in a standalone Apache config file. Note that standard Apache setup on CentOS (including the setup on ElasticBeanstalk) inculdes all files matching /etc/httpd/conf.d/*.conf, which matches the file path where we are storing this file.

The -n '%{HTTP:X-Forwarded-Proto}' part of the condition prevents it from redirecting if you are not behind a load balancer, allowing you to have shared configuration between a production evironment with a load balancer and https, and a staging environment that is single instance and does not have https. This is not necessary if you are using load balancers and https on all of your environments, but it doesn't hurt to have it.

Option 2: Do the redirect with the ALB

This is only possible if you are using an Application Load Balancer. Amazon has instructions for how to do that here: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https-httpredirect.html

All you need to do is add the following to one of your .config files in the .ebextensions directory of your project to replace the http listener with a redirect:

Resources:
 AWSEBV2LoadBalancerListener:
  Type: AWS::ElasticLoadBalancingV2::Listener
  Properties:
    LoadBalancerArn:
      Ref: AWSEBV2LoadBalancer
    Port: 80
    Protocol: HTTP
    DefaultActions:
      - Type: redirect
        RedirectConfig:
          Host: "#{host}"
          Path: "/#{path}"
          Port: "443"
          Protocol: "HTTPS"
          Query: "#{query}"
          StatusCode: "HTTP_301"

Bad solutions I have seen

I have seen a lot of bad solutions to this problem, and it is worth going through them to understand why this solution is necessary.

  1. Use Cloudfront: Some people suggest using non-cached Cloudfront setup in front of Elastic Beanstalk to do the HTTP to HTTPS redirect. This adds a whole new service (thus adding complexity) that isn't exactly appropriate (Cloudfront is a CDN; it's not the right tool for forcing HTTPS on inherantly dynamic content). Apache config is the normal solution to this problem and Elastic Beanstalk uses Apache, so that's the way we should go.

  2. SSH into the server and...: This is completely antithetical to the point of Elastic Beanstalk and has so many problems. Any new instances created by autoscaling won't have the modified configuration. Any cloned environments won't have the configuration. Any number of a reasonable set of environment changes will wipe out the configuration. This is just such a bad idea.

  3. Overwrite the Apache config with a new file: This is getting into the right realm of solution but leaves you with a maintenance nightmare if Elastic Beanstalk changes aspects of the server setup (which they very well may do). Also see the problems in the next item.

  4. Dynamically edit the Apache config file to add a few lines: This is a decent idea. The problems with this is that it won't work if Elastic Beanstalk ever changes the name of their default Apache config file, and that this file can get overwritten when you least expect: https://forums.aws.amazon.com/thread.jspa?threadID=163369

Zags
  • 26,675
  • 10
  • 77
  • 107
  • 3
    Excellent answer, this worked perfectly. I did not have an .ebextensions directory in my project yet, so I made one and put your config in an arbitrarily named .conf file. I was able to keep the regular port disabled in the settings on the elastic beanstalk console, which seems ideal. – Tyler Aug 13 '16 at 19:12
  • Great answer, thanks! After playing around with overwriting my wsgi.conf and still having issues, this answer worked and seems like the most robust. – benedwards44 Aug 25 '16 at 23:29
  • This is great. Using the `` block is really slick – booshong Aug 26 '16 at 03:55
  • 4
    This is a fantastic answer, really needs to be at the top of the page. @landland you should accept this answer. – gtd Aug 27 '16 at 01:27
  • 1
    Excellent and clean answer, worked seamlessy for me. I added `R=301` in order to send a permanent redirect. – LoicAG Sep 01 '16 at 09:31
  • 2
    I regret that I have only one upvote to give. Huge problem is that the AWS forums have an incorrect answer for this! – Cfreak Sep 01 '16 at 21:17
  • Any way to add this to an existing deployment? Also, does the .ebextensions folder have to be added to my git repo to be deployed/used, or is that folder used regardless (while the actual app files MUST be in git when doing a node.js deploy anyway)? – rainabba Sep 15 '16 at 20:56
  • 1
    @rainabba These directions work for both new and existing deployments. The .ebextensions folder needs to be included in the files uploaded to elastic beanstalk. If you are using the EB CLI, then yes, they do need to be checked in to git. – Zags Sep 16 '16 at 01:01
  • Excellent answer. After days of struggling with this, this worked, and I got rid of my Cloudfront instance which as you pointed out is a "bad idea." Now I have an extra problem. I have one subdirectory that I do not want to be https. I have tried placing RewriteCond %{REQUEST_URI} !^/blog/ immediately preceding the RewriteRule and that works if I try to access http://domain.com/blog/directory but not http://domain.com/blog/directory/subdirectory. Any suggestions? I'd like to place a condition in the IF statement to handle this, but I have not found the solution. If it matters the /blog/ is WP – greco.roamin Sep 22 '16 at 21:50
  • @greco.roamin The easiest thing to do is host the blog off its own subdomain. You could also add an && clause to the if statement. This is complicated enough to warrant it's own stackoverflow question. – Zags Sep 23 '16 at 20:57
  • @zags Thanks, I have thought of a subdomain, and even tried it and it worked fine. However, that does not give me the SEO bump I need (google's rules). I have posted this topic as you suggest, and if you could expand on the idea of an && clause I'd appreciate it. I tried a few && clause ideas but still haven't come up with the solution. Thanks, here is the new post http://stackoverflow.com/questions/39650843/codeigniter-with-wordpress-https-with-http-on-aws-with-load-balancer-wordpres – greco.roamin Sep 25 '16 at 16:56
  • Very good answer if you're using a platform that utilizes Apache 2.4. If you're using the Tomcat platform (Apache 2.2), you have to completely override httpd/conf.d/elasticbeanstalk/00_application.conf file. I ended up copying this file off an existing environment and inserting the Rewrite rules since they have to be within the element. There are some notes about how to do that here: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-tomcat-platform.html – Domenic D. Dec 15 '16 at 18:28
  • 2
    for some reason this doesn't seem to work for me. the `ssl_rewrite.conf` file is created (verified with `eb ssh`) but no redirect happens. :S – mb21 Apr 10 '17 at 09:40
  • @mb21 I'd need more details about your setup to help. You should post your own question. – Zags Apr 10 '17 at 18:04
  • @Zags thanks for your reply! should pretty much be a duplicate of this: http://stackoverflow.com/questions/37427970/forcing-https-in-elasticbeanstalk-with-certificate-from-acm (I just used the default elastic beanstalk rails stuff and https works now but the redirect from http to https doesn't) – mb21 Apr 11 '17 at 12:00
  • @mb21 I recommend posting your own question with as many details as you can. I don't know of any reason why this wouldn't work with the default config – Zags Apr 11 '17 at 15:03
  • @mb21 Ah, the problem is that Ruby uses nginx rather than Apache. I'm surprised they would do that. There may be a way to write an equivalent nginx extra config file, but I don't have one on hand that does the trick – Zags Apr 13 '17 at 04:47
  • Beanstalk does not necessarily use Apache. Nginx is another supported proxy. Besides, some of our Node.js apps run without a proxy on Beanstalk. – Onur Yıldırım Sep 11 '17 at 23:07
  • How can I make this work with a load-balanced application in ELB with _64bit Amazon Linux 2016.03 v2.1.1 running Tomcat 8 Java 8_? I've added the `.ebextensions` folder to the root of the WAR archive, but it didn't do anything. Both HTTP and HTTPS serve the same content but there's **no redirect** of the first to the second happening. – ADTC Nov 11 '17 at 19:37
  • @ADTC This should be posted as it's own question – Zags Nov 13 '17 at 19:05
  • @ADTC Your question doesn't have an obvious answer and likely requires extended discussion. The comments section of an answer is an inappropriate medium for this. If you post it as a separate question, it can both get the attention it deserves and be found by other users in the future. – Zags Nov 14 '17 at 14:07
  • Thanks for this! It's worth making clear that you must use *Apache*. I had nginx instead and it doesn't work for that! – Wayneio Nov 17 '17 at 12:26
  • Apache recommend changing the configuration of your server, and not using Rewrite if you can help it. – Chuck Le Butt Feb 15 '18 at 15:37
  • 1
    For info on the background steps before this, see https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https-elb.html – Zach Saucier Jul 25 '18 at 01:55
  • Note that if you are deploying your application to different environments (dev, stage, prod for example), this will apply it to all of them. You can modify this answer so that an env var is used to switch the redirection on/off (see my answer way below) – nbeuchat Apr 21 '19 at 17:18
  • @nbeuchat My answer already supports not doing an https redirect for selective environments. You simply have them be single instance environments rather than load balanced (the redirect is only done based on the forwarded protocol, and without a load balancer, there is no forwarding). Any environment (such as staging) that need to be load balanced to mimic production should also have https to mimic production. – Zags Apr 21 '19 at 17:42
  • @Zags thanks. That's strange, that's exactly the setup we had (dev being a single instance without a load balancer) and your approach didn't work as we always had a redirection. I'll go back in our old config to see if there is an obvious reason as to why it was the case. – nbeuchat Apr 22 '19 at 11:24
  • make sure you have port 80 listener on your load balancer as well as 443 for this solution to work – Ehsan Jan 16 '20 at 21:48
  • Great answer and it's still working in 2020 with Django and Python 3.6. I just wish I had read this answer before as it's so much easier than the previous way I was doing it! – data101 Jul 13 '20 at 18:05
  • This it working great for me on my .com domains! However, for some reason it doesn't seem to redirect correctly for a TLD of .online. Does this sound correct? Or am I missing something? – James Parker Nov 10 '20 at 18:15
  • @JamesParker There's nothing here that should be specific to .com TLDs. If you're still having trouble, I recommend posting as it's own question – Zags Nov 10 '20 at 19:16
16

EDIT: While I love this answer, it is now very old. AWS has come up with new services (like Certificate Manager) that make part of this answer obsolete. Additionally, using the .ebextensions folder with Apache is a cleaner way to handle this redirect as explained above.

If you are hosting your website on S3, parts of this answer may still be useful to you.


This worked for me:

  1. Upload the certificate to AWS using the aws console command. The command structure is:

    aws iam upload-server-certificate --server-certificate-name CERTIFICATE_NAME --certificate-body "file://PATH_TO_CERTIFICATE.crt" --private-key "file://YOUR_PRIVATE_KEY.pem" --certificate-chain "file://YOUR_CERTIFICATE_CHAIN.ca-bundle" --path /cloudfront/
    
  2. In your Elastic Beanstalk application, go to Configuration -> Network Tier -> Load Balancing and click the gear icon.

  3. Select Secure listener port as 443. Select Protocol as HTTPS. Select the CERTIFICATE_NAME from step 2 for SSL certificate ID. Save the configuration.

  4. Go to your Console. Click EC2 Instances. Click Load Balancers. Click through the load balancers. Click Instances and scroll down to see the EC2 instances assigned to that load balancer. If the EC2 instance has the same name as your Application URL (or something close), take note of the DNS Name for the load balancer. It should be in the format awseb-e-...

  5. Go back to your Console. Click CloudFront. Click Create Distribution. Select a Web distribution.

  6. Set up the distribution. Set your Origin Domain Name to the load balancer DNS name you found in step 5. Set the Viewer Protocol Policy to Redirect HTTP to HTTPS. Set Forward Query Strings to Yes. Set Alternate Domain Names (CNAMEs) to the URL(s) you want to use for your application. Set SSL Certificate to the CERTIFICATE_NAME you uploaded in step 2. Create your distribution.

  7. Click on your distribution name in CloudFront. Click Origins, select your origin, and click Edit. Ensure your Origin Protocol Policy is Match Viewer. Go back. Click Behaviors, select your origin, and click Edit. Change Forward Headers to Whitelist and add Host. Save.

Note: I wrote a longer guide as well.

Community
  • 1
  • 1
Adam Link
  • 2,705
  • 4
  • 26
  • 44
  • Did exactly this, but it gives me a "The request could not be satisfied." "CloudFront wasn't able to connect to the origin. ", only when I whitelist the host header. If i set forward headers to none, then it works, but it doesn't redirect to https, all http requests stay http. Any thoughts? – Vlad Dec 08 '15 at 16:59
  • @Adam Can you please paste your whole elasticbeanstalk.conf file here? or give me a link of it? – thekosmix Apr 28 '16 at 05:39
  • @thekosmix The `elasticbeanstalk.conf` file shouldn't really come into play here unless you are overriding settings in the guide above. – Adam Link Apr 28 '16 at 14:25
  • But the ec2 instances(their DNS) within the load balancer are ephemeral, isn't it? I'm not sure you've got so many up-votes for a totally flawed solution. – themihai May 18 '16 at 10:28
  • @themihai That's not actually correct - the solution doesn't use the EC2 DNS or IP (which are ephemeral). The DNS URL you are getting is static to the environment. The EC2 step is to get the DNS URL for use in step 6, where you are linking the environment to the CloudFront distribution. The solution above may not work, since it is a year old now, but it certainly did when I posted it. – Adam Link May 18 '16 at 20:48
6

The most upvoted doesn't work for me.. the <If> directive only works with Apache 2.4+, but ElasticBeanstalk has version 2.2.x.

So, following the same advice as above. Create a file called .ebextensions/https_rewrite.config with the following content

files:
    "/etc/httpd/conf.d/ssl_rewrite.conf":
        mode: "000644"
        owner: root
        group: root
        content: |
            LoadModule rewrite_module modules/mod_rewrite.so
            RewriteEngine On
            # This will enable the Rewrite capabilities
            RewriteCond %{HTTPS} !=on
            # This checks to make sure the connection is not already HTTPS
            RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]

This seems to work for me.

On how to build this file into your WAR file, see this answer

Community
  • 1
  • 1
Marc
  • 61
  • 1
  • 1
5

With the new Application Load Balancers you can do this fairly trivially now...

Ensure you setup one of these at the time you setup an EB environment (still defaults to classic load balancer I believe). You could not change the type once the environment is created, so recreate it

Once this is done, go to your EC2 settings -> Load Balancers. Click on the load balancer you created for your EB environment. You must ensure that you have setup a HTTPS listener prior to this task so make sure you listen on HTTPS 443 with an SSL cert and forward traffic to your instances with HTTP on 80.

Then add a new listener which listens on HTTP and add a default action of "Redirect to:". Make sure you set HTTPS as the protocol, 443 as the port, "Original host, path, query" as the option and finally 301 as the HTTP response code.

Once this listener is added ensure that you update your EC2 Load Balancer security group to accept both HTTPS and HTTP connections, you will see small warning sign on the listener to remind you!

Chris

Kristian
  • 628
  • 5
  • 15
  • Thanks, I got this to work for my www. route but not the naked domain. Any suggestions on why that might be? – Chris Mar 02 '20 at 23:55
4

Edit: Zags solution is more general and correct. I recommend it over mine (which is specific to a python env)

Here's a clean and quick solution that I came up with that avoids hacking wsgi.conf or using CloudFront

In your .ebextensions/some_file.config:

# Redirect HTTP to HTTPS
  "/etc/httpd/conf.d/https_redirect.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      <Directory /opt/python/current/app/>
      RewriteEngine on
      RewriteCond %{HTTP:X-Forwarded-Proto} ^http$
      RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
      </Directory>

I feel like this is too easy, but seems to be working fine.

Also note that I am explicitly redirecting HTTP instead of "not HTTPS".

Community
  • 1
  • 1
booshong
  • 687
  • 5
  • 20
  • So I got this working on one EBS environment. /etc/httpd/conf.d/https_redirect.conf exists and it redirects to https. The problem is on a second environment, setup exactly the same way, the file /etc/httpd/conf.d/https_redirect.conf is NOT there. Any ideas? – Nitzan Wilnai Aug 15 '16 at 23:09
  • @NitzanWilnai `/etc/httpd/conf.d/https_redirect.conf` doesn't have to exist, see [answer](http://stackoverflow.com/a/38751749/1821593) – Anatoly Vasilyev Aug 25 '16 at 13:24
  • 1
    Adding a file to /etc/httpd/conf.d was a great idea. This helped me get to the general solution (http://stackoverflow.com/a/38751749/2800876) – Zags Aug 30 '16 at 21:34
4

I am trying to redirect an elastic beanstalk with loadbalancer in 2018. None of the above answers works in my environment. Several issues I encoutered:

  1. I was trying the most voted answer, but my tomcat is version 2.7. It does not support .

  2. I was using container_commands and copy the 00_applications setting. AWS simply ignores it.

So finally I got it working by reading this: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-tomcat-proxy.html

Here is what I do:

I recreated the folder structure:

.ebextensions 
 - httpd
  -conf.d
   -ssl.conf

And then this is the content of ssl.conf

<VirtualHost *:80>
  RewriteEngine on
  RewriteCond %{HTTP:X-Forwarded-Proto} =http
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  <Proxy *>
    Order Allow,Deny
    Allow from all
  </Proxy>
  ProxyPass / http://localhost:8080/ retry=0
  ProxyPassReverse / http://localhost:8080/
  ProxyPreserveHost on

  ErrorLog /var/log/httpd/elasticbeanstalk-error_log
</VirtualHost>

Hope this will help.

sliks
  • 91
  • 8
3

It's work for me with the next command:

RewriteCond %{HTTP:X-Forwarded-Port} !=443

and without the https check:

RewriteCond %{HTTP:X-Forwarded-Proto} !https

It's look like ELB change the value of X-Forwarded-Proto to http (even on TCP protocol).

Roy Shmuli
  • 4,489
  • 1
  • 21
  • 38
  • This should be the accepted answer. The headers are documented so you can rely on them. http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/x-forwarded-headers.html – themihai May 18 '16 at 10:44
3

None of the above answers worked for me but some helped me to figure out the answer that worked for me Also I found the below url which helped http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-tomcat-platform.html

I created the file structure mentioned in above url to change 2 files httpd.conf 00_application.conf

copy the whole httpd.conf from your instance and put it in your code under .ebextention under the folder structure mentioned in the above link. Then just add below line to that file in your project

LoadModule rewrite_module modules/mod_rewrite.so

Do that same for 00_application.conf, copy it from your instance and place it in your codebase under .ebextention under httpd/conf.d/elasticbeanstalk/00_application.conf Now edit this file and add the below between VirtualHost

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

Now deploy your code It should work.

A Paul
  • 7,473
  • 2
  • 24
  • 53
2

I had a difficult time figuring this out so after I came up with a solution I wrote a detailed explanation of my solution to hopefully help someone else. This is specific to Tomcat 8, Apache2, and Spring Boot app. There are really useful ebextension examples in the AWS labs github.

Summary of what worked for me:

  1. Create a file at /src/main/webapp/.ebextensions/httpd/conf.d/elasticbeanstalk.conf
  2. Add rewrite conds/rules being careful to include "LoadModule rewrite_module modules/mod_rewrite.so"
  3. Deploy to AWS EBS

Here is an example Spring Boot app.

yerself
  • 83
  • 2
  • 8
2

On elastic beanstalk you can just add your on configuration so that AWS overwrite their, it will allow you to overwrite the web-server configuration and submit your own configuration.

Simply add the following file under the path: .ebextensions\httpd\conf.d

File content:

<VirtualHost *:80>
   LoadModule rewrite_module modules/mod_rewrite.so

   RewriteEngine On
   RewriteCond %{HTTP:X-Forwarded-Proto} !https
   RewriteCond %{HTTP_USER_AGENT} !ELB-HealthChecker
   RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

   <Proxy *>
     Order deny,allow
     Allow from all
   </Proxy>

   ProxyPass / http://localhost:8080/ retry=0
   ProxyPassReverse / http://localhost:8080/
   ProxyPreserveHost on

   ErrorLog /var/log/httpd/elasticbeanstalk-error_log

</VirtualHost>

The '.ebextensions' is the standard configuration folder in AWS and the rest just point to which file and folder you wish to overwrite. If the file or folder doesn't exist simple create them.

Adi
  • 1,911
  • 18
  • 25
1

I have following configurations for elastic beanstalk (64bit Amazon Linux 2016.09 v2.3.1 running Tomcat 8 Java 8). I created a directory .ebextensions and added a .config YAML file with the rewrite conditions

Zagas solution described above (which is very complex) doesn't work for me.

  1. Because "If" condition is unknown
  2. Because of Apache 2.2 I don't have mod_rewrite.so included in my httpd.conf file

This solution make more sense for me, but also this doesn't work. Nothing happens, and I cannot see file "ssl_rewrite.conf" under "conf.d" directory.

Third tried solution was to add "run.config" and "ssl_rewrite.conf" files under ".ebextendsion" directory.

run_config contains

container_commands:
copy-config:
command: "cp .ebextensions/ssl_rewrite.conf /etc/httpd/conf.d"

ssl_rewrite.conf contains

LoadModule rewrite_module modules/mod_rewrite.so
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule . https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]

ssl_rewrite.conf is created under "conf.d" direcotry but redirect from http to https doesn't work.

The only worked solution for me was to add the following lines in "/etc/httpd/conf.d/elasticbeanstalk/00_application.conf"

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

but this is a temporary solution and if a machine is replaced my https redirection is gone.

Community
  • 1
  • 1
aelve
  • 119
  • 1
  • 8
  • _"if a machine is replaced my https redirection is gone"_ I think you could use the same trick shown in Zags' answer to write the file automatically when ELB deploys the application in a new instance. Basically, give your file path under `files:`, the file content under `content: |` and set the appropriate mode, owner and group. ELB will then create the file for you, automatically. – ADTC Nov 11 '17 at 20:16
  • I have used the above method (in my comment) to deploy this file as part of application (instead of writing it directly into the current instance). I checked through SSH that the file exists. However, it also didn't work for me, despite my setup being very close to yours: _64bit Amazon Linux 2016.03 v2.1.1 running Tomcat 8 Java 8_ One thing though, the file didn't exist at all originally - it was created new. Should I be editing `/etc/httpd/conf.d/elasticbeanstalk.conf` instead? – ADTC Nov 11 '17 at 20:44
1

Just in case anybody is still struggling:

I've struggled for some time and finally, I've found a GitHub (from AWS team) with all AWS configs and the example below works for the HTTP>HTTPS redirection for Apache 2.2. (For configs for Apache 2.4 and Nginx please see the link below).

Apache 2.2

  1. Create a file in the root directory of your app: YOUR_PROJECT_ROOT/.ebextensions/httpd/conf.d/elasticbeanstalk.conf (In case of using IntelliJ / Java make sure it go added to the final .WAR artifact)

  2. Add the following lines to enable the redirection in the virtual host:

    <VirtualHost *:80>
        LoadModule rewrite_module modules/mod_rewrite.so
        RewriteEngine On
        RewriteCond %{HTTP:X-Forwarded-Proto} !https
        RewriteCond %{HTTP_USER_AGENT} !ELB-HealthChecker
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
    
        <Proxy *>
            Order deny,allow
            Allow from all
        </Proxy>
    
        ProxyPass / http://localhost:8080/ retry=0
        ProxyPassReverse / http://localhost:8080/
        ProxyPreserveHost on
    
        ErrorLog /var/log/httpd/elasticbeanstalk-error_log
    </VirtualHost>
    

For more examples for Apache 2.4 and Nginx please visit this GitHub repository:

https://github.com/awsdocs/elastic-beanstalk-samples/tree/master/configuration-files/aws-provided/security-configuration/https-redirect/java-tomcat

Also, there is plenty more useful configuration and examples available.

Regards

Joao Gavazzi
  • 1,330
  • 13
  • 7
1

Enabling HTTPS through an environment variable

I needed to enforce HTTPS only for our production environment, and not for the development and staging ones which are also on Elastic Beanstalk but do not use a load balancer (and therefore cannot be assigned a certificate directly).

I use an environment variable USE_HTTPS. We copy the the ssl_rewrite.conf file if and only if USE_HTTPS is set to true.

.ebextensions/files/ssl_rewrite.conf

RewriteEngine On
<If "-n '%{HTTP:X-Forwarded-Proto}' && %{HTTP:X-Forwarded-Proto} != 'https'">
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</If>

.ebextensions/https.config

files:
  "/home/ec2-user/https_setup.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash

      echo "USE_HTTPS env var: ${USE_HTTPS,,}"
      outfile=/etc/httpd/conf.d/ssl_rewrite.conf
      if [ "${USE_HTTPS,,}" == "true" ]; then
        echo "Configure SSL rewrite"
        cp .ebextensions/files/ssl_rewrite.conf $outfile
        chmod 644 $outfile
        chown root:root $outfile
      else
        [ -f $outfile ] && rm $outfile
        echo "Do not use SSL"
        exit 0
      fi

container_commands:
  01_https_setup:
    command: "/home/ec2-user/https_setup.sh"

Note that if you change USE_HTTPS, you need to redeploy your application for the change to take effect. You can also remove the echo commands in the https.config file if you wish.

nbeuchat
  • 4,802
  • 2
  • 28
  • 37
1

AWS has also some documentation on this.

If you're using an application load balancer, add the file http-to-https.config to your .ebextensions folder and then add the following config (Don't forget to put in the ARN of your https certificate):

NOTE: Please be sure that you haven't yet added a listener on port 443 via the EB console. If you did so, delete the listener before adding the .config file.

Resources:
  AWSEBV2LoadBalancerListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: redirect
          RedirectConfig:
            Protocol: HTTPS
            Port: '443'
            Host: '#{host}'
            Path: '/#{path}'
            Query: '#{query}'
            StatusCode: HTTP_301
      LoadBalancerArn:
        Ref: AWSEBV2LoadBalancer
      Port: 80
      Protocol: HTTP
  AWSEBV2LoadBalancerListenerHTTPS:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      Certificates:
        - CertificateArn: Replace with Certificate ARN
      DefaultActions:
        - Type: forward
          TargetGroupArn:
            Ref: AWSEBV2LoadBalancerTargetGroup
      LoadBalancerArn:
        Ref: AWSEBV2LoadBalancer
      Port: 443
      Protocol: HTTPS 

The advantage of using your LB for this is that your config will be agnostic to the server you use like nginx, apache, etc.

Xen_mar
  • 4,549
  • 4
  • 24
  • 40
1

I found an answer from here to be helpful.

All I did was make the health check path /index.php instead of / in the application load balancer default process.

0

Why don't you simply put an .htaccess file in the root folder? That way you can simply test and debug it. And if you include it in the .zip, it will automatically deployed on all instances again.

Simply use .htaccess:

RewriteEngine on
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
Timo
  • 1
0

Please note that the most voted answer is a bit old now. The answer by A Paul is actually the correct answer. The link provided in his answer is by AWS (so it is the recommended method to override your Apache configuration to make the redirection from HTTP to HTTPS when running your application on Elastic Beanstalk).

There is one very important thing to note. If you are deploying more than 1 web app, then adding the .ebextensions folder inside one of your web app is not going to work. You will notice that Non of the configurations you specified are being written or created. If you are deploying multiple Web Apps on Elastic Beanstalk environment, then you will need to read this article by AWS Java Tomcat Deploy Multiple WAR files on Elastic Beanstalk

In general, you will need to have the following structure before you issue the eb command on it to deploy the WAR files:

MyApplication.zip
├── .ebextensions
├── foo.war
├── bar.war
└── ROOT.war

if .ebextentions folder exists inside each WAR file, then you will notice that it is completely ignored and no configuration changes will be performed.

Hope this helps someone else.

moto kazi
  • 29
  • 5
0

We have solved it on our backend by handling X-Forwarded-Proto properly.

This is our Grails config but it will help you with the idea:

    grails.plugin.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
    grails.plugin.springsecurity.portMapper.httpPort = 80
    grails.plugin.springsecurity.portMapper.httpsPort = 443
    grails.plugin.springsecurity.secureChannel.secureHeaderName = 'X-Forwarded-Proto'
    grails.plugin.springsecurity.secureChannel.secureHeaderValue = 'http'
    grails.plugin.springsecurity.secureChannel.insecureHeaderName = 'X-Forwarded-Proto'
    grails.plugin.springsecurity.secureChannel.insecureHeaderValue = 'https'
    grails.plugin.springsecurity.secureChannel.definition = [
        [pattern: '/**', access: 'REQUIRES_SECURE_CHANNEL']
    ]
Amio.io
  • 17,083
  • 11
  • 66
  • 100
0

To extend another two answers to this question https://stackoverflow.com/a/43026082/8775205, https://stackoverflow.com/a/42035023/8775205. For spring boot users who deploy their services on AWS with ELB, and need step by step guide, you can add an ****.conf file under src/main/webapp/.ebextensions/httpd/conf.d/ in your project.

src
--main
----java
----resources
----webapps
------.ebextensions
--------httpd
----------confd
------------****.conf

****.conf looks like the following. Noticed that I have my testing site with a single instance, so I add a condition to exclude it.

<VirtualHost *:80>
   LoadModule rewrite_module modules/mod_rewrite.so

   RewriteEngine On
   RewriteCond %{HTTP:X-Forwarded-Proto} !https
   RewriteCond %{HTTP_USER_AGENT} !ELB-HealthChecker 
   RewriteCond %{HTTP_HOST} !testexample.com #excludes test site
   RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

   <Proxy *>
     Order deny,allow
     Allow from all
   </Proxy>

   ProxyPass / http://localhost:8080/ retry=0
   ProxyPassReverse / http://localhost:8080/
   ProxyPreserveHost on

   ErrorLog /var/log/httpd/elasticbeanstalk-error_log

</VirtualHost>

After this, remember to add a "resource" under maven-war-plugin in your pom.xml in order to pick up the above configuration.

<plugin>
     <groupId>org.apache.maven.plugins</groupId>  
     <artifactId>maven-war-plugin</artifactId>  
     <configuration>  
         <webResources>
             <resource>  
               <!-- some other resource configured by yourself-->
             </resource> 
             <resource>
                <directory>src/main/webapps/.ebextensions</directory>
                 <targetPath>.ebextensions</targetPath>
                 <filtering>true</filtering>
             </resource> 
         </webResources>  
     </configuration>  
     <version>2.1.1</version>
 </plugin>

Finally commit and push your code, wait AWS codebuild and codepipeline to pick up your code from your repository and deploy to beanstalk environment, or simply pack your project into a war file and upload it to your AWS beanstalk environment

0

AWS do not accept unserscores (_) in headders, while we can use (-), So Remove underscores from the header variables, example:- header_var_val = "some value" replace it with headervarval = "some value". It works for me.

Rishabh Jhalani
  • 739
  • 6
  • 17
-4

If you use a Load Balanced environment you can follow the instructions for Configuring HTTPS for your AWS Elastic Beanstalk Environment and at the end disable the HTTP port.

Note that currently the AWS Free Usage Tier includes the same amount of hours for an Elastic Load Balancing (ELB) as for an EC2 Micro Instance.

danilop
  • 387
  • 1
  • 9
  • 7
    This way you only enable HTTPS but you don't enforce it. Enforcing means you automatically redirect all HTTP requests to HTTPS. – Bastian Venthur Nov 10 '15 at 09:51
-4

this is an easy solution

  1. ssh into your EC2 instance
  2. copy the contents of /etc/httpd/conf.d/wsgi.conf into a local file called wsgi.conf which will be placed in the base folder of your application
  3. Edit the local version of wsgi.conf and add the following redirect rules within the < VirtualHost> < /VirtualHost> tags

    RewriteEngine On
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteRule !/status https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]
    
  4. Change the “/status” to whatever page you are using as a health check page.

  5. Save the file
  6. Edit your < app>.conf file inside your .ebextensions directory to add a container command to copy this version of wsgi.conf over Amazon’s version

    container_commands:
    01_syncdb:
      command: "django-admin.py syncdb --noinput" leader_only: true
    02_collectstatic:
      command: "django-admin.py collectstatic --noinput"
    03_wsgireplace:
      command: 'cp wsgi.conf ../wsgi.conf'
    ...
    
  7. Deploy the code.

  8. The deployed version of wsg.conf at /etc/httd/conf.d/wsgi.conf will now include the necessary redirect rules.

It should work and the file will be properly updated for each deployment. The only thing to watch for is if Amazon changes their base wsgi.conf file contents in the future, then your copy may no longer work.

Autor rickchristianson

gusgard
  • 776
  • 7
  • 21
  • 2
    Exact duplicate of his own answer: http://stackoverflow.com/questions/6858492/how-to-force-https-on-amazon-elastic-beanstalk-without-failing-the-health-check/21896755#21896755. stop posting duplicate answers! – Paresh Mayani Feb 20 '14 at 19:02
  • the problem can be solved with the same answer ;) its spam ?? – gusgard Feb 21 '14 at 17:55
  • 3
    ssh-ing into an instance behind the load balancer and making adjustments defeats the purpose of Elastic Beanstalk. What happens when you scale up and get more instances? Do this on all of them? Manually? – fivedogit Dec 17 '16 at 17:46
  • 1
    @fivedogit if you read carefully, you notice that he didn't make adjustments by SSH-ing into the instance. He only SSH to read the file and copy it. After that, he is using `.ebextensions` in his deployment to make the adjustments correctly through Elastic Beanstalk itself, so he's not defeating its purpose. – ADTC Nov 11 '17 at 20:24