agentsclimarketplace

Fly rails deployment

Skill Tyr0/agent-skills/plugins/fly-expert/skills/fly-rails-deployment

A collection of skills, plugins, and agents for AI workflows.

Install
npx -y skills add Tyr0/agent-skills --skill fly-rails-deployment

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill whenever the user asks about deploying Ruby on Rails to Fly.io, configuring fly.toml for Rails, using Docker with Rails on Fly, setting up environment variables or secrets on Fly.io, configuring Sidekiq or background workers on Fly, setting up health checks, running rake tasks or Rails console on Fly, scaling Rails apps on Fly.io, or troubleshooting Rails deployments on Fly. Also use it for questions about local Docker development that mirrors a Fly.io Rails deployment, multi-process setups (web + worker), Action Cable, Redis on Fly, or Fly.io Dockerfile generation via `bin/rails generate dockerfile`.

SKILL.md

11.6 KB, as published. Nobody here has run it

Fly.io Rails Deployment Reference

A dense reference for deploying and operating Ruby on Rails applications on Fly.io with Docker. Covers the full workflow from initial launch through production operations.


Deployment Priority Order

  1. fly launch — detect, scaffold, first deploy
  2. Commit generated files (Dockerfile, fly.toml, bin/docker-entrypoint, .dockerignore, config/dockerfile.yml)
  3. Attach Postgres and set secrets before first deploy if skipped at launch
  4. Verify release_command runs migrations (bin/rails db:prepare)
  5. Add health check endpoint (/up is Rails default)
  6. Add process groups for workers before scaling

1. Initial Setup

Install flyctl

brew install flyctl          # macOS
curl -L https://fly.io/install.sh | sh   # Linux/CI
fly auth login

Launch a new Rails app

fly launch

fly launch auto-detects Rails and:

  • Generates Dockerfile, fly.toml, bin/docker-entrypoint, .dockerignore, config/dockerfile.yml
  • Prompts for org, region, machine size
  • Optionally creates a Postgres cluster and attaches it (sets DATABASE_URL secret)
  • Builds and deploys immediately if you accept

All five generated files must be committed to version control.

Redeploy after changes

fly deploy

fly deploy builds the Docker image remotely (on Fly builders), pushes it, runs the release_command, then updates Machines.


2. Generated Files

Dockerfile

Rails' built-in generator produces a production-ready multi-stage Dockerfile:

# Stage 1: build gems and assets
FROM ruby:3.3-slim AS build
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs npm
WORKDIR /rails
COPY Gemfile Gemfile.lock ./
RUN bundle install --without development test
COPY . .
RUN bundle exec rails assets:precompile

# Stage 2: minimal runtime image
FROM ruby:3.3-slim AS final
RUN apt-get update -qq && apt-get install -y libpq5
WORKDIR /rails
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
EXPOSE 3000
CMD ["./bin/rails", "server", "-b", "0.0.0.0"]

Regenerate when dependencies change:

bin/rails generate dockerfile

Common generator flags:

FlagEffect
--postgresqlAdd libpq5 runtime dependency
--redisAdd Redis client
--sidekiqAdd Sidekiq worker entrypoint
--nginxAdd nginx for asset serving
--nodeAdd Node.js for JS bundling
--swap=512Add swap space (MB) for memory spikes
--tigrisAdd Tigris object storage support
--ciBuild for CI environments

bin/docker-entrypoint

Runs database preparation on every container start (idempotent):

#!/bin/bash -e
if [ "${*}" == "./bin/rails server" ]; then
  ./bin/rails db:prepare
fi
exec "${@}"

Remove db:prepare from entrypoint if you use release_command in fly.toml instead (preferred for migrations).

config/dockerfile.yml

Tracks generator preferences so bin/rails generate dockerfile regenerates consistently:

args:
  postgresql: true
  redis: true

3. fly.toml Reference

Minimal production Rails configuration:

app = "my-rails-app"
primary_region = "ord"

[build]
  dockerfile = "Dockerfile"

[deploy]
  # Runs once per deploy in a temporary Machine BEFORE traffic switches
  release_command = "bin/rails db:prepare"
  strategy = "rolling"   # rolling | immediate | canary | bluegreen

[env]
  RAILS_ENV = "production"
  RAILS_LOG_TO_STDOUT = "true"
  LOG_LEVEL = "info"
  WEB_CONCURRENCY = "2"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = "stop"    # stop | suspend | off
  auto_start_machines = true

  [http_service.concurrency]
    type = "connections"
    hard_limit = 25
    soft_limit = 20

[[http_service.checks]]
  grace_period = "10s"
  interval = "30s"
  method = "GET"
  path = "/up"           # Rails 7.1+ built-in health check
  timeout = "5s"

[[vm]]
  size = "shared-cpu-1x"
  memory = "512mb"

Key [deploy] options

OptionValueNotes
release_command"bin/rails db:prepare"Runs migrations; failure aborts deploy
strategy"rolling"Replaces Machines one by one (zero-downtime)
wait_timeout"5m"Time to wait for Machine health

Key [http_service] options

OptionValueNotes
internal_port3000Must match Rails PORT or -p flag
auto_stop_machines"stop"Shuts idle Machines to save costs
auto_start_machinestrueWakes on incoming request
force_httpstrueAlways enable in production

[env] — non-sensitive only

Never put secrets in [env]. Use fly secrets set for anything sensitive.

[[vm]] sizes

SizeCPURAMUse
shared-cpu-1x1 shared256MBDev / low traffic
shared-cpu-1x + memory = "512mb"1 shared512MBTypical Rails
shared-cpu-2x2 shared512MBMedium load
performance-1x1 dedicated2GBCPU-bound workloads
performance-2x2 dedicated4GBHigh traffic

4. Secrets Management

Secrets are encrypted, stored in Fly vault, and injected as env vars at runtime.

# Set one or more secrets (triggers Machine restart by default)
fly secrets set SECRET_KEY_BASE=$(rails secret) RAILS_MASTER_KEY=$(cat config/master.key)

# Stage secrets (no immediate restart; applied at next deploy or manual restart)
fly secrets set DATABASE_URL=postgres://... --stage

# List secret names (values hidden)
fly secrets list

# Remove secrets
fly secrets unset OLD_SECRET

Required Rails secrets on Fly:

SecretHow to generate
SECRET_KEY_BASEbin/rails secret
RAILS_MASTER_KEYContents of config/master.key
DATABASE_URLSet automatically by fly postgres attach
REDIS_URLSet when provisioning Redis

Never commit config/master.key — set it as a secret instead. Add to .gitignore if not already.


5. Multi-Process Setup (Web + Worker)

Add Sidekiq or other workers as a separate process group:

[processes]
  web    = "bundle exec rails server -b [::] -p 3000"
  worker = "bundle exec sidekiq -c 5"

[http_service]
  internal_port = 3000
  processes = ["web"]         # http_service only routes to web

[[vm]]
  size = "shared-cpu-1x"
  memory = "512mb"
  processes = ["web"]

[[vm]]
  size = "shared-cpu-1x"
  memory = "512mb"
  processes = ["worker"]

Scale each process group independently:

fly scale count web=2 worker=1

6. Running One-Off Commands

# Open Rails console on a running Machine
fly console

# SSH into a running Machine
fly ssh console

# Run a one-off command (temporary Machine, auto-destroyed)
fly machine run . --rm --command "bin/rails db:seed"
fly machine run . --rm --command "bin/rails runner 'User.reindex'"

# Run a rake task
fly ssh console -C "bin/rails db:version"

fly console vs fly ssh console:

  • fly console — uses console_command from fly.toml (defaults to /bin/bash); set it to bin/rails console for direct Rails console
  • fly ssh console — raw shell access
# fly.toml — set Rails console as default
console_command = "/rails/bin/rails console"

7. Monitoring & Troubleshooting

fly status                   # Machine health overview
fly logs                     # Tail live logs
fly logs --instance <id>     # Logs for a specific Machine
fly releases                 # Deployment history
fly releases show <version>  # Details of a specific release

# Check health of a deploy
fly checks list
fly checks list --app my-rails-app

Common deploy failures

SymptomCauseFix
release_command failsMigration error or missing DBCheck fly logs; verify DATABASE_URL is set
Machine never becomes healthyHealth check path wrong or app crashesCheck /up route exists; fly logs for stack trace
SECRET_KEY_BASE missingForgot to set secretfly secrets set SECRET_KEY_BASE=$(rails secret)
Assets not foundPrecompile step failedCheck Dockerfile build stage; verify assets:precompile runs
Memory OOMRails + gems exceed limitIncrease memory in [[vm]]; add swap with --swap in Dockerfile generator

8. Scaling

# Scale Machine count
fly scale count 3                    # 3 Machines for default process
fly scale count web=2 worker=1       # Per process group

# Scale Machine size
fly scale vm shared-cpu-2x
fly scale vm shared-cpu-1x --memory 1024

# Show current scale
fly scale show

auto_stop_machines = "stop" and auto_start_machines = true are the recommended default for cost savings — Machines stop when idle and wake on the first request (~300ms cold start for Rails).


9. Local Docker Development (Mirror Production)

Run the exact production image locally:

# Build the production image locally
docker build -t my-rails-app .

# Run with local env vars
docker run --rm -it \
  -p 3000:3000 \
  -e DATABASE_URL=postgres://localhost:5432/myapp_dev \
  -e SECRET_KEY_BASE=local_dev_secret \
  -e RAILS_ENV=production \
  my-rails-app

# Or use docker compose for full stack (Rails + Postgres + Redis)
docker compose up

Recommended docker-compose.yml for local Fly parity:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://postgres:password@db:5432/myapp_development
      - SECRET_KEY_BASE=local_dev_secret_not_for_production
      - RAILS_ENV=development
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: myapp_development
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

10. Anti-Patterns

Anti-patternProblemFix
Secrets in [env] sectionVisible in fly.toml; committed to gitUse fly secrets set
db:migrate in ENTRYPOINT instead of release_commandRuns on every Machine start; risk of parallel migrationMove to release_command in fly.toml
Hardcoded PORT=3000 without -b [::] Won't bind to IPv6; unreachable on FlyUse rails server -b [::] -p 3000
Single shared-cpu-1x with 256MB for Puma + multiple workersOOM killsUse 512MB+ or reduce WEB_CONCURRENCY
Not committing DockerfileLocal and CI builds diverge from productionAlways commit all generated files
Using fly launch on an existing app without --no-deployMay reset fly.toml configurationUse fly deploy for subsequent deploys
Omitting health checkDeploy succeeds even if app crashes silentlyAlways configure [[http_service.checks]] with path = "/up"

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.