Deploy Ruby on Rails on Temps

Choose the Autopack (Ruby) preset (nixpacks-ruby) and run up: Temps installs your gems, precompiles assets and starts rails server (Puma) on $PORT with automatic HTTPS. Link managed PostgreSQL and read POSTGRES_URL, and run rails db:migrate yourself as a one-off step after a deploy that changes the schema.

This guide describes how the nightly release channel builds your app, using the Autopack builder. Beta (v0.1.0-beta.56) also builds with Autopack, but some details below may differ. Earlier releases and the stable channel build with Nixpacks and behave differently. To run nightly, see Release channels.

For an overview of self-hosting Rails, including costs, see Deploy Rails to your own server. Every framework and the preset it needs is listed under Supported platforms.


Quickstart

From your project root, deploy with your preferred package manager:

npx @temps-sdk/cli up --preset nixpacks-ruby

Temps doesn't detect Ruby projects from a Gemfile, so choose the Autopack (Ruby) preset (nixpacks-ruby), as above or under Project → Settings → Build & deploy → Build → Framework.

With that preset, the build runs bundle install, precompiles assets, and starts your app with bundle exec rails server -b 0.0.0.0 -p ${PORT:-3000}. The Ruby version comes from .ruby-version or the ruby line in your Gemfile, and defaults to 3.3. Temps sets RAILS_ENV=production, RACK_ENV=production and RAILS_LOG_TO_STDOUT=1 for you.


What Temps handles automatically

FeatureHow Temps handles it
Installbundle install
Assetsbundle exec rails assets:precompile, when the app has app/assets or app/javascript
App serverrails server (Puma, Rails' default server); a Procfile web: line replaces the command
HTTPSLet's Encrypt, auto-renewed
PortPORT env var injected, defaults to 3000
Action CableWebSocket support via reverse proxy

Apps generated before Rails 7.1 serve the precompiled assets in public/ only when RAILS_SERVE_STATIC_FILES is set. Nightly builds set it for Rails apps; on beta.56 and earlier, set it yourself:

npx @temps-sdk/cli environments vars set RAILS_SERVE_STATIC_FILES 1 -e production

Database migrations are not run automatically — see Run migrations below.


Run migrations

Temps does not have a remote "run one command" CLI action yet, so migrations are run directly against the container over SSH. Find the container name, then run the migration:

bunx @temps-sdk/cli projects show -p my-rails-app --json     # note the numeric "id"
bunx @temps-sdk/cli containers list -p <project-id>          # note the container_name
ssh your-server 'docker exec <container_name> bundle exec rails db:migrate'

Run this manually (or from your CI/CD pipeline right after the deploy step) every time a deploy includes a schema change.

On the first deploy the tables don't exist yet. If your app's / needs the database, the deploy fails its health check before you can migrate, so point the health check at a path that doesn't, such as Rails' built-in /up (Rails 7.1 and later), with health.path in .temps.yaml (see Health checks).

Do not add bundle exec rails db:migrate to your Dockerfile's CMD or start command — with rolling deploys, restarts, or multiple replicas, the container start command can run more than once, and concurrent migration runs against the same database can conflict or corrupt data.


Managed services

Create PostgreSQL and Redis under Databases → Create database, then link them from your project's Databases page. Temps injects POSTGRES_URL and REDIS_URL. It doesn't inject DATABASE_URL, so point Rails at POSTGRES_URL in config/database.yml:

production:
  adapter: postgresql
  url: <%= ENV["POSTGRES_URL"] %>

Set a secret key base for production:

npx @temps-sdk/cli environments vars set SECRET_KEY_BASE "$(openssl rand -hex 64)" -e production

Background jobs with Sidekiq

Temps runs only the web process. In a Procfile, only the web: line is used, as the start command; other process types such as worker: bundle exec sidekiq are ignored, so Temps doesn't run Sidekiq for you. For example, this Procfile starts Puma with your own config:

web: bundle exec puma -C config/puma.rb

A project that doesn't answer HTTP fails its health check, so Sidekiq can't run as a Temps project of its own either. To run it, deploy the app as a Docker Compose project with a web service and a worker service that runs bundle exec sidekiq; services that don't publish a port stay off the proxy. Point both at the same Redis and PostgreSQL. For light workloads, Active Job's :async adapter runs jobs in a thread pool inside the web process, but loses queued jobs on every restart. Recurring jobs can also run as cron jobs in .temps.yaml, which call an HTTP endpoint in your app on a schedule.


Action Cable

Action Cable WebSockets work out of the box. Set config.action_cable.allowed_request_origins to include your domain:

# config/environments/production.rb
config.action_cable.allowed_request_origins = ["https://yourdomain.com"]

Platform behavior

These rules apply to every app deployed on Temps, regardless of framework.

The one requirement: your app must listen on the port in the PORT environment variable and bind to 0.0.0.0 — not localhost or 127.0.0.1. Temps runs your app in a container and routes traffic from the host, so an app bound to localhost only accepts connections from inside the container and will fail its health check.

Health checks

After your container starts, Temps sends HTTP GET requests to verify it is healthy before routing traffic to it.

  • Path: / (the root of your application) by default
  • Success: 2 consecutive responses with a 2xx, 3xx, 404 or 405 status code
  • Timeout: 300 seconds (5 minutes) for the app to become healthy, fixed in v0.1.0-beta.56. If the app answers with error responses (other 4xx, or 5xx) for 60 seconds in a row, the deployment fails sooner. From the next release the timeout is configurable from 30 to 3600 seconds under Project → Settings → Build & deploy
  • Retry interval: 2 seconds between successful checks, 5 seconds after an error response or a failed connection

Connection errors and other 4xx or 5xx responses are retried until the timeout; if the app hasn't passed by then, the deployment fails. The check runs once, at deploy time. To check a different path, add a .temps.yaml to your repository root:

.temps.yaml
health:
  path: /health

Only path is used. Other health fields (status, interval, timeout, retries) are accepted but currently have no effect.

Add a dedicated /health endpoint that returns a simple 200. This avoids issues where / requires authentication or returns a redirect.

Auto-injected environment variables

Temps injects these variables into every deployment automatically:

VariableValueDescription
PORTResolved portThe port your app must listen on
HOST0.0.0.0Bind address
SENTRY_DSNAuto-generatedError tracking endpoint
TEMPS_API_URLYour Temps URLPlatform API endpoint
TEMPS_API_TOKENDeployment tokenAuthentication for Temps SDKs
OTEL_EXPORTER_OTLP_ENDPOINTYour Temps OTLP URLOpenTelemetry trace collection
OTEL_SERVICE_NAMEProject nameService identifier for traces

You do not need to configure these manually. They are available in process.env (Node.js), os.environ (Python), os.Getenv (Go), and the equivalent in other languages.


Next Steps

Last updated

Was this page helpful?