Deploying Laravel to Elastic Beanstalk in 2021

Helium Services
11 min readJan 7, 2021

State of the Union

There are about a million and three different articles, documentation pages, StackOverflow questions, and video tutorials on how to deploy your application with AWS Elastic Beanstalk. However, nowadays it seems many of those sources are outdated, only cover part of the process, or simply are not compatible with your particular circumstances.

In this tutorial, we will cover an updated set of instructions for automatically deploying your Laravel application to Elastic Beanstalk with a custom domain name and SSL certificate.

Prerequisites

This tutorial assumes that you already have an AWS account, and that you already have a Laravel codebase hosted in GitHub, BitBucket, or AWS CodeCommit.

Step 1: Laravel

Before your application can be deployed, there are a few changes you must make to your Laravel project.

1. Open your Laravel project.

2. Create a copy of your .env file for your specific environment, such as .env.beta or .env.production.

3. Edit the new file and remove any sensitive values such as passwords or authentication tokens. I usually remove APP_KEY, DB_HOST, DB_DATABASE, DB_USERNAME, DB_PASSWORD, and any other usernames, passwords, and tokens used for other services.

4. If you have not already, run php artisan passport:keys to generate your OAuth public and private keys in your app's storage folder.

5. Be sure to add these files to your .gitignore file.

6. Create a folder in the root of your project called .ebextensions.

7. In the .ebextensions folder, add a file called alb-http-to-https-redirection.config with the following content. The original copy of this file can be found in the awsdocs/elastic-beanstalk-examples GitHub repository.

###################################################################################################
#### Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
####
#### Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file
#### except in compliance with the License. A copy of the License is located at
####
#### http://aws.amazon.com/apache2.0/
####
#### or in the "license" file accompanying this file. This file is distributed on an "AS IS"
#### BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#### License for the specific language governing permissions and limitations under the License.
###################################################################################################

###################################################################################################
#### This configuration file modifies the default port 80 listener attached to an Application Load Balancer
#### to automatically redirect incoming connections on HTTP to HTTPS.
#### This will not work with an environment using the load balancer type Classic or Network.
#### A prerequisite is that the 443 listener has already been created.
#### Please use the below link for more information about creating an Application Load Balancer on
#### the Elastic Beanstalk console.
#### https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-alb.html#environments-cfg-alb-console
###################################################################################################

Resources:
AWSEBV2LoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn:
Ref: AWSEBV2LoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
- Type: redirect
RedirectConfig:
Host: "#{host}"
Path: "/#{path}"
Port: "443"
Protocol: "HTTPS"
Query: "#{query}"
StatusCode: "HTTP_301"

8. If you are using Laravel Passport for OAuth authentication, add another file in the .ebextensions folder called 01-oauth-keys.config with the following content.

container_commands:
01-oauth-keys:
env:
AWS_ENV:
"Fn::GetOptionSetting":
Namespace: "aws:elasticbeanstalk:application:environment"
OptionName: AWS_ENV
command: |
aws secretsmanager get-secret-value --secret-id $AWS_ENV --region=us-east-1 --query=SecretString --output text | jq -r ."OAUTH_PUBLIC_KEY" | sed -e "s/-----BEGIN PUBLIC KEY-----/&\n/" -e "s/-----END PUBLIC KEY-----/\n&/" -e "s/\S\{64\}/&\n/g" > storage/oauth-public.key
aws secretsmanager get-secret-value --secret-id $AWS_ENV --region=us-east-1 --query=SecretString --output text | jq -r ."OAUTH_PRIVATE_KEY" | sed -e "s/-----BEGIN RSA PRIVATE KEY-----/&\n/" -e "s/-----END RSA PRIVATE KEY-----/\n&/" -e "s/\S\{64\}/&\n/g" > storage/oauth-private.key
chmod 444 storage/oauth-public.key
chmod 444 storage/oauth-private.key
chgrp nginx storage/oauth-public.key
chgrp nginx storage/oauth-private.key

9. Commit and push your changes.

Step 2: Route 53

To deploy your app with an SSL certificate, you must use a custom domain name. All production apps should be deployed with SSL, but pre-release apps for internal testing purposes can often get by with the default domain name provided by Beanstalk. If you do not need to deploy with SSL, you can skip to Step 4: Elastic Beanstalk.

If you already have a registered domain name in Route 53 or another service, skip to Step 3: Certificate Manager.

To register your domain name, we will use the Route 53, the AWS-provided DNS service. For a more comprehensive tutorial on registering your domain with Route 53, visit the AWS

1. Log in to the AWS Console.

2. Search for Route 53 using the search bar, then click the result to open the service.

3. In the left side panel, click Registered Domains.

4. Near the top of the page, click Register Domain.

5. Enter your domain name, then click Add To Cart.

6. When you’re ready, click Continue at the bottom of the page.

7. Fill out the contact information form, then click Continue.

8. You may be asked to verify your email address. If so, follow the provided instructions. If not, skip to the next step.

9. Choose whether to automatically renew your domain name, then read and confirm the Terms of Service.

10. Click Complete Purchase.

11. You will receive an email when your domain registration is ready.

12. Route 53 will automatically create a hosted zone for your domain. We will come back to this later.

Step 3: Certificate Manager

To protect your applications hosted on AWS, you can create free SSL certificates with the Certificate Manager service.

1. Search for Certificate Manager using the search bar, then click the result to open the service.

2. Near the top of the page, click Request a certificate.

3. Leave this form on the default option, Request a public certificate. Click Continue.

4. Enter the domain name you will use to deploy your application. Note that you may use a subdomain and/or wildcard domain, as long as you own and control the base domain name.

5. Leave this form on the default option, DNS validation. Click Next.

6. If you want, add tags to identify your certificate. Click Review.

7. Click Confirm and request.

8. On this page, click the arrow to show details about the certificate DNS records.

9. If you are using Route 53 to serve your DNS records, click Create record in Route 53. Otherwise, add the record to your DNS provider.

10. Once the record is added, click Continue.

11. After a few minutes, refresh the status page to check that your certificate status is Issued.

Step 4: Elastic Beanstalk

Before we can create the deployment pipeline, we must first create your Elastic Beanstalk environment. You will select your Beanstalk environment as the deployment target when you configure CodePipeline in Step 4.

1. Search for Elastic Beanstalk using the search bar, then click the result to open the service.

2. In the left side panel, click Applications.

3. Click Create a new application.

4. Enter your application name. This should be the generic name of your application, not environment-specific (such as beta or production). For example, you should enter MyApp, not MyApp-Production.

5. Click Create.

6. You will be redirected to the Application Environments page. Click Create a new environment.

7. Leave this option as the default, Web server environment. Click Select.

8. Enter your environment name. This should include the specific deployment tag for your application environment, such as beta, staging, or production.

9. Enter your domain name. Again, this should be a combination of your application name and the environment name.

10. Choose PHP from the Platform dropdown menu. Then choose your PHP version from the Platform branch menu.

11. Leave all other options as the default value. Click Create environment.

12. You will be redirected to a status page. While your environment is being created, you can continue to the next steps.

Step 5: CodePipeline

To deploy your application from version control, we will process and build using AWS CodePipeline and CodeBuild.

1. Search for CodePipeline using the search bar, then click the result to open the service.

2. Near the top of the page, click Create pipeline.

3. Enter your application name to name the pipeline, and leave the other options as the default values. This should include the specific deployment tag for your application environment, such as beta, staging, or production.

4. Click Next.

5. Choose your source provider from the dropdown menu.

6. If you are using GitHub or BitBucket, you will need to click Connect to GitHub, or Connect to BitBucket to authorize AWS to access your repository.

6.1. Enter your connection name. I usually use the service name and account name. In my case, bitbucket-teamhelium.

6.2. Click Install a new app, then configure the connection settings. Click Grant Access.

6.3. You will be redirected back to the connection page. Click Connect.

7. Enter your repository name. If it does not appear in the list, you probably have the repository marked as private in GitHub or BitBucket. Don’t worry! You can still enter the repository name manually. Enter the repository name as <username>/<reponame>.

8. Enter the name of your deployment branch.

9. Choose CodePipeline Default, then click Next.

10. Choose AWS CodeBuild from the dropdown. Click Create Project to be redirected to AWS CodeBuild.

10.1. Enter your application name to name the build project.

10.2. Choose your build environment options. I use Ubuntu for Operating system, Standard for Runtime(s), and aws/standard/codebuild:4.0 for Image.

10.3. Leave all other options as the default values. Click Continue to CodePipeline.

10.4. You will be redirected back to CodePipeline. We will finish configuring CodeBuild later.

11. Click Next.

12. Choose AWS Elastic Beanstalk from the dropdown menu.

13. Enter the Application and Environment names that you configured earlier. Click Next.

14. Click Create Pipeline.

15. You will be redirected to a status screen, and the pipeline will automatically attempt to run and fail on the Build step because it has not been configured yet.

Step 6: CodeBuild

You have already created a project in AWS CodeBuild. Now we will configure all of the the build options to ensure that it is deployed correctly on Elastic Beanstalk.

1. Search for CodeBuild using the search bar, then click the result to open the service.

2. Click on the CodeBuild project you created in the last step.

3. Near the top of the page, click Edit, then click Environment.

4. Click Additional configuration to show advanced options.

5. In the Environment Variables section, add all of the values you removed from your .env.production (or other) file, including APP_KEY. Note that you should not run php artisan key:generate in any deployment pipeline, as this will generate a new key each time a new version of your app is deployed.

6. Click Update environment.

7. Near the top of the page, click Edit, then click Buildspec.

8. Click Insert build commands, then click Switch to Editor

9. Replace the editor with the following contents. In the pre_build commands section, be sure to enter the name of the .env file you created earlier.

version: 0.2phases:
install:
runtime-versions:
php: 7.4
nodejs: 12.x
commands:
- apt-get update -y
- apt-get install -y libpq-dev libzip-dev
- apt-get install -y php-pgsql
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
pre_build:
commands:
- cp .env.beta .env
- composer install
- npm install
build:
commands:
- npm run production
- php artisan migrate --force
- php artisan db:seed
artifacts:
files:
- '**/*'
name: $(date +%Y-%m-%dT%H:%M:%S).zip
proxy:
upload-artifacts: yes
logs: yes

10. If you have any additional build commands required to deploy your application, add them here.

11. Click Update buildspec.

Step 7: Secrets Manager

If you are using Laravel Passport for OAuth authentication, you will deploy your OAuth keys to your application with AWS Secrets Manager. In Step 1 you should have added a script that retrieves these keys and copies them into your app’s storage folder on the server.

If you are not using Laravel Passport, skip to Step 8.

1. Search for Secrets Manager using the search bar, then click the result to open the service.

2. Click Store a new secret.

3. Click Other type of secrets.

4. In the left field, enter OAUTH_PUBLIC_KEY, and in the right, copy the value of your app's storage/oauth-public.key.

5. Click + Add Row.

6. In the left field, enter OAUTH_PRIVATE_KEY, and in the right, copy the value of your app's storage/oauth-private.key.

7. It is ok that when pasting the key file values into Secrets Manager, the multiline values are condensed into a single line. The script you added in Step 1 handles splitting it into the proper format again upon deployment.

8. Click Next.

9. Enter the name of your application and environment (e.g. MY_APP_BETA or MY APP_PRODUCTION) for the Secret name.

10. Record the name you enter here for use in the next step.

11. Click Next.

12. Click Next again.

13. Click Store.

Step 8: IAM

Since we are using Secrets Manager, you have to grant CodeBuild and Elastic Beanstalk permission to access your secrets.

1. Search for IAM using the search bar, then click the result to open the service.

2. In the left side panel click Policies.

3. Click Create Policy.

4. Click the JSON tab, then replace the editor contents with the following.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:*:014079349738:secret:*"
}
]
}

5. Click Review Policy.

6. Enter SecretsManagerRead for the Name. Click Create Policy.

7. In the left side panel click Roles.

8. Use the search bar to search codebuild. Click on the role that includes the name of your CodeBuild project.

9. Click Attach policies.

10. Use the search bar to search SecretsManagerRead, then click checkbox next to the policy.

11. Click Attach policy.

12. In the left side panel click Roles.

13. Use the search bar to search aws-elasticbeanstalk-ec2-role. Click on the role.

14. Click Attach policies.

15. Use the search bar to search SecretsManagerRead, then click checkbox next to the policy.

16. Click Attach policy.

Step 9. Finish Configuration

Before we can deploy your application, there are a few more things we have to configure.

1. Search for Elastic Beanstalk using the search bar, then click the result to open the service.

2. Click on your application environment.

3. In the left side panel, click Configuration under your application environment.

4. In the row called Software, click Edit.

5. In the Document root section, enter /public.

6. In the Environment properties section, add all of the values you removed from your .env.production (or other) file, including APP_KEY.

7. In the Environment properties section, add a key called AWS_ENV, and enter the name of your Secrets name from earlier (MY_APP_BETA or MY_APP_PRODUCTION were used as examples).

8. Click Continue.

9. In the row called Load balancer, click Edit.

10. Near the top of the page, click + Add listener.

11. For Port enter 443. For Protocol, choose HTTPS. For SSL Certificate, choose the certificate you created earlier in Step 3. Click Add.

12. Click Apply.

13. You will be redirected to the status page for your environment. While it is deploying the changes, you can continue to the next steps.

14. Search for Route 53 using the search bar, then click the result to open the service.

15. In the left side panel, click Hosted zones.

16. Click on your domain.

17. Click Create record.

18. Leave the option on the default, Simple routing. Click Next.

19. Click Define a simple record.

20. Enter the subdomain you want to use for your application. If none, leave the first field empty.

21. In the dropdown, choose Alias to Elastic Beanstalk environment. Choose your region, then select the Elastic Beanstalk environment you created earlier.

22. Click Define simple record, then click Create records.

Step 10: Deploy

Finally, it’s time to deploy your application!

1. Search for CodePipeline using the search bar, then click the result to open the service.

2. Click on your application’s pipeline.

3. Click Release Change.

4. Watch it build. Once all the circles are green, you can test your application!

5. Visit your application in your browser by entering the domain name you chose earlier.

Now any time you push changes to your deployment branch, the change will be automatically deployed through your CodePipeline project and onto Elastic Beanstalk. The pipeline usually takes about 5–10 minutes to run completely, so don’t worry if you don’t see changes immediately. You can also monitor the progress of your pipeline in the CodePipeline service page in the AWS console.

In addition, your site will be deployed with an SSL certificate, allowing you to use the protected https protocol in your app URL. With the configuration script you added to your Laravel project, your app will also automatically any unprotected http calls to the secure https connection.

--

--