AWS HTTP to HTTPS redirection

For a Java application in Tomcat in an Elastic Beanstalk environment

It's easy to configure an ssl certificate and associate it with a load balancer. The certificate is free, too. It's also easy to get automatic redirection from all http requests to https reguests, if one knows how to do it. What is not so easy is finding all the required information in one place. This is what this short how-to is about.

The starting point

You must have your Elastic Beanstalk environment all set up and your certificate issued and associated with your load balancer. If you are going to use a database, which is most likely, that must be set up and configured, too. You can have the AWS default application running. You will notice that you have to specify https in the url to get the application, yours or the default, loaded to a browser window.

The first two things you have to do

It is absolutely imperative that you ensure that firstly your load balancer security group (in the EC2 window of the AWS console) inbound permissions look like the image below. Don't worry about the last https row. That looks like IPV6 values and is automatically added.
load balancer security group

Next, you must make sure your load balancer listeners look like in the image below.
load balancer listeners
You will see that the load balancer listens on ports 443 and 80. Port 443 is associated with your ssl certificate. The output to Apache is on port 80 for both port 443 and port 80. That means Apache has to examine the request headers and see which of them specify http as the protocol. If http is specified, Apache has to redirect the request so https is specified as the protocol. Of course, if https is specified, Apache does nothing to the request and just passes it on to the requested url.

The changes to make this happen are needed in just one file: /etc/httpd/conf.d/elasticbeanstalk/00_application.conf. Below is what the file looks like with the changes needed indicated in a slightly darker background.

# Elastic Beanstalk Managed
LoadModule rewrite_module modules/mod_rewrite.so
<VirtualHost *:80>
RewriteEngine On RewriteCond %{HTTP:X-Forwarded-Proto} =http RewriteRule . https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]
<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>

The problem

As you can see from the comment which forms the first line of this file, Elastic Beanstalk manages this file. That means that with every application restart, every new deployment and every new instance created when you environment scales up, the changes are lost.

The solution

The way to get past this is to create a directory named .ebextensions (note the leading dot) in the root of your war file with some files in it. As your application is deployed, AWS scans this directory and does what the files in it tells AWS to do. So, how to get it into the root of your war archive when it is built?

As you know, Gradle is used to build things in Grails 3. In Grails 3, the Gradle war plugin is already loaded in build.gradle. All you have to do is add the following to the bottom of your project build.gradle file:

war {
	from 'ebextensions'
}
					

Note the absence of the leading dot in the code above.

In your project root directory, create a directory named ebextensions. Again, no leading dot. Inside this directory you at last create the directory with the leading dot, .ebextensions. You can most likely see what is going on here - the from directive in the war block above will include everything inside the ebextensions directory, which will be the .ebextesnions directory and everything it contains.

Inside the .ebextensions directory, create two text files, one named 00_application.conf and the other named elastic-beanstalk-ssl.config. The second must have a .config extension and the first must not.

The only thing different from when we saw it before for 00_application.conf is the first line. Here is the whole file:

# Copied from .ebextensions
LoadModule rewrite_module modules/mod_rewrite.so
<VirtualHost *:80>
  RewriteEngine On
  RewriteCond %{HTTP:X-Forwarded-Proto} =http
  RewriteRule . https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]
  <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>
					

Below is elastic-beanstalk-ssl.config, which does the heavy lifting, which is not really that heavy. It's a yaml formatted file and must have a .config extension.

container_commands:
  01remove-default-file:
    command: "rm /etc/httpd/conf.d/elasticbeanstalk/00_application.conf"
  02replace-default-file:
    command: "cp .ebextensions/00_application.conf /etc/httpd/conf.d/elasticbeanstalk/00_application.conf"
					

As you can see, all that happens is that the default Elastic Beanstalk managed file is removed and replaced with the one supplied in the .ebextensions directory in the root of your war archive. This happens after all Elastic Beanstalk management.

Upload and deploy your project war archive now. When it's deployed, ssh into your EC2 instance and look at /etc/httpd/conf.d/elasticbeanstalk/00_application.conf using Nano or Vi or whatever you wish. The first line should be # Copied from .ebextensions. Of course, the other changes should also be there.

You can now forget about the automatic redirecting from http to https. It should always work.

If you find what you learned on this page useful, please use the social media widgets at the bottom and pin, tweet, plus-one or whatever this page.