Skip to main content

Deploying Ruby on Rails on Vessl

Vessl detects Rails via Gemfile and config/application.rb, builds with Nixpacks, and auto-detects bundle exec rails db:migrate as the post-deploy command when a database is attached.

Prerequisites

  • A server added and provisioned in Vessl
  • A GitHub repository with your Rails app
  • Gemfile and config/application.rb at the repository root

What Vessl auto-detects

When Vessl finds Gemfile + config/application.rb it sets:

SettingAuto-filled value
Build engineNixpacks
Port3000
Post-deploy commandbundle exec rails db:migrate (only if a database add-on is attached)

Nixpacks runs bundle install and detects the Puma web server from your Gemfile.lock, starting the app with bundle exec puma.

Step 1 — Make sure Puma is in your Gemfile

Nixpacks starts Rails via Puma. If Puma isn't in your Gemfile, add it:

Gemfile
gem "puma", ">= 5.0"

And in config/puma.rb, bind to the port Vessl injects:

config/puma.rb
port ENV.fetch("PORT", 3000)
environment ENV.fetch("RAILS_ENV", "development")

Step 2 — Create the app

  1. In your project, click New Application.
  2. Select your Rails repository and branch.
  3. Vessl detects Node.js for the stack type (if you have a package.json) or falls back to auto-detect. The port defaults to 3000.
  4. Set the Start command to:
    bundle exec puma -C config/puma.rb
  5. Click Deploy.

Step 3 — Set production environment variables

Rails requires a few variables in production:

VariableValueNotes
RAILS_ENVproductionRequired
SECRET_KEY_BASE128+ char hex stringRun rails secret locally to generate
RAILS_LOG_TO_STDOUT1Routes logs to stdout for Vessl to capture
RAILS_SERVE_STATIC_FILES1Lets Rails serve public/assets/ directly

Generate SECRET_KEY_BASE locally:

rails secret

Then paste the output into the Variables tab.

Step 4 — Asset pipeline

Run assets:precompile at build time so compiled assets are baked into the image:

Set the Build command to:

bundle exec rails assets:precompile

This compiles CSS and JS with Sprockets or Propshaft and puts the results in public/assets/. With RAILS_SERVE_STATIC_FILES=1 (set above), Rails serves them directly.

Step 5 — Add a database

Open the app → Overview → Connected Services → Add → PostgreSQL. Vessl injects:

DATABASE_URL=postgresql://<user>:<pass>@<host>:5432/<db>
DB_HOST=<internal hostname>
DB_PORT=5432
DB_DATABASE=<db name>
DB_USERNAME=<username>
DB_PASSWORD=<password>

Rails reads DATABASE_URL automatically in production — no config/database.yml changes needed. The post-deploy command bundle exec rails db:migrate runs on every deploy.

Step 6 — Add Redis (optional)

For Action Cable, Sidekiq, or Rails cache:

  1. Open the app → Overview → Connected Services → Add → Redis.
  2. Vessl injects REDIS_URL, REDIS_HOST, REDIS_PORT, REDIS_PASSWORD.

Action Cable:

config/cable.yml
production:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") %>

Sidekiq:

config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
config.redis = { url: ENV.fetch("REDIS_URL") }
end

Step 7 — Background workers

For Sidekiq or other background job processors, add a daemon from the Daemons tab:

WorkerCommand
Sidekiqbundle exec sidekiq
Good Jobbundle exec good_job start

Each daemon runs in its own container with the same environment variables as your web app.

Common issues

SECRET_KEY_BASE is missing Rails refuses to start in production without SECRET_KEY_BASE. Set it in the Variables tab (generate with rails secret locally).

assets:precompile fails This usually means a dependency is missing at build time. Make sure all gems referenced in your assets (e.g. sass-rails, terser) are in the production group of your Gemfile (or not in development-only groups).

PG::ConnectionBad on startup The database isn't reachable yet (first deploy, add-on still starting) or DATABASE_URL isn't set. Attach a PostgreSQL add-on from Overview → Connected Services and redeploy.

Assets return 404 Make sure RAILS_SERVE_STATIC_FILES=1 is set and assets:precompile ran during the build. Check the build logs to confirm it completed without errors.

bundle exec rails db:migrate runs but schema changes don't apply The migration may have rolled back due to an error. Check the post-deploy output in the deployment drawer for the specific migration that failed and its error message.