16

I have configured my Elastic Beanstalk environment to redirect all pages to https, redirection works, however, the instance fails the health check and gets terminated, any ideas how to configure the rewrite rules?

My configuration:

NameVirtualHost *:80

<VirtualHost *:80>
.
.
.

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule !/_hostmanager/healthcheck https://%{SERVER_NAME}%{REQUEST_URI} [L,R] 
</VirtualHost>
Zags
  • 26,675
  • 10
  • 77
  • 107
user867340
  • 161
  • 1
  • 1
  • 4
  • 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:09

11 Answers11

13

There's multiple hostmananger URLs that Elastic Beanstalk needs to access besides the health check. Grepping /var/log/httpd/elasticbeanstalk-access_log, I see requests to /_hostmanager/tasks and /_hostmanager/healthcheck.

Here are the rules that I added to /etc/httpd/sites/elasticbeanstalk on my EC2 instances:

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]

Note that I'm also allowing non-https traffic to my /status and /version pages. I'm actually using /status as the actual healthcheck lookup URL, so having that traffic skip the rewrite will avoid the redirect and make the status lookup faster (I'm assuming).

Joel Rosenberg
  • 1,362
  • 2
  • 12
  • 15
8

I think that some of the other answers on here may not be based on whatever the arbitrary User-Agent AWS is currently setting. When I watch the Apache logs, I see this User-Agent:

ELB-HealthChecker/1.0

As of writing this, the following mod_rewrite rule is working for me:

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTP_USER_AGENT} !^ELB-HealthChecker.* 
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
vcardillo
  • 1,558
  • 3
  • 22
  • 28
6

As of 2016, none of these answers works for me, but this worked:

1 Retrieve /etc/httpd/conf.d/wsgi.conf

2 Add the following to the virtual host: (Note that the third line prevents an issue where the setup script /opt/elasticbeanstalk/hooks/config.py waits 5 minutes failing to load the path /.)

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTP_HOST} !localhost
RewriteCond %{HTTP_USER_AGENT} !^ELB-HealthChecker.* 
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]

3 Put the file in your repository, and add the following container command:

06_https:
  command: "cp wsgi.conf /opt/python/ondeck/wsgi.conf"

This file is then copied automatically by the setup script into /etc/httpd/conf.d.

Dan
  • 10,532
  • 2
  • 42
  • 74
3

It looks like the AWS Health Checker uses the user agent 'AWSHealthCheck'.

I got round this by avoiding the redirect if the request came from the Health Checker User Agent.

SOmething like:

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{USER_AGENT} !^AWSHealthCheck$ 
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
Pat C
  • 351
  • 2
  • 4
  • 1
    This is close, but doesn't seem to actually work for me. The health check still fails. `%{USER_AGENT}` does not appear to be a valid `mod_rewrite` variable. According to the docs at http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html, the correct variable is `HTTP_USER_AGENT` – vcardillo Aug 21 '13 at 07:49
1

You can configure ELB to use a specific path for health checks, such as /ping. You can then explicitly tell apache not to redirect that URL, rather than relying on the UserAgent string.

You can also tell ELB to use HTTPS for the health check and then redirect all HTTP URLs to HTTPS, including the health check.

Both these settings can be changed in the EC2 Console in the Load Balancer section.

Greg Kempe
  • 1,587
  • 1
  • 9
  • 8
1

If you are trying to do this in Wordpress or PHP, you can setup your .htaccess as follows without having to modify anything through .ebextensions:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{REQUEST_URI} !^/status\.html$
RewriteCond %{REQUEST_URI} !^/_hostmanager/
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
</IfModule>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Remember to change status.html to whatever path you are using to do your Elastic Beanstalk health check

For more info see my response here.

Giles Butler
  • 922
  • 3
  • 14
  • 23
1

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

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.

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

Community
  • 1
  • 1
Zags
  • 26,675
  • 10
  • 77
  • 107
0

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
0

For me, copying the wsgi.conf into place never worked. Either EB would fail to deploy, or the file would be overwritten.

The only answer I found that worked was here. Essentially, he used sed to insert the necessary rewrite rules into the wsgi.conf. He says the container command to add is

container_commands:
  01_http_to_https_redirect:
    command: 
      sed -i '/\<VirtualHost \*:80\>/a RewriteEngine On\nRewriteCond %{HTTP:X-Forwarded-Proto} !https\nRewriteRule \!/robots.txt https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]' /opt/python/ondeck/wsgi.conf

Don't forget to change your health check endpoint from robots.txt.

Nick Yap
  • 857
  • 1
  • 10
  • 13
0

As a general strategy what has worked for us, with both Apache and Nginx EC2 instances behind an AWS secured Load Balancer, is:

  1. At the load balancer, forward port 80 to port 80 on the instances
  2. forward port 443 to port 8080 (for example) on the instances
  3. In the web server, listen on both ports (80 and 8080)
  4. redirect port 80 to port 443
  5. Add environment variable "HTTPS", with value "on" to the EC2's, e.g. using the Elastic Beanstalk Software Configuration

Step 1 ensures that AWS internal traffic is treated "naturally".

Step 2 allows only secure external traffic to reach our code

Step 5 tells the web server and what's behind it (Laravel, in our case) that generated URL's should be given the https: scheme. Other frameworks may need some other environment variables set in order to trigger that behavior.

JDA3
  • 336
  • 3
  • 7
0

Create a static health.html. If possible, as a configuration Template.

aldrinleal
  • 3,489
  • 24
  • 31