Prepare your repository
Cloud detects a Ruby application when it finds aGemfile in your application directory. You should commit both your Gemfile and Gemfile.lock, and make sure they include your production server and database adapter. For Rails applications, keep the generated config/application.rb, config/environment.rb, and bin/rails files in your repository, since Cloud uses them to recognize the framework.
Your application runs on Linux with ARM64 processors. If your lockfile only lists the platforms for your development machine, add Cloud’s platform locally and commit the updated lockfile:
aarch64-linux, aarch64-linux-gnu, or generic ruby platform. If the application creation form reports a missing platform, push your updated lockfile and refresh the repository scan before continuing.
If your application lives in a monorepo, select the directory that contains your Gemfile. Cloud keeps the surrounding repository available, so dependencies such as sibling path gems continue to work.
Choose a Ruby version
Cloud supports Ruby 3.2, 3.3, 3.4, and 4.0, with Ruby 3.4 as the default. The simplest way to choose your version is with a.ruby-version file:
.ruby-version first, then the RUBY VERSION section of Gemfile.lock, the ruby declaration in your Gemfile, .tool-versions, and finally mise.toml. A pinned version selects a major and minor release line, while a Gemfile version constraint selects the lowest supported release line that satisfies it.
If your repository doesn’t declare a version, you may select one from your environment’s General Settings instead. If you declare a version Cloud doesn’t support, the deployment stops before building. You can find more details in the Ruby runtime documentation.
It’s a good idea to keep your Ruby declarations consistent with one another. In particular, if your Gemfile requires an exact patch version, it must match the Ruby patch version Cloud installs, or Bundler will reject the build.
Install dependencies
Cloud installs your gems automatically before running your build commands. It uses the Bundler version recorded underBUNDLED WITH in your Gemfile.lock, or the Bundler version that ships with the runtime if that section is missing.
Gems are installed using Bundler’s deployment and frozen modes, so you should update your dependencies locally and commit the lockfile rather than running bundle update during deployment. Be sure that every gem your application needs in production lives outside of the excluded groups, including puma, your database adapter, and any gems used for background jobs or building assets.
By default, Cloud skips the development and test groups. You may change which groups are installed using your environment variables or linked secrets:
BUNDLE_WITHOUT to an empty value. Cloud applies these settings while installing your gems and keeps the same group configuration at runtime. Remember to redeploy after changing them.
Run a production server
Rails
Cloud pre-fills your Rails start command using your application’s binstub, when it exists:bin/rails binstub, Cloud uses bundle exec rails server with the same bind and port options. Either way, keep puma in your production dependencies so Rails can start its server.
Your server must listen on the port set by the PORT environment variable, which is 3000 by default, and it must accept IPv6 connections. This matters because Cloud’s startup probes reach your application over IPv6. If you change the start command, be sure to keep the :: bind, since an IPv4-only or loopback-only listener will prevent it from reaching your application.
If you would rather start Puma directly, replace the port or bind directive in your config/puma.rb file with the following:
port or bind directives from your configuration. You should also keep Puma running in the foreground.
Procfile commands
If your repository includes aProcfile, Cloud uses its web command as your initial start command instead of the framework default. For example:
config/puma.rb as described in the previous section. For Rails applications, Cloud also offers the release command in your deployment settings, and your other processes as background process suggestions. It doesn’t run your entire Procfile automatically, so be sure to review these suggestions and configure the ones you need in your environment.
Rails environment variables
New Rails environments include a securely generatedSECRET_KEY_BASE, which you are free to edit. You should keep this value the same across deployments so your users’ existing signed cookies and sessions stay valid. If you are migrating an existing application, use its current secret.
Cloud also provides the following production defaults:
Cloud sets your environment variables on your application’s process and makes them available to your build commands, so you can read any custom settings from
ENV just like you do locally. If you define a variable yourself, your value takes precedence over both linked secrets and the injected defaults.
Encrypted credentials
If your application uses encrypted Rails credentials, add the matchingRAILS_MASTER_KEY to your environment variables or Secrets Manager. Be sure to use the key for the credentials file your production configuration actually loads, such as config/credentials.yml.enc or config/credentials/production.yml.enc.
Keep in mind that SECRET_KEY_BASE is only used to sign your application’s data. It can’t decrypt your credentials, so it doesn’t replace RAILS_MASTER_KEY. If your production configuration explicitly enables config.require_master_key, Cloud will check for a key before building your application.
Databases
When you connect a Postgres or MySQL database from your environment’s infrastructure canvas, Cloud provides aDATABASE_URL variable containing a postgresql:// or mysql2:// URL for Rails.
Be sure to include the pg gem for Postgres or the mysql2 gem for MySQL in your production bundle. Rails reads DATABASE_URL automatically and merges it with your config/database.yml file. However, an explicit url: in that file takes precedence, so if your configuration still contains a URL from a previous host, remove it so Rails uses Cloud’s connection instead.
You should always use a managed database in production. Since your environment’s filesystem is ephemeral, a SQLite file stored on an instance can’t be shared across replicas and won’t survive your next deployment.
Solid Cache, Solid Queue, and Solid Cable
Rails applications may use separate production connections namedcache, queue, and cable. Cloud detects these connections in your config/database.yml file, and when you attach your primary database, it creates a separate database for each one it finds. These databases live in the same database cluster as your primary connection.
For example, a Postgres application using all three Solid components might have the following configuration:
mysql2 adapter and its gem instead. Cloud provides a connection URL for each connection, and Rails reads them automatically:
To have Cloud provision these databases, keep the conventional connection names and leave out any
url: entries. It skips connections that have an explicit URL or replica: true, and you will need to configure connections with any other name yourself. Since Cloud reads the structure of your YAML file without evaluating its Ruby expressions, make sure your production connection definitions are written out in the file.
You may override the injected secondary URLs using your own environment variables or linked secrets, but those external connections are then yours to manage. When you replicate an environment, Cloud copies or creates the attached secondary databases based on the database replication option you choose. If you have set custom URLs, review them before deploying a replica or preview environment so it doesn’t accidentally use your production data.
Changing
config/database.yml on its own doesn’t update an existing environment’s database attachments, so be sure to declare your connections before Cloud scans your repository and you attach the database. Detaching a database removes the environment’s secondary connections, but the databases themselves are kept.Prepare the databases
Database preparation belongs in your environment’s deploy commands:Build and serve assets
When Cloud detects Propshaft or Sprockets in a Rails application that isn’t configured as API-only, it pre-fills the following build command:public directory, including the compiled assets in public/assets.
The SECRET_KEY_BASE_DUMMY=1 setting only applies to asset compilation. Your real SECRET_KEY_BASE is still used at runtime, so don’t add the dummy setting as an environment variable. Also, keep in mind that initializers that access your credentials or database may still require those resources while your assets compile.
Caches and background jobs
When you attach a Laravel Valkey or Redis cache, Cloud provides aREDIS_URL variable. You should configure your cache library or Rails cache store to use this URL, and make sure it supports TLS when the URL uses the rediss:// scheme.
To use Rails’ Redis cache store, include the redis gem and add the following to your config/environments/production.rb file:
Be sure to keep the required gems and binstubs in your production bundle. Cloud suggests Sidekiq and GoodJob commands based on your lockfile, along with any processes from your Procfile. If you are using Solid Queue with
bin/jobs, add the process yourself. You should run your workers as separate background processes rather than enabling SOLID_QUEUE_IN_PUMA on your web server.
Each background process runs on every replica of its cluster, so account for your total worker concurrency and database connections when choosing process counts and replica limits. If your workers need to process jobs or recurring tasks while your App cluster scales to zero, keep their worker cluster awake.
Solid Queue can run recurring tasks using its own scheduler and config/recurring.yml file. To use it, configure your recurring tasks in your application and run the jobs process. Cloud’s scheduler controls for Laravel and Symfony don’t configure Rails recurring tasks.
Store files in object storage
For user uploads, you should use object storage. To get started, attach a private bucket as your environment’s default disk. Cloud provides the bucket’s AWS connection variables, but you will need to select and configure an Active Storage service in Rails yourself. First, add theaws-sdk-s3 gem to your production Gemfile, run bundle install locally, and commit the updated lockfile. Then, add the following service to your config/storage.yml file:
config/environments/production.rb file:
public: true.
The Ruby runtime includes libvips for image variants. If your application transforms images, include the image_processing gem as well. The Active Storage guide covers direct uploads and variant configuration in more detail.
Configure Puma concurrency
You should configure Puma’s process and thread counts based on your instance’s CPU and memory. Unlike Python applications, Cloud doesn’t calculateWEB_CONCURRENCY for Ruby applications. You may set it yourself, or start with Puma’s single-process mode and increase concurrency once you have a feel for your application’s memory usage.
For example, you might add the following settings to your existing config/puma.rb file:
WEB_CONCURRENCY=0 runs a single server process without clustered workers. Keep in mind that each clustered worker has its own thread pool and its own database connection pools, so set the pool for each database large enough to accommodate every thread that uses it, including any background or asynchronous work.
Shut down gracefully
When an instance stops, whether during a deployment or while scaling down, Cloud sends aSIGTERM signal to your application’s process. Puma handles this signal gracefully by letting active requests finish before exiting.
You should keep Puma’s shutdown limits, such as the force_shutdown_after and worker_shutdown_timeout settings in the previous example, shorter than your environment’s graceful shutdown timeout. This leaves time for the proxy and the rest of the instance to stop cleanly. If your requests or jobs need more time to finish, increase the environment’s timeout as well. Puma’s configuration documentation describes the available shutdown and concurrency options.
Running behind the proxy
Cloud handles TLS for you before forwarding requests to your application, so Puma only needs to speak plain HTTP. Along the way, its proxy passes along the original request scheme in theX-Forwarded-Proto header, which allows Rails to recognize HTTPS requests. You should keep your production HTTPS configuration, such as config.force_ssl = true, in place.
If you restrict hosts using config.hosts, be sure to allow your Cloud domain and any custom domains. You should also configure the hostnames used in URLs generated outside of a request, such as links in your mailers. Cloud provides an APP_URL variable, but Rails doesn’t apply it to these settings automatically.
Logging
Cloud captures everything your application writes to stdout and stderr and displays it in the Logs dashboard. Recent Rails applications already log to stdout. If you are deploying an older application that only writes to a log file, configure its logger in yourconfig/environments/production.rb file:
RAILS_LOG_TO_STDOUT variable only has an effect when your application’s configuration reads it. The Rails configuration guide is a helpful reference when adapting an older application.
Other Ruby and Rack applications
For Ruby applications that don’t use Rails, Cloud uses theweb command from your Procfile if you have one. Otherwise, it uses the Ruby or Rack entrypoint you selected. A Ruby file such as app.rb runs with bundle exec ruby app.rb, so your program needs to start its own server, read PORT, and accept IPv6 connections.
For a Rack entrypoint such as config.ru, Cloud pre-fills the following start command:
rackup executable otherwise, and it binds the server to :: on PORT for you. Be sure to add Puma, or Rackup with a compatible server, to your production dependencies.
Generic Ruby applications receive RACK_ENV=production, BUNDLE_WITHOUT=development:test, and the connection variables for any attached resources. Their DATABASE_URL uses the mysql:// or postgresql:// scheme, so you may need to adapt it for the database library you use. The Rails-specific asset builds, secrets, and database preparation described in this guide don’t apply to generic Ruby applications.
