Laravel 5 Configurations in AWS Elastic Beanstalk

I’m working on a new project that is running an API using Laravel 5. We’re also hosting it on Amazon’s Elastic Beanstalk service, which gives us great scaling capabilities on the fly. However, since new instances of your application can be added/removed on the fly, setting your configuration requires a little more tweaking than the base install provides.

With Laravel 5, they have adopted the phpdotenv library to provide a flexible configuration setup. Simply create a .env file in the root of the site with the configuration overrides that you need, and the library will load them into the environment variables. You’ll see that in configuration files in Laravel will contain code such as:

'key' = env('APP_KEY', 'SomeRandomString’)

Which will check for an environment variable named APP_KEY, or default to the alternate value. Before this code has run, phpdotenv has already found our .env file and loaded our APP_KEY value into the environment accordingly.

Both phpdotenv, and Laravel, use the mindset that the overrides are intended for development use only, so your production values should be in the configuration files. This brings up two issues that we have to resolve.

AWS RDS Connection Strings

If you have an AWS RDS database in conjunction with your database, Amazon does a great thing and auto-generates environment variables that you need to connect to your database. These are easily referenced through variables such as $_SERVER[“RDS_HOSTNAME”]. However, the .env file is designed to have basic text, so you can’t put a server variable there. In addition, if you put this value into the “default” condition in the env() method, it generates an error in local development, because from what I can see, env tries to retrieve both values and then evaluate them, instead of finding the env first and then continuing. While you could technically put the actual database values that AWS provides (which are very cryptic for security), I still don’t like that prospect in the event that I have multiple databases scaled up through RDS or they change on me. Instead, we change our app/database.php file to use the shortcode ternary operator instead:

'host' = env('DB_HOST') ?: $_SERVER["RDS_HOSTNAME"]

This will do our standard env check. In the local environment our .env file will already have DB_HOST set. In production, with no .env file, this value will be null, so we then grab our RDS_HOSTNAME value and set that for our DB_HOST. We have a dynamic setting that is secure, and we can still have our local overrides without hassle.

Using .env for Staging Environment

So by now, your configuration files have all of your production values, and for your local development you have your .env file in place with all of your local overrides in it. But what do you do for your staging environment? For me, we have an EB instance up and running, but some of our configuration values (like URLs and app keys) are different than production. How do we account for this?

One thing we could do is to SSH in to the server, create a .env file with our settings, and let things run as usual. The problem with this is that as soon as we push a fresh code change up, EB will build a new instance and that .env file is wiped out. We could add extra server side conditions to our configuration files based on the server name, but with the dynamic nature of EB, those server names could change as well.

What we do instead is we create a special “elastic beanstalk” version of our .env file that we check into our code repository, and then add some additional instructions to our EB deployment. In case you didn’t know, you can create a .ebextensions folder in the root of your project and add additional commands, configurations, etc to your EB instance. More details about that can be found here.

The first step is to create a .env.elasticbeanstalk file in the root of our project and put our staging details in there, it could be something as:

APP_ENV=staging
APP_DEBUG=true
APP_URL=staging.example.com

Then, in our .ebextensions folder, we create a new file, named 01envconfig.config and add the following lines:

container_commands:
   # Copy EB env configuration file over
   01_config_environment:
      command: mv /var/app/ondeck/.env.elasticbeanstalk /var/app/ondeck/.env

Note that spacing is important here and not to use tab characters.

Save these files and run your Elastic Beanstalk deployment again. What will happen is that your elasticbeanstalk config file will be renamed .env, allowing you to have your staging overrides in place. You can update this later to use a different file or command if necessary when deploying to your production environment.

There you have it, a nice way to handle managing Laravel 5 configurations with Elastic Beanstalk that will handle your local/staging/production unique configurations as well as remain stable and flexible during any scaling/deployments that AWS EB will do for you.

If you know any other tricks, make sure to share them!

8 thoughts on “Laravel 5 Configurations in AWS Elastic Beanstalk

  1. I am having hard time to setup laravel 5.1 on beanstalk. Not sure how to update my code each time and, where to store the media files…. any help is much appreciated. I used only shared server/cpanel … i would like to use aws, but no success

    1. With AWS / EB, you have to remember that your servers are essentially “rebuilt” with every new code push. So any resources that are uploaded by users would be lost with the next code push.

      To work around this, I’d suggest storing your resources in Amazon S3. There is a simple filesystem library that will help you interface with it easily in Laravel and you won’t lose the data if you code push. In addition, if you wind up having multiple servers, you don’t have to worry about potential duplicate files in your system.

  2. Hi dillie

    lets say i have 2 env in EBS so i want to deploy my code to production
    so how to do that ?

    do we need make 2 file .env for example .staging.env and .production.env
    once the ebs is starting running the file will be automaticly copy file to root staging ENV or prodcution ENV

    Thx,
    Lukman

    1. So for our scenario similar to that, I only used one .env.elasticbeanstalk file, but I had them configured different (connections strings, variables, etc.) in our master vs release branches in source control (git).

      This worked out best for us because we were using an intermediate continuous integration solution (dploy.io) that could deploy from either and as long as you were mindful of your merges from master to release, there haven’t been any problems to date.

      There are a few different scenarios to handle this. We could have stored our .env.elasticbeanstalk file separately in dploy.io and had it injected as part of the solution, keeping it out of the repo (and potential conflicts), but I didn’t like having that one external file in a separate resource when everything else was in the code branch. There might be options to have special configurations based on some kind of environment variable on the server during the deployment process, which would have allowed us to have two separate files, but I wasn’t able to track anything down.

      Admittedly I’m still quite fond of how .net does it, through web.config transforms or environment flags and the use of .staging and .production files. It allows you to keep multiple configuration without the concern of conflicts and the deployment model can handle inserting the right config file automatically.

      1. hi dillie ,

        thx a lot for your explanation , i’m still reconfig n retesting regarding the laravel on my EBS already config 2 instance on ebs staging n prod , have tried different scenario to make my deployment is success ,

        i had wrote bash script like this put in the .ebextension but looks like my script is not running hiks hiks :(

        #!/usr/bin/env bash

        if [ “$DEPLOYMENT_GROUP_NAME” == “campaign-env-staging” ]
        then

        cat /var/app/ondeck/env/07-staging.config > /var/app/current/.staging.env

        else [ “$DEPLOYMENT_GROUP_NAME” == “campaign-env-prod” ]

        cat /var/app/ondeck/env/08-prod.config > /var/app/current/.prod.env

        fi

        1. You might have to check the AWS documentation on that deployment script to see if there are environment detection items for that. I haven’t checked recently.

What are your 10 bits on the matter? I want to know!

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s