Menu Octopus Deploy

Deploy Ruby on Rails to AWS: a practical guide

What is Ruby on Rails?

Ruby on Rails, often called Rails, is a popular open-source web application framework written in the Ruby programming language. It follows the model-view-controller (MVC) pattern, which separates concerns in the codebase, making large-scale web applications easier to maintain and extend. Rails provides a set of conventions and generators that speed up common development tasks, including database migrations, routing, asset management, and authentication.

The “convention over configuration” philosophy in Rails reduces the number of decisions developers need to make, streamlining the development workflow. Rails is used by startups and established companies for its productivity and tooling. It is in active development, with the latest major version, Rails 8.0, released in late 2024.

This is part of a series of articles about software deployment.

Benefits of deploying Ruby on Rails to AWS

Deploying Ruby on Rails on AWS provides a scalable and reliable infrastructure for running production applications. AWS offers a variety of managed services that align well with the architecture of a typical Rails app, from databases to caching to background job processing. Leveraging AWS can reduce operational overhead and improve performance, especially for applications expecting growth or variable traffic.

Benefits of deploying Ruby on Rails on AWS:

  • Scalability: AWS enables horizontal and vertical scaling of Rails applications using services like EC2 Auto Scaling, Elastic Load Balancing, and managed RDS for databases.
  • High availability: With AWS’s multi-AZ and regional infrastructure, applications can achieve greater fault tolerance and uptime.
  • Managed services: Rails apps can benefit from AWS offerings such as RDS for PostgreSQL/MySQL, ElastiCache for Redis, and S3 for asset storage, all reducing the need for manual maintenance.
  • Security: AWS provides integrated security tools like IAM, VPC, and security groups, making it easier to control access and secure applications and data.
  • Infrastructure as code: With tools like CloudFormation and Terraform, developers can provision and manage AWS resources in a repeatable, version-controlled manner.
  • Global reach: AWS has a global network of data centers, allowing Rails applications to serve users with low latency across different regions.
  • Integration with CI/CD pipelines: AWS supports smooth integration with deployment workflows using services like CodeDeploy, CodePipeline, and third-party CI/CD tools.

Tutorial: deploying a Rails application to AWS Elastic Beanstalk

This tutorial explains how to deploy a Ruby on Rails application to AWS Elastic Beanstalk using the Ruby platform. You’ll go through setting up dependencies, generating a Rails app, preparing it for deployment, configuring environment variables, and deploying it to a fully managed AWS environment. Instructions are adapted from the AWS documentation.

Prerequisites

Ensure the following components are installed:

  • Ruby (2.5.0 or newer)
  • Rails
  • Node.js
  • Yarn

To install Rails:

gem install rails

Installing Rails with gem

Verify the installation:

rails --version
# Rails 7.1.5.2

Checking the installed Rails version

Install Node.js and Yarn using your package manager or by following platform-specific instructions.

Step 1: create a new Rails project

Generate a new Rails application:

rails new ~/eb-rails

This will create a directory named eb-rails with a complete Rails app scaffold. Change into the new directory:

cd ~/eb-rails

Start the server locally to test:

rails server

Then open http://localhost:3000 or http://<YOUR-SERVER-IP>:3000 in your browser. You should see the default Rails welcome page.

The default Rails welcome page

Step 2: create a homepage for production

Use Rails generators to create a welcome page:

rails generate controller WelcomePage welcome

Generating the welcome page controller

This creates a controller, view, route, helper, and associated assets. Now edit the generated view file app/views/welcome_page/welcome.html.erb:

<h1>Welcome!</h1>
<p>This is the front page of my first Rails application on Elastic Beanstalk.</p>

Make the new page the root of the app by updating your routes in config/routes.rb:

Rails.application.routes.draw do
  get 'welcome_page/welcome'
  root 'welcome_page#welcome'
end

Step 3: prepare for deployment

Update the lockfile to include the Ruby platform to avoid compatibility issues during deployment:

bundle lock --add-platform ruby

Adding the Ruby platform to the lockfile

Prepare your application for deployment by zipping the project directory:

zip ../rails-default.zip -r * .[^.]*

This creates a file named rails-default.zip in the parent directory, containing all your app files and configuration.

Step 4: launch an Elastic Beanstalk environment

Use the AWS Management Console:

  1. Go to the Elastic Beanstalk console.

    The Elastic Beanstalk console

  2. Click Create Application.

  3. Set Platform to Ruby and use the Load balanced environment type.

    Configuring the Ruby platform

  4. Select Sample Application for the initial deployment.

  5. Click Next to configure relevant service access.

  6. The rest of the steps are optional (unless you need a specific VPC or security group); click Skip to Review to continue to the summary page.

    Skipping to the review page

  7. On the Summary page, click Create App.

This takes about 5 minutes and provisions the following resources:

  • EC2 instance with a pre-configured Ruby environment
  • Security groups for instance and load balancer access
  • Elastic load balancer to distribute traffic
  • Amazon S3 bucket to store deployment artifacts
  • Auto scaling group and CloudWatch alarms
  • CloudFormation stack to manage resources

The provisioned Elastic Beanstalk environment

Step 5: set environment variables

Rails requires a SECRET_KEY_BASE environment variable in production. Set it in the Elastic Beanstalk console:

  1. Navigate to your environment.
  2. Go to Configuration > Software.
  3. Click Edit under Environment properties.
  4. Add a new variable with Name SECRET_KEY_BASE and Value <your_secure_key>.

You can generate a secure key with:

rails secret

Generating a secret key

Avoid storing this value in source control.

Step 6: deploy the application

In the Elastic Beanstalk console:

  1. Go to your environment.
  2. Click Upload and deploy.
  3. Choose the rails-default.zip file.
  4. Click Deploy.

Uploading and deploying the application

Once the deployment completes, you’ll see a URL in the environment overview. Click it to view your Rails app in the browser.

The deployed Rails app in the browser

Best practices for deploying Rails on AWS

Store assets and uploads in S3 with CloudFront

Rails applications typically serve static assets (CSS, JS, images) and handle user uploads (e.g., avatars, documents). Hosting these on the app server increases memory usage and slows down response times.

Instead, configure Active Storage (built-in since Rails 5.2) or use CarrierWave to upload directly to Amazon S3. Update config/storage.yml for Active Storage or config/initializers/carrierwave.rb for CarrierWave to use the S3 service. Ensure credentials and bucket names are managed through environment variables.

For faster global delivery, use Amazon CloudFront with your S3 bucket. CloudFront caches content at edge locations, reducing load times and bandwidth costs. Configure long-lived cache headers on assets and enable HTTPS for secure transmission.

Example Active Storage config:

amazon:
  service: S3
  access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
  region: us-east-1
  bucket: your-app-assets

Use RDS with high availability

Rails apps rely heavily on a relational database, and uptime is critical. Amazon RDS with Multi-AZ deployments ensures high availability by automatically replicating your database to a standby in another Availability Zone.

In production, choose a supported engine like PostgreSQL or MySQL. Enable Multi-AZ to get automatic failover and regular backups without manual intervention. Use RAILS_MAX_THREADS and database connection pool settings to match the instance size and concurrency level.

Monitor performance using Amazon CloudWatch metrics like read/write IOPS, CPU, and free memory. Use read replicas for scaling read queries, reporting, or background jobs.

Database settings in config/database.yml should reference environment variables for credentials and endpoint names to keep the codebase portable.

Add caching with ElastiCache

To reduce database load and speed up page rendering, use caching at various layers of your Rails app. Amazon ElastiCache supports Redis and Memcached, both of which can act as a centralized cache store.

Use Redis with redis-rails for session storage, fragment caching, and background job queues (e.g., Sidekiq). Configure your cache store in config/environments/production.rb:

config.cache_store = :redis_cache_store, {
  url: ENV['REDIS_URL'],
  namespace: 'my-app-cache'
}

ElastiCache clusters should be provisioned in the same VPC as your app for low-latency access. Use security groups to allow connections only from your application instances.

Regularly monitor cache hit/miss ratios and evictions in CloudWatch, and scale your cache nodes as needed to prevent performance bottlenecks.

Secure credentials with Secrets Manager or Parameter Store

Hardcoding sensitive information in source code or configuration files is a common security risk. AWS Secrets Manager and Systems Manager Parameter Store offer encrypted storage for secrets, along with IAM-based access control.

Secrets Manager is better suited for managing database passwords, API keys, and third-party credentials. Use the AWS SDK to fetch secrets dynamically at runtime or inject them as environment variables via Elastic Beanstalk configurations.

Parameter Store can be used for non-sensitive configuration values, organized hierarchically by environment and application.

To integrate with Rails, use gems like aws-sdk-ssm or dotenv to load secrets during boot. For example:

# Fetching a secret at runtime
client = Aws::SSM::Client.new
param = client.get_parameter(name: "/my-app/production/database_password", with_decryption: true)
ENV['DB_PASSWORD'] = param.parameter.value

Use IAM roles attached to your EC2 or Beanstalk instances to grant least-privilege access to specific parameters or secrets.

Implement auto scaling and load balancing

To handle changing traffic patterns without manual intervention, implement auto scaling and load balancing. Elastic Beanstalk makes this straightforward with load-balanced environments that include an ELB and an Auto Scaling group by default.

Configure instance scaling policies based on metrics like CPU usage (e.g., scale out at 70%, scale in at 30%). Use CloudWatch alarms to trigger these changes automatically.

Application load balancers (ALBs) support path-based routing, SSL termination, and health checks. Ensure your Rails app responds with a 200 status for health check endpoints to prevent unnecessary restarts.

You can also configure scheduled scaling (e.g., higher capacity during business hours) to reduce costs. Monitor scaling activity and instance health in the Beanstalk and EC2 dashboards to ensure reliable operation.

Help us continuously improve

Please let us know if you have any feedback about this page.

Send feedback

Categories:

Next article
Software delivery lifecycle