HTTPS/TLS for Single Instance Elastic Beanstalk Environments

Share this post on:

Overview

  • This post will cover how to set up HTTPS on AWS Elastic Beanstalk Environment (EBS) that is running only a single instance, as opposed to an load balanced environment which can scale up the instances based on load.
  • While you can easily set up HTTPS using Amazon Certificate Manager (ACM) if you are using an AWS load balancer with your EBS environment, this is not a method you can use if you choose to use a single instance environment, which does not allow load balancers to be used.
  • This post will cover how to set up and use Let’s Encrypt certificates for HTTPS using certbot, which is completely free.

Use Case

The main use case for using this method of setting up HTTPS this way is when you are setting up a small project that requires HTTPS (e.g. You have a domain that requires HTTPS like .dev), but you are not willing to fork out extra cash for multiple EC2 instances and/or you are not willing to pay extra for a load balancer.

Prerequisites

  • You have already set up the necessary records in Route 53 for your project to be accessible at your desired domain
  • You have set up a single instance EBS Environment1

Process

  1. As per the instructions on the AWS support documentation2, create the following directory and file to allow HTTPS connections to your environment

    .ebextensions/01_https-instance-securitygroup.config
    Resources:
      sslSecurityGroupIngress: 
        Type: AWS::EC2::SecurityGroupIngress
        Properties:
          GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
          IpProtocol: tcp
          ToPort: 443
          FromPort: 443
          CidrIp: 0.0.0.0/0
  2. Create the following directory and file to create a hook to install EPEL3 (required for installing certbot) in the prebuild phase4.

    .platform/hooks/prebuild/01_install_epel.sh
    #!/bin/bash
    sudo amazon-linux-extras install epel -y
  3. Create the following file in the same directory to install certbot. Note the “02_“prepended to the file name. The files in the .platform/hooks/prebuild folder are executed in alphanumerical order, so this will cause this script to be run after 01_install_epels.sh is run.

    .platform/hooks/prebuild/02_install_certbot.sh
    #!/bin/bash
    sudo yum install -y certbot-nginx

    This script will install certbot with the nginx plugin, as EBS uses the nginx web server under the hood.

  4. Set the following environment properties (variables) for you EBS environment:

    • DOMAIN_1
      • This will be the same as the domain or subdomain you’ve set in Route 53 to reach your application, (e.g. www.example.com)
    • EMAIL
      • This is the email used when using certbot to generate certificates

    You may notice that I have a DOMAIN_2 set as well. That is only needed if you have another domain and/or a subdomain linked to the application.

  5. Create the following directory and file.

    .platform/hooks/postdeploy/01_execute_certbot.sh
    #!/bin/bash
    sudo certbot --nginx --non-interactive --agree-tos -m ${EMAIL} -d ${DOMAIN_1}

    This will create a hook in the postdeploy phase and run certbot to generate the necessary certificates required for HTTPS connections for the listed domains. It will also use the nginx plugin to reconfigure and reload it’s configuration as needed.

    In case you have multiple domains and DOMAIN_2 was set in the environment properties in the previous step, you would include the second domain like this:

    .platform/hooks/postdeploy/01_execute_certbot.sh
    #!/bin/bash
    sudo certbot --nginx --non-interactive --agree-tos -m ${EMAIL} -d ${DOMAIN_1} -d ${DOMAIN_2}
  6. (Optional) To configure auto renewal of certificates, you can setup a cron job to automatically run the certbot renew command by creating the following file in the .ebextensions directory.

    .ebextensions/02_certbot_renewal.config
    files:    
        "/etc/cron.d/certbot":
            mode: "000644"
            owner: root
            group: root
            content: |
                0 12 * * * root /usr/bin/certbot renew
    
    commands:
        remove_old_cron:
            command: "rm -f /etc/cron.d/certbot.bak"

    This file will do 2 things:

    • Create a cron job to run the certbot renew command every day at 12:00,
      • Although the command is run every day, the certificates themselves will not be renewed unless they are within 30 days of expiry.
    • Run the rm -f /etc/cron.d/certbot.bak command before the application and webserver are setup to remove the old cron job, in case it exists
  7. To summarise, by the end, you should have a directory structure which looks something like this:

    Project Tree View
    .
    ├───.ebextensions
    │       01_https-instance-securitygroup.config
    │       02_certbot_renewal.config
    
    └───.platform
        └───hooks
            ├───postdeploy
            │       01_execute_certbot.sh
    
            └───prebuild
                    01_install_epel.sh
                    02_install_certbot.sh

    Make sure that every file is in the right place, and their contents are correct. Note this is the view from the root project directory. When you zip your project and upload it to AWS Elastic Beanstalk, both the .ebextensions and .platform directories should be located in the root directory, alongside the rest of your project files.

Conclusion

No one wants to fork out huge sums of cash every time we setup a small project on the web. So us poor folks gotta find ways around it but still get what we want. At any rate, this post summarises my method of setting up HTTPS on AWS EBS without load balancers. I’m sure there are better ways of doing it, especially in terms of “best practice”, but for now, this works for me in my small personal projects. Although if you are looking for a more professional solution, this likely won’t meet your requirements, but then again, a professional wouldn’t be looking at a blog like this, haha.

Footnotes

  1. AWS Documentation to change environment types: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-types.html#using-features.managing.changetype ↩︎
  2. AWS documentation to open port 443 in a single instance environment: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/https-singleinstance.html ↩︎
  3. Extra Packages for Enterprise Linux (EPEL) ↩︎
  4. For more information on the Elastic Beanstalk deployment phases, see the documentation here: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/platforms-linux-extend.html ↩︎