How to deploy a Ruby on Rails application to AWS Elastic Beanstalk

by Jason Swett,

Overview

This tutorial will show you how to deploy a Rails application to AWS Elastic Beanstalk.

Using Elastic Beanstalk is just one of many (perhaps an infinite number of!) AWS deployment options. Each approach has different pros and cons. I’ll briefly go over some of them because it’s good to understand the pros and cons of various approaches (at least to an extent) before choosing one.

Manual EC2 deployment

One option is to do things “the old fashioned way” and manually set up a Rails application on a single EC2 instance. This is the approach I go over in this AWS/Rails deployment post and it’s perfectly fine for hobby projects where the stakes are low.

The downside to manual EC2 deployment is you end up with a snowflake server, a server with a one-of-a-kind configuration that’s hard to understand, modify, or replicate.

Elastic Beanstalk

Elastic Beanstalk is kind of analogous to Heroku. The basic idea is the same in that both Elastic Beanstalk and Heroku are abstraction layers on top of AWS services. The big difference is that Heroku is generally really easy and Elastic Beanstalk is a giant pain in the ass.

But the upside is that EB provides more easily replicable and understandable server instances than a manual EC2 instance. The server configuration is expressed in files, and then that configuration can be applied to an indefinite number of servers. This makes scaling easier. It’s also nice to know that if I somehow accidentally blow away one of my EC2 instances, EB will just automatically spin up a new identical one for me.

Another drawback to EB is that I understand EB can be kind of overly rigid. I ran into this trouble myself on a project where I needed to set up Sidekiq. I discovered that EB boxed me in in a way that made Sidekiq setup very difficult. So for a production project that grows over time, EB is perhaps a good place to start, but it should be expected that you might want to migrate to something more flexible sometime in the future.

An infrastructure-as-code approach

An infrastructure-as-code approach is probably the best long-term solution, although it currently also seems to be the most difficult and time-consuming to set up initially.

Options in this area include Ansible, Chef, Puppet, ECS, and probably a lot more. I’ve personally only used Ansible. I found Ansible to be great. This post will of course only cover Elastic Beanstalk though.

Configuration steps

Here are the steps we’ll be carrying out in this tutorial.

  1. Install the Elastic Beanstalk CLI
  2. Create the Elastic Beanstalk application
  3. Create the Elastic Beanstalk environment
  4. Create the RDS instance
  5. Deploy

Let’s get started.

Install the Elastic Beanstalk CLI

Much of what we’ll be doing involves the Elastic Beanstalk CLI (command-line interface). It can be installed with this command:

Create the Elastic Beanstalk application

Now cd into the directory that contains your Rails project and run eb init.

When prompted, Select Create new Application. Accept the defaults for all other options.

When this command finishes running you’ll end up with a file called .elasticbeanstalk/config.yml that looks something like this:

Now that we’ve created our Elastic Beanstalk application, we’ll need to create an Elastic Beanstalk environment inside of that application. I typically set up one production environment and one staging environment inside a single application.

Create the Elastic Beanstalk environment

The command to create an environment is eb create.

You’ll be prompted for what to call your environment. I called mine discuss-with-production.

For load balancer type, choose application.

This step will take a long time. When it finishes, health will probably be “Severe”. Ignore this.

Set up SECRET_KEY_BASE

We’ll need to set a value for the SECRET_KEY_BASE environment variable. This can be done using the following eb setenv command which just sets the variable to a random string.

Set up ebextensions

With Elastic Beanstalk, you can add files in an .ebextensions directory at your project root to control how your server is configured. We need to add three ebextensions files.

The first, .ebextensions/01_ruby.config, looks like this:

The second, .ebextensions/02_yarn.config, looks like this:

The last, .ebextensions/gem_install_bundler.config, looks like this:

Deploy the application

Now we can make our first deployment attempt.

Unfortunately, it doesn’t work. We get an error that says: /opt/elasticbeanstalk/hooks/appdeploy/pre/12_db_migration.sh failed.

Why does this happen? Because he haven’t set up a database yet. Let’s do that now.

Create the RDS instance

In the AWS console, go to RDS, go to Databases, and click Create database.

Choose Postgresql and Free tier.

Choose whatever name you like for your database. I’m calling mine discuss-with-production

For size, choose t2.micro.

Make sure to set public accessibility to Yes so you can remotely connect to your database from your development machine.

Click Create database.

On the next screen, click View credential details.

Copy what’s there to a separate place for later use. You’ll also need the RDS instance’s endpoint URL which is found in a different place, under Connectivity & security and then Endpoint & port.

Make sure your database’s security group has port 5432 open.

Set the database credentials and create the database instance

Our production server will need to know the database endpoint URL and database credentials. Run the eb setenv command, with your own values of course replaced for mine, to set these values.

Even though the RDS instance exists, our actual PostgreSQL instance doesn’t exist yet. The RDS instance itself is more like just a container. We can run the rails db:create command remotely on the RDS instance by supplying the RDS endpoint URL when we run rails db:create.

Before running this command, make sure the production section of config/database.yml matches up with these environment variable names as follows:

Now create the database.

Deploy the application

Now the application can finally be deployed for real using eb deploy.

Once this finishes you can use the eb open command to visit your environment’s URL in the browser.

  •  
  •  
  •  
  • 2

4 thoughts on “How to deploy a Ruby on Rails application to AWS Elastic Beanstalk

  1. DEMIAN

    This is a great tutorial. Better than the AWS one which seems to leave stuff out? I still get ‘502 Bad Gateway nginx/1.16.1’ error. I deployed my app, created a database in RDS and set up the environment but still no luck. I’m using Rails 6. Any ideas?

    :

    Reply
  2. Demian

    It appears the main problem is that the EB environment can’t locate a gem file:

    /opt/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/bundler.rb:237:in rescue in root': Could not locate Gemfile or .bundle/ directory (Bundler::GemfileNotFound)
    from /opt/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/bundler.rb:233:in
    root’
    from /opt/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/bundler.rb:80:in bundle_path'
    from /opt/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/bundler.rb:554:in
    configure_gem_home’
    from /opt/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/bundler.rb:535:in configure_gem_home_and_path'
    from /opt/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/bundler.rb:66:in
    configure’
    from /opt/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/bundler.rb:134:in definition'
    from /opt/elasticbeanstalk/support/scripts/check-for-gem.rb:21:in

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *