James Galley Software engineer - SaaS, AI automation & business operations

Using SSL and CloudFront with a single-instance Elastic Beanstalk app

Adding HTTPS to a single-instance Elastic Beanstalk PHP application by putting CloudFront in front of it, including the Apache and Yii2 configuration needed.

AWS • CloudFront • PHP

A single-instance Elastic Beanstalk environment doesn't terminate SSL the way a load-balanced environment does, so the EC2 serves plain HTTP. You can still put your application behind HTTPS by placing CloudFront in front of it, with an ACM certificate on the distribution, while the origin connection back to the instance stays on HTTP. The wrinkle with a PHP or Yii2 app is that the framework needs to detect the original HTTPS request, which arrives via the CloudFront-Forwarded-Proto header rather than the connection itself.

This picks up once your app is running on Elastic Beanstalk, which is a natural home after migrating a web application to the cloud.

The certificate

Request or import your certificate in AWS Certificate Manager in the US East (N. Virginia) us-east-1 region. CloudFront only uses certificates from that region, regardless of where the rest of your infrastructure lives.

CloudFront distribution settings

Create a distribution with the origin pointing at your Elastic Beanstalk environment domain, for example env.eu-west-2.elasticbeanstalk.com:

  • Alternate domain name: your domain, for example yourdomain.com
  • Custom SSL certificate: choose the certificate from the list
  • Origin: the Elastic Beanstalk environment domain
  • Origin protocol: HTTP only, as the EC2 instance has no SSL
  • Viewer protocol policy: HTTP and HTTPS
  • Allowed HTTP methods: all (GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE)
  • Cache based on selected request headers: whitelist CloudFront-Forwarded-Proto and Host
  • Object caching: customise, all TTLs set to 0 if you are not using CloudFront for caching
  • Forward cookies: whitelist, adding your Yii or PHP framework CSRF parameter name and session ID
  • Query string forwarding and caching: forward all, cache based on all

The .htaccess redirect

Because the request reaching the EC2 instance is always HTTP, an ordinary HTTPS redirect would create a loop. The redirect must instead key off the CloudFront-Forwarded-Proto header, which carries the viewer's original protocol:

RewriteCond %{HTTP:CloudFront-Forwarded-Proto} !https

And to send visitors to your canonical domain:

## Redirect to real domain
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTP_HOST} !^domain\.test$
    RewriteCond %{HTTP_HOST} !^domain\.com$
    RewriteRule ^(.*)$ https://domain.com/$1 [R=302,NC]
</IfModule>