---
title: "Rails hosting on Fly.io: convention over configuration for your infrastructure"
description: "Rails hosting on Fly.io, with convention over configuration for your infrastructure. fly launch configures your app, and migrations run before every deploy."
---

# Rails hosting on Fly.io: convention over configuration for your infrastructure

Build and scale Rails apps on a developer-focused public cloud.

[Launch Now](https://fly.io/app/sign-up)

Ready, Set, Go!

## Speedrun Your Rails App Onto Fly.io

Deploy a Rails app to Fly.io in a few minutes with Fly.io's command line tool, `flyctl`.

[Get Started](https://docs.fly.io/rails/getting-started)

```
> Install flyctl on GNU/Linux
$ curl -L https://fly.io/install.sh | sh

> Run from Rails project root
$ fly launch

> Scale CPU, memory, instances & regions
$ fly scale
```

Not on GNU/Linux? [Install flyctl for your platform.](https://docs.fly.io/flyctl/install)

Up-to-Date with Best Practices

## Managed TLS, HTTP/2, Fast launching Docker VMs, Kubernetes & More

Fly.io utilizes the latest standards, open-source tools, and hardware to give Rails developers a modern production environment free from vendor lock-in. We manage it all so you don't have to.

A Secure & Productive Coexistence

## WireGuard, Private Networks, TLS & Encrypted Volumes

Each Fly.io app launches by default with its own private network and encrypted volumes so you can focus on building apps instead of wrestling with IAM or writing firewall rules. Your security team will like us.

Scale up, down, or to zero.

## Idle Machines Stop, and the Next Request Starts Them Again

Fly Proxy stops Machines that have no traffic and starts them on the next request, and a stopped Machine isn't billed for CPU or RAM. When load grows, one command, fly scale, changes memory, CPU, or the Machine count. Fly Machines boot Rails Docker images in a few seconds directly on our metal servers.

NEW!

## Managed Postgres for Rails Projects

Focus on features and leave database management to Fly.io. Our Managed Postgres service, gives you:

- Automatic backups and recovery
- High availability with automatic failover
- Performance monitoring and metrics
- Resource scaling (CPU, RAM, storage)
- Automatic encryption of data at rest and in transit

[Learn More](https://fly.io/mpg/)

## Trusted by teams at

- **Built for HTML Over the Wire Turbo & ActionCable Apps**
  Fly Proxy sits in front of your Machines, terminates TLS with managed certificates, and load balances your app for you via HTTP/2 with Brotli compression and encrypted WebSockets. Turbo Streams and ActionCable connect through it with no proxy or certificate of your own to run.
- **S3-Compatible ActiveStorage, Set Up in One Command**
  Tigris is S3-compatible object storage run on Fly.io. fly storage create makes a bucket and sets its credentials as secrets on your app, so ActiveStorage's S3 service reads them from the environment with no keys to copy by hand.
- **Managed Databases & Services**
  Supabase for Postgres. LiteFS for SQLite. Upstash for a popular key/value store 😉. Fly.io's Omakase menu of fully managed services run on our infrastructure, and fly redis create writes REDIS_URL onto your app as a secret, so there is no connection string to paste.

## Ready to Take Flight?

Fly.io was built for Rails developers who want to run Rails apps without all the fuss of managing the underlying infrastructure. fly launch detects Rails, writes the Dockerfile and fly.toml, and deploys in a few minutes, and fly deploy ships every release after that.

[Get Started](https://fly.io/app/sign-up)

## What Rails is, and what it's used for

Ruby on Rails is a server-side web application framework written in Ruby. It follows the model-view-controller pattern and ships with conventions for routing, persistence (ActiveRecord), background work, asset compilation, and almost every other piece of infrastructure a web app needs.

The "convention over configuration" idea cuts in two directions. You spend less time wiring things up, and you spend more time learning what Rails has already decided for you. That trade is usually worth it. A team can ship a real product on Rails in days, and the resulting codebase is recognizable to anyone else who has worked on a Rails app before.

Rails powers everything from solo side projects to multi-tenant SaaS at scale. GitHub, Shopify, Basecamp, and a long tail of smaller apps run on Rails. It is not the right tool for every job (a static marketing site does not need an ORM and a job queue), but for an interactive app that owns data and serves authenticated users, Rails removes most of the boilerplate decisions you would otherwise spend a week making.

On Fly.io, Rails runs as a standard Ruby app on Fly Machines, alongside Postgres, Redis, and any other services your app needs. Nothing about the framework is forked or wrapped. The same Rails you run on your laptop runs in production here.

## Deploy a Rails app to Fly.io: the actual flow

The flow is three commands: install `flyctl`, run `fly launch`, then `fly deploy` for every change after that.

The first command installs the CLI:

```
curl -L https://fly.io/install.sh | sh
```

`flyctl` is the only tool you need on your machine. Authenticate with `fly auth login` once.

The second command kicks off your first deploy:

```
cd path/to/your/rails/app
fly launch
```

`fly launch` walks through a short wizard. It detects that your app is Rails by reading `Gemfile` and `bin/rails`, picks a region, generates a `Dockerfile`, `bin/docker-entrypoint`, `config/dockerfile.yml`, and `.dockerignore`, and writes a `fly.toml` to your repo. After the wizard finishes, the app builds and deploys, and you get a URL to hit. Provision your database (Managed Postgres) and Redis as separate steps after launch. We cover both in the sections below.

For every change after the first deploy, run `fly deploy`. That rebuilds the image, pushes it to our registry, and rolls a new version onto your Machines with no downtime. No CI required to get started; you can wire it up later when you're ready.

## Deploying an existing Rails app

`fly launch` works the same way on an existing Rails codebase as it does on a brand new one. The wizard reads your `Gemfile.lock`, picks the Ruby version your project pins, and bundles the gems you depend on. It also reads `config/master.key` and stores it as a Fly secret so `config/credentials.yml.enc` decrypts at boot.

This is true regardless of how old your app is. A Rails 6 app, a Rails 5 app, even a Rails 4 app will boot if you have a sane `Gemfile.lock` and a `config.ru` that Puma can serve. Rails 8 is supported out of the box, since the generated `Dockerfile` uses whichever Ruby version your `Gemfile` pins and the base image is updated as new Rubies ship.

What `fly launch` cannot do is detect every custom step your existing deploy pipeline runs. If you have a Heroku app with custom buildpacks, npm steps, asset pipelines that depend on environment variables, or release hooks that touch external services, take a few minutes after `fly launch` finishes to review the generated `Dockerfile` and `fly.toml`. The `[deploy] release_command` slot in `fly.toml` is the right place to add custom pre-boot steps (migrations, asset upload to a CDN, cache warmers, anything else).

## Postgres on Fly.io for Rails

The recommended path is Fly.io Managed Postgres (MPG). MPG handles automatic backups and recovery, high availability with automatic failover, performance monitoring, resource scaling, and encryption of data at rest and in transit. We no longer support the older unmanaged `fly postgres` path; MPG is the supported way to run Postgres on Fly.io.

Provision a cluster and attach it to your app:

```
fly mpg create
fly mpg list
fly mpg attach your-cluster-id -a your-app-name
```

`fly mpg create` walks through plan, region, and volume size. `fly mpg list` shows the cluster ID. `fly mpg attach` writes the `DATABASE_URL` secret onto your app and reboots it. You're now connected.

Your `database.yml` doesn't change. Run `fly deploy` after the attach. Migrations run on the next release via the `release_command` in `fly.toml` that `fly launch` sets up for you (see the next section).

## What you didn't have to set up

Look back at what actually happened. You ran `fly launch`, then `fly mpg create` and `fly mpg attach`. A standard Rails app with a Postgres database in one region is the ordinary case Fly.io is built for, not a stretch. Here is the work that never appeared:

**A hosting service for your code.** `fly launch` and `fly deploy` build from the directory you are standing in. A Rails app with no git remote at all deploys fine.

**A Dockerfile.** `fly launch` detects Rails and writes one, along with the `fly.toml`. Both land in your repository where you can read them, edit them, and see them in a diff.

**A connection string.** `fly mpg attach` writes `DATABASE_URL` onto the app as a secret. Your `database.yml` does not change, and the password never lands in your clipboard or your shell history.

**A migration step in a deploy pipeline.** `fly launch` writes `release_command` into `fly.toml`, so migrations run on a throwaway Machine before any Machine takes traffic. A migration that fails fails the deploy, instead of half migrating production.

**TLS and a hostname.** The app answers on `<app>.fly.dev` with HTTPS from the first request, and the certificate is issued and renewed for you.

**A load balancer or a VPC.** Fly Proxy is already in front of your Machines, and your app reaches Postgres over your organization's private network as soon as the cluster is attached.

None of that work is missing. It is done, and the record of it is a `fly.toml` you can read in one screen, diff in a pull request, and revert with git.

## The first deploy: handling RAILS_MASTER_KEY and release commands

Two things commonly bite people on the first Rails deploy: a misconfigured `RAILS_MASTER_KEY`, and migrations that don't run.

The migration story is mostly handled for you. For Postgres apps, `fly launch` writes a release command into your `fly.toml` automatically:

```
[deploy]
  release_command = './bin/rails db:prepare'
```

`db:prepare` runs migrations if the database exists, and creates plus migrates if it does not. `fly deploy` runs this release command before any new Machines take traffic, so a fresh schema is in place before requests hit your app. If you see a 500 right after deploy, check `fly logs` for migration errors before looking elsewhere.

The `RAILS_MASTER_KEY` issue shows up as 500 errors with `ActiveSupport::MessageEncryptor::InvalidMessage` in the logs. The master key isn't uploaded automatically by `fly launch`. Set it as a Fly secret yourself:

```
fly secrets set RAILS_MASTER_KEY=$(cat config/master.key)
```

This reboots the app. After it comes up, `config/credentials.yml.enc` decrypts and your app boots clean.

## Running a Rails console against your deployed app

The Fly CLI lets you open a real Rails console against your deployed app in one command:

```
fly ssh console --pty -C "/rails/bin/rails console"
```

`/rails` is the working directory for apps built with the dockerfile generator `fly launch` uses. `--pty` attaches a pseudo-terminal so the console is interactive. Database queries hit your production Postgres. Cache operations hit your production Redis. `ActiveJob` calls enqueue real jobs that real workers pick up.

Be careful what you type. The same access that lets you debug a production issue also lets you `User.destroy_all`. For destructive operations, prefer a script in `bin/` you can read before you run, rather than typing Ruby directly into the console.

For ad-hoc one-off tasks, `bin/rails runner` works the same way:

```
fly ssh console --pty -C "/rails/bin/rails runner 'puts User.count'"
```

## Background jobs: Sidekiq, Solid Queue, Good Job

Background jobs on Fly.io run as ordinary Ruby processes. The standard pattern is to add a second process group to your `fly.toml` alongside the web one:

```
[processes]
  web = "bin/rails fly:server"
  worker = "bundle exec sidekiq"
```

`fly deploy` runs your web Machines and your worker Machines from the same image. You scale them independently with `fly scale count web=2 worker=4`. The `bin/rails fly:server` task is what `fly launch` wires up for Rails apps; `bundle exec sidekiq` (or whichever job system you use) starts the worker.

This pattern works for any Ruby job system. Sidekiq, Solid Queue, Good Job, Resque, and Que all run as processes that read from a backend (Redis or Postgres) and process work. Swap the `worker` command for the one your stack uses.

For Sidekiq specifically, you'll want a shared Redis. The `fly redis create` flow provisions a Redis instance (powered by Upstash) and writes a `REDIS_URL` secret. Solid Queue and Good Job both use Postgres as their backend, so they piggyback on your existing `DATABASE_URL` and don't need a separate Redis.

The thing to watch is database connection pool size. Each worker process opens connections to Postgres just like your web processes do. Set `RAILS_MAX_THREADS` low (or use `database.yml`'s `pool` setting) so you don't exhaust your database connection limit when you scale workers up.
