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
| Feature | How Temps handles it |
|---|---|
| Install | bundle install |
| Assets | bundle exec rails assets:precompile, when the app has app/assets or app/javascript |
| App server | rails server (Puma, Rails' default server); a Procfile web: line replaces the command |
| HTTPS | Let's Encrypt, auto-renewed |
| Port | PORT env var injected, defaults to 3000 |
| Action Cable | WebSocket 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:
health:
path: /healthOnly path is used. Other health fields (status, interval, timeout, retries) are accepted but currently have no effect.
/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:
| Variable | Value | Description |
|---|---|---|
PORT | Resolved port | The port your app must listen on |
HOST | 0.0.0.0 | Bind address |
SENTRY_DSN | Auto-generated | Error tracking endpoint |
TEMPS_API_URL | Your Temps URL | Platform API endpoint |
TEMPS_API_TOKEN | Deployment token | Authentication for Temps SDKs |
OTEL_EXPORTER_OTLP_ENDPOINT | Your Temps OTLP URL | OpenTelemetry trace collection |
OTEL_SERVICE_NAME | Project name | Service 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.