Ruby on Previewops
Previewops builds whatever your Dockerfile produces and runs it as a container, so Ruby needs no special support. What it does need is what every stack needs: read the injected PORT and listen on 0.0.0.0.
| Read the port | ENV["PORT"] |
| Bind all interfaces | puma -b tcp://0.0.0.0:$PORT |
Dockerfile
FROM ruby:3.3-slim
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
ENV PORT=8080
CMD ["sh", "-c", "bundle exec puma -b tcp://0.0.0.0:$PORT"]
ENV PORT=8080 is only a default. Previewops overrides it at deploy time, so the app must read the value rather than assume it.
Application code
A typical setup with Rails or Rack behind Puma:
# config/puma.rb
port ENV.fetch("PORT") { 8080 }
# Bind every interface, not just loopback.
bind "tcp://0.0.0.0:#{ENV.fetch('PORT') { 8080 }}"
environment ENV.fetch("RAILS_ENV") { "production" }
Ruby-specific pitfalls
config.force_ssl = truebreaks readiness checks. Behind a proxy that terminates TLS it redirects the health check in a loop. Setconfig.assume_ssl = trueas well, or disableforce_sslfor previews.RAILS_MASTER_KEYis required to boot a production Rails app. Store it as an env secret rather than baking it into the image.- Precompile assets at build time (
RUN bundle exec rails assets:precompile), never in the start command — see the migration warning below.
Configuration
If your Dockerfile is not at the repository root, point at it from .previewops.yaml:
provider: cloud-run
dockerfile: ./docker/Dockerfile
port: 8080
ttl_hours: 24
See configuration.md for every available option.
Do not gate startup behind a migration
Language-agnostic, and the hardest failure here to diagnose:
# Avoid this
CMD ["sh", "-c", "run-migrations && start-server"]
If the migration cannot reach the database — a paused instance, an expired connection string, a cold-start timeout — it never exits, the server never starts, and the port never opens. The deploy itself already succeeded, so the preview shows as Live while nothing answers. Run migrations as a separate, visible step instead.
Related pages
- getting-started.md — your first deploy end to end
- configuration.md —
.previewops.yamlreference - databases.md — connecting a database to a preview
- ui-deploy.md — deploying from the dashboard