Deployment.io

Deploy a Ruby on Rails app on AWS


Deployment.io builds your Rails app with the Dockerfile Rails generates. It runs the app on AWS Fargate behind a load balancer, in your own AWS account.

Before you start

  • Your app uses Rails 7.1 or later. rails new generates a production Dockerfile at the root of the app. An older app needs its own Dockerfile first.
  • The app is in a GitHub, GitLab or Bitbucket repository connected to Deployment.io. See Adding a Repository.

Deployment

  1. Add your app's secret key to the environment you'll deploy to. Open Resources → Environments, open the environment and click Edit. Use Add Environment Variable to add RAILS_MASTER_KEY with the contents of your app's config/master.key (that file isn't in your repository). Save. Note: an environment's variables are available to every service in that environment.
  2. Create a new Web Service on Deployment.io and select the repository.
  3. Leave Dockerfile Path empty. The Dockerfile is at the root.
  4. Port number: the port in your Dockerfile's EXPOSE line. That's 80 for Rails 8 (the image runs Thruster in front of Puma) and 3000 for Rails 7.1 and 7.2.
  5. Health check path: /up. This is Rails' built-in health check.
  6. If the app has a database, set Pre-deploy command to bin/rails db:prepare. See Database below.
  7. Choose the Environment and click Deploy web service.

Your app will be available at the load balancer URL shown in the dashboard as soon as the deploy finishes. For the other fields, see Deploying a Web Service.

Try it with the example app

Fork deployment-io/rails-hello-world on GitHub. It's a minimal Rails 8 app with no database.

It has no credentials file. So instead of RAILS_MASTER_KEY, add SECRET_KEY_BASE to the environment's variables. You can generate one with openssl rand -hex 64.

Then deploy it as above with Port number 80 and Health check path /up.

Database

Don't rely on SQLite (Rails 8's default) in production. A container's files don't survive a deploy, and each running copy of the service has its own. Use PostgreSQL (or MySQL) instead, for example a database created under Resources → Databases.

  • Rails 7.1 and 7.2: set DATABASE_URL in the environment's variables, e.g. postgres://USER:PASSWORD@HOST:5432/myapp_production.
  • Rails 8: production uses four databases on the same server. One is the app's, and there are separate ones for its cache, queue and Action Cable (Solid Cache, Solid Queue and Solid Cable). Set all four URLs, with a different database name in each: DATABASE_URL, CACHE_DATABASE_URL, QUEUE_DATABASE_URL and CABLE_DATABASE_URL. DATABASE_URL alone isn't enough: the other three would try a local database and the app wouldn't start.

bin/rails db:prepare creates the databases that don't exist yet and runs pending migrations. As the Pre-deploy command, it runs once per deploy, before the new version gets traffic. (The image's entrypoint also runs it when the server starts. After the pre-deploy command, that does nothing.)

HTTPS

The load balancer URL is plain HTTP. Rails' production settings expect HTTPS (config.force_ssl = true).

  • Rails 8: pages load on the load balancer URL. But Rails marks its session cookie secure, so the browser won't send it back over HTTP. Sign-in and forms don't work there.
  • Rails 7.1 and 7.2: every request to the load balancer URL redirects to https://, which that URL doesn't answer. Pages don't load there.

Add a custom domain to serve the app over HTTPS. See Adding Custom Domains. The load balancer tells Rails the request came over HTTPS, so no Rails setting needs to change.

Good to know

  • Your app's logs are on the service's page. See Checking Application Logs.
  • Add any other variables your app needs to the environment's variables the same way.