Guides

Building Ruby on Rails with open-source tools

This guide details the implementation of a production-ready Rails 8 application using the 'No-PaaS' stack. It focuses on replacing Redis-dependent background processing with Solid Queue and deploying to a VPS using Kamal. This architecture minimizes infrastructure complexity while maintaining scalability for full-stack web applications.

45-60 minutes5 steps
1

Configure Solid Queue for Background Jobs

Rails 8 defaults to Solid Queue for background processing to remove the Redis dependency. Ensure your database configuration supports the queue schema and that the adapter is correctly set for production.

config/environments/production.rb
# config/environments/production.rb
config.active_job.queue_adapter = :solid_queue

# config/database.yml
production:
  primary:
    <<: *default
    database: storage/production.sqlite3
  queue:
    <<: *default
    database: storage/production_queue.sqlite3
    migrations_paths: db/queue_migrate

⚠ Common Pitfalls

  • Failure to run 'bin/rails solid_queue:install' will result in missing migration files for the queue schema.
  • Using a single SQLite database for both data and queueing can lead to lock contention under high write loads; use separate database files as shown.
2

Initialize Kamal Deployment Configuration

Kamal handles Docker-based deployments to any Linux server. Initialize the configuration to generate the deploy.yml file and the necessary directory structure.

Terminal
bundle add kamal
kamal init

⚠ Common Pitfalls

  • Do not commit the generated .env file to version control; it will contain sensitive registry and server credentials.
3

Define Infrastructure in deploy.yml

Configure your application name, container registry, and server IP addresses. Specifically, define a separate role for the Solid Queue worker to ensure background tasks do not starve the web server of CPU cycles.

config/deploy.yml
service: my-rails-app
image: username/my-rails-app

servers:
  web:
    hosts:
      - 192.168.1.100
  job:
    hosts:
      - 192.168.1.100
    command: bundle exec rake solid_queue:start

registry:
  username: [REGISTRY_USERNAME]
  password:
    - KAMAL_REGISTRY_PASSWORD

env:
  secret:
    - RAILS_MASTER_KEY

⚠ Common Pitfalls

  • Ensure the 'job' role command correctly points to the solid_queue runner; otherwise, jobs will remain in the 'pending' state.
  • Verify that port 80/443 is open on the host firewall for the 'web' role.
4

Configure Health Checks for Zero-Downtime

Kamal uses a health check endpoint to verify the new container is ready before stopping the old one. Rails 8 includes a built-in health check controller; ensure it is properly mapped in deploy.yml.

config/deploy.yml
proxy:
  ssl: true
  host: app.example.com
  healthcheck:
    path: /up
    interval: 5s
    timeout: 2s

⚠ Common Pitfalls

  • If your /up endpoint requires authentication or database connections that are not yet established, the deployment will roll back automatically.
  • Mismatch between the proxy port (default 80) and the Rails Puma port (default 3000) will cause health check failures.
5

Provision and Deploy

The final step is to prepare the server and push the application. Kamal will install Docker on the remote host, build the image locally (or via builder), push it to the registry, and pull it to the server.

Terminal
kamal setup

⚠ Common Pitfalls

  • First-time setup may fail if the SSH user does not have passwordless sudo access on the target server.
  • Asset compilation failures during the Docker build stage are often caused by missing environment variables required by Tailwind CSS or Propshaft.

What you built

Your Rails 8 application is now configured for modern production standards using Solid Queue for background processing and Kamal for deployment. This setup provides the benefits of a managed PaaS while retaining full control over the underlying hardware. For scaling, you can now add additional IP addresses to the 'web' or 'job' roles in deploy.yml and run 'kamal deploy' to distribute the load.