A Rails app needs three things from a host: a place to run Puma, a Postgres database it can reach, and a way to run db:migrate before traffic hits the new code. Ownkube covers all three from a git push, with no cloud account and no YAML to write by hand.
This walks through deploying a standard Rails app on Ownkube Compute: configuring Puma, wiring up a managed Postgres, setting RAILS_MASTER_KEY and SECRET_KEY_BASE, precompiling assets, and running migrations on release.
TL;DR
- Push a Rails app with a
Dockerfile, and Ownkube builds and deploys it behind automatic TLS. - Add an Ownkube-managed Postgres database and set
DATABASE_URLfrom its connection string. - Set
RAILS_MASTER_KEY(orSECRET_KEY_BASE) andRAILS_ENV=productionas environment variables in the dashboard, not in the repo. - Precompile assets in the Docker build step, and run
db:migrateas a release step so it happens before Puma serves the new version. - Metered billing fits Rails well: Puma sits mostly idle between requests, so the CPU line barely moves outside real traffic.
1. Prepare the app for production
Rails is opinionated enough that most of the setup is standard Rails, not anything Ownkube-specific. Confirm the basics before you deploy:
config/database.ymlreads its production connection fromENV["DATABASE_URL"], which is the Rails default.config/environments/production.rbhasconfig.assets.compile = falseandconfig.public_file_server.enabledset to match your asset pipeline (Propshaft or Sprockets, either works).Gemfileincludespgfor the Postgres adapter andpumaas the app server.
# config/database.yml
production:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
2. Write a Dockerfile
Ownkube deploys from a Dockerfile. A multi-stage build keeps the final image small and lets you precompile assets during the build:
FROM ruby:3.3-slim AS build
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev git curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle config set without 'development test' \
&& bundle install --jobs 4 --retry 3
COPY . .
# Precompile assets. SECRET_KEY_BASE_DUMMY lets this run without real secrets at build time.
RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile
FROM ruby:3.3-slim
RUN apt-get update -qq && apt-get install -y libpq-dev curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /app /app
ENV RAILS_ENV=production
ENV RAILS_LOG_TO_STDOUT=true
ENV RAILS_SERVE_STATIC_FILES=true
EXPOSE 3000
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
Puma’s default config/puma.rb reads the port and worker count from environment variables already, so leave it as Rails generated it:
# config/puma.rb
port ENV.fetch("PORT", 3000)
workers ENV.fetch("WEB_CONCURRENCY", 2)
threads_count = ENV.fetch("RAILS_MAX_THREADS", 5).to_i
threads threads_count, threads_count
3. Push the repo and create the app
Connect the repository from the Ownkube dashboard (app.ownkube.io) or push directly with the okctl CLI:
okctl login
okctl apps create rails-app --dockerfile Dockerfile
okctl deploy
Ownkube builds the image, allocates a hostname on *.ownkube.app, and issues TLS automatically, so you have a working HTTPS URL the moment it deploys. Serving the app on a domain you own is available today when it runs on a Starter (K3s) cluster in your own AWS account; custom domains on Ownkube Compute are on the roadmap, not shipped yet.
4. Add a managed Postgres database
Create a database box from the dashboard: New > Database > Postgres. It provisions a single-instance, private (in-region) Postgres box starting at $4 a month plus storage at $0.15 per GB, with backups included. Multi-instance HA, public access, and point-in-time recovery are on the roadmap, not shipped yet, so plan around a single private instance for now.
Ownkube gives you a DATABASE_URL connection string for the box. Attach it to the Rails app as an environment variable:
okctl env set DATABASE_URL="postgres://user:password@db-host:5432/rails_production" --app rails-app
Because config/database.yml already reads from ENV["DATABASE_URL"], no further Rails configuration is needed.
5. Set your secrets
Rails needs its master key or secret key base to decrypt credentials and sign sessions. Set it as a secret environment variable in the dashboard rather than committing config/master.key:
okctl env set RAILS_MASTER_KEY="$(cat config/master.key)" --app rails-app
okctl env set RAILS_ENV=production --app rails-app
If you use SECRET_KEY_BASE directly instead of the encrypted credentials file, set that instead:
okctl env set SECRET_KEY_BASE="$(bundle exec rails secret)" --app rails-app
Never commit config/master.key to the repository. Environment variables set through Ownkube are encrypted at rest and only injected into the running container.
6. Run migrations on release
Migrations need to run before the new Puma workers start serving requests, not after. Configure db:migrate as a release command so Ownkube runs it once per deploy, ahead of the rollout:
okctl apps update rails-app --release-command "bundle exec rails db:migrate"
With a release command set, every okctl deploy runs the migration against the connected Postgres box first, and only rolls Puma workers over to the new image once it succeeds. If the migration fails, the previous version keeps serving, which is the zero-downtime rollout behavior working in your favor.
7. Scale and watch it run
A fresh Rails app usually starts fine on a small metered ceiling:
okctl deploy --cpu-limit 500m --memory-limit 1Gi
Turn on horizontal autoscaling if traffic is uneven, so Ownkube adds Puma instances under load and scales back down when it is quiet:
okctl apps update rails-app --autoscale-min 1 --autoscale-max 4 --autoscale-cpu-target 70
Logs and metrics for the app and the database box are both in the dashboard, so a slow migration or a Puma worker that keeps restarting shows up in one place.
Moving to your own AWS later
If the app outgrows the shared Compute tier, or a customer contract requires it to run in a named AWS account, the same Dockerfile and Rails app move to your own AWS with no rewrite. Ownkube provisions the instance, wires up the same deploy flow, and brings the logs, metrics, and health checks with it. That portability is one of the things that separates Ownkube from Railway, which only runs on Railway’s infrastructure. Our Railway alternative comparison covers the tradeoffs in more depth.
FAQ
Does Ownkube support Rails credentials and Active Storage?
Yes. Encrypted credentials work through RAILS_MASTER_KEY as shown above. Active Storage works against any S3-compatible bucket you configure; Ownkube does not provide managed object storage directly, so point it at your own bucket.
Do I need a Dockerfile, or can Ownkube detect Rails automatically?
A Dockerfile gives you full control over the Ruby version, native gems, and the asset precompile step, and is the most reliable path for Rails. Simpler apps without native dependencies can also deploy straight from source.
Can I run Sidekiq or another background worker alongside the web app?
Yes. Deploy the worker as a second Ownkube app pointed at the same Postgres connection string (and a Valkey cache box from $2 a month if you need Redis for the queue), so the web app and worker scale independently.
What happens if my wallet balance runs out mid-month?
The app pauses and its data, including the Postgres box, is kept. Adding credit or the next monthly plan load resumes it. Unused wallet credit rolls over and never expires, so a quiet month is not credit lost.
Can I roll back a bad deploy?
Yes. Ownkube keeps prior image versions and supports zero-downtime rollback from the dashboard or okctl, so a migration or code issue does not require a manual recovery.
Where Ownkube fits
Rails wants a real database, a release step for migrations, and an app server that survives restarts, and Ownkube gives you all three without provisioning a cloud account first. Push the Dockerfile, attach a managed Postgres, set your secrets, and the release command handles the rest. Deploy your first app.