I am using Elastic Beanstalk on AWS to host a single-tenant application with Amazon Linux 2 + Nginx server. Is there any way to automatically generate a HTTPS certificate without recurring to a Load Balancer?
A solution would be to create an AWS Linux 2 + Nginx image based on your Elastic Beanstalk image with Certbot (application needed to generate the certificates) preinstalled and roll out this image to your instances. Then, with a .posthook script Certbot can be called to renew the certificate each time the server is started or updated (restart/new version upload)
For the first step you can create an AWS Beanstalk environment through the wizard : the instance will be made available on your EC2 tab. Then, you can access your EC2 instance through SSH (there is a tutorial at this link : Putty is a good choice of a SSH client on Windows) and run the following commands to install Certbot:
sudo wget -r --no-parent -A 'epel-release-*.rpm' http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/
sudo rpm -Uvh dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-*.rpm
sudo yum-config-manager --enable epel*
sudo yum install -y certbot python2-certbot-nginx
After that you can go to the EC2 tab, find your instance and create an image based on your EC2 Elastic Beanstalk instance:
With the image created, it can be reused on several instances by inserting the newly created AMI on the Instance Traffic and Scaling menu on the Elastic Beanstalk Configuration tab.
The next step is to assign a DOMAIN environment variable to your EB environment. This variable corresponds to the domain that has been assigned to your server IP through DNS.
Lastly, a script should be placed in the .zip /.jar file or docker image that is uploaded on Beanstalk. The file should be located on:
-- .zip file root
-- .platform
-- hooks
-- postdeploy
-- update_certificate.sh
The file content is:
#!/bin/bash
sleep 60
sudo certbot --nginx --non-interactive --redirect --email your@email.com --agree-tos -d $(sudo /opt/elasticbeanstalk/bin/get-config environment -k DOMAIN) --cert-name $(sudo /opt/elasticbeanstalk/bin/get-config environment -k DOMAIN) || echo 'The certificate could not be generated/updated. Initialization will continue'
The --email parameter should be replaced with a real e-mail and could also be set up as an environment variable.
The sleep command waits for the server IP to correspond to the Elastic IP : if Certbot is called before that the certificate will not be generated.
Also note that this command instructs Nginx to redirect traffic from port 80 (HTTP) to 443 (HTTPS), so this port should be enabled on your EC2 instance:
This solution should be resilient to an Application server / Nginx server restart and to the upload of new application versions.