30

I'm developing with django on elastic beanstalk and I want to make two changes to apache configuration:

1. redirect www.domain.com to domain.com

2. redirect http://domain.com to https://domain.com

I don't have experience with apache configuration, googling it gave me the idea that I should put RewriteRules in .htaccess file.

example: How to force https on amazon elastic beanstalk without failing the health check

I couldn't find instructions on how to do it with elastic beanstalk configuration (.ebextensions), I tried to simply put a .htaccess file in my root filder and deploy but it didn't work.

Does anyone know how it's possible to add the RewriteRules in elastic beanstalk?

Community
  • 1
  • 1
Dan Bolofe
  • 1,099
  • 2
  • 13
  • 21

4 Answers4

68

Having www.example.com go to example.com can be done with a CNAME in DNS if you don't care about having it actually being a redirect. If you need a redirect, you can add it to the Apache config below. The primary point of this answer is to detail how you modify Apache config on Elastic Beanstalk (because doing this properly is not very straight forward).

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).

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", or adding the following to one of your .config files in .ebextensions:

option_settings:
  aws:elasticbeanstalk:environment:proxy:
    ProxyServer: apache

On AWS Linux 2, Apache is configured exclusively through adding files to your codebase in .plaform/httpd/conf.d/, from which they will get added to the server's Apache config. You can no longer edit Apache files through .ebextensions.

To do an HTTP to HTTPS redirect using Apache, 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>

Note that nginx can be configured in a similar way, namely by adding a .conf file to .platform/nginx/conf.d/ (though the contents of this file will obviously be different).

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.

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
  • 37,389
  • 14
  • 105
  • 140
  • Your solution works great on one of my environments, but not on the other. Both are supposed to be identical. One one the /etc/httpd/conf.d/ssl_rewrite.conf file is there and it redirects correctly. On the other the file is missing. The eb_extension config file also adds a variable to php.ini and that shows up in both environments, so it is only the ssl_rewrite.conf that is missing for some weird reason. Any ideas? Thanks. – Nitzan Wilnai Aug 15 '16 at 23:21
  • @NitzanWilnai If the ssl_rewrite.conf file is missing on one of your environments, then most likely you need to redeploy to that environment. Make sure the branch you are deploying has the new config in it. If that doesn't work, post this as it's own question on StackOverflow. – Zags Aug 16 '16 at 01:44
  • 6
    This is an excellent answer, thanks for saving us a lot of time (and helping us avoid a future maintenance nightmare). If an AWS employee is reading this, you should add something similar to your docs. – KayakinKoder Feb 23 '17 at 18:02
  • 1
    Completely agree with KayakinKoder. AWS support just pointed me to [this](https://github.com/awslabs/elastic-beanstalk-docs/blob/master/configuration-files/aws-provided/security-configuration/https-redirect/python/https-redirect-python.config) solution on awslabs at github, which is similar to the accepted answer. However, the answer by Zags is preferable as far as I can see. @Zags, perhaps you could try to get this solution pulled into the awslabs repo? – djvg Jun 13 '17 at 14:37
  • Thanks for the post @Zags. I find it works for redirecting the domain. However, it doesn't seem to redirect for any subdirectories? I'm guessing that's what the REQUEST_URI part is suppose to cover. Any ideas? – Ian Aug 25 '17 at 15:56
  • @Ian It redirects the whole domain for me. That is what REQUEST_URI is for. You should probably post this as a separate question, to add more information. – Zags Sep 06 '17 at 15:14
  • I wish I could mark answers as favourite rather than just questions. This one is great! – timeSmith Sep 08 '18 at 17:48
  • Trying to add a condition in here where it forwards any domain without a subdomain or www to redirect to https and www.fake-url.com. Any suggestions? – James Parker Dec 06 '18 at 01:53
  • @JamesParker That's big enough to post as it's own question – Zags Dec 06 '18 at 03:15
  • 1
    For those who came to this question but use nginx, the solution also applies if the configuration file is created in `.platform/nginx/conf.d/your_config_file.conf` – Martin Forte Jan 21 '22 at 13:24
10

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 /etc/httpd/conf.d/wsgi.conf'
    ...
    
  7. Deploy the code.

  8. The deployed version of wsgi.conf at /etc/httpd/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.

Source : rickchristianson

nicholsonjf
  • 971
  • 2
  • 11
  • 21
gusgard
  • 905
  • 1
  • 10
  • 24
  • 11
    That last sentence a big deal => "maintenance nightmare" – winwaed Jun 08 '14 at 17:20
  • exactly =( , do you have a elegant solution =D ?? – gusgard Jun 09 '14 at 04:27
  • Since writing that comment, I was able to get it to work for my situation. I was trying to redirect http to https though. This can be solved with django-secure and then set SECURE_PROXY_SSL_HEADER, SECURE_SSL_REDIRECT, and SECURE_HSTS_SECONDS. This does NOT solve the OP's redirection of www.domain.com -> domain.com though. – winwaed Jun 10 '14 at 01:01
  • 3
    Make sure you COMMIT to git your changes to you .config file or else the container_commands won't be run. – Meistro Oct 16 '14 at 00:17
  • 3
    For the www.domain.com to domain.com, you can set this up in the Amazon Route 53 with a record on a Host Zone that maps www.domain.com to your Elastic Load Balancer like you probably have already done for domain.com. – Nathan Ward Dec 10 '14 at 13:31
  • This no longer works. EB overwrites the file after the `container_commands` run. – Dan Apr 29 '16 at 09:33
  • See stackoverflow.com/a/38751648/2800876 for a proper solution – Zags Aug 03 '16 at 19:03
5

This is very well explained in AWS documentation as below:

To extend the Elastic Beanstalk default Apache configuration, add .conf configuration files to a folder named .ebextensions/httpd/conf.d in your application source bundle. The Elastic Beanstalk Apache configuration includes .conf files in this folder automatically.

~/workspace/my-app/
|-- .ebextensions
|   -- httpd
|      -- conf.d
|         -- myconf.conf
|         -- ssl.conf
-- index.jsp

To override the Elastic Beanstalk default Apache configuration completely, include a configuration in your source bundle at .ebextensions/httpd/conf/httpd.conf.

~/workspace/my-app/
|-- .ebextensions
|   `-- httpd
|       `-- conf
|           `-- httpd.conf
`-- index.jsp

If you override the Elastic Beanstalk Apache configuration, add the following lines to your httpd.conf to pull in the Elastic Beanstalk configurations for Enhanced health reporting and monitoring, response compression, and static files.

IncludeOptional conf.d/*.conf
IncludeOptional conf.d/elasticbeanstalk/*.conf

Note

To override the default listener on port 80, include a file named 00_application.conf at .ebextensions/httpd/conf.d/elasticbeanstalk/ to overwrite the Elastic Beanstalk configuration.

For a working example, take a look at the Elastic Beanstalk default configuration file at /etc/httpd/conf/httpd.conf on an instance in your environment. All files in the .ebextensions/httpd folder in your source bundle are copied to /etc/httpd during deployments.

Further details can be seen on this link under Extending and overriding the default Apache configuration. Better to use correct approach instead of patches or workarounds.

Imran Zahoor
  • 2,521
  • 1
  • 28
  • 38
  • Just note that this configuration only works on newer Amazon Linux 2 platforms – gmsantos Aug 30 '20 at 16:11
  • 2
    The last linux platforms uses the `.platform` directory instead the `.ebexensions` one to override httpd configuration: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/platforms-linux-extend.html – Boris Burgos Jun 16 '21 at 20:54
2

Just for reference for others, using Zags' solution to redirect non-www to www, add this to your .ebextensions/your_file.config:

files:
    "/etc/httpd/conf.d/www_rewrite.conf":
        mode: "000644"
        owner: root
        group: root
        content: | 
            RewriteEngine On
            <If "'%{HTTP_HOST}' !~ /^www\./">
            RewriteRule ^(.*)$ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
            </If>
Nad
  • 516
  • 5
  • 18