
How to Dockerize and Deploy Ruby on Rails
Lukas MauserThis Dockerfile builds your Rails app with a multi-stage setup that installs gems, precompiles assets, and then copies only what production needs into a slim final image.
If you're just here to copy and paste, here's the final Dockerfile that will produce an image for your Rails app:
FROM ruby:3.3-slim AS base
WORKDIR /rails
ENV RAILS_ENV=production \
BUNDLE_DEPLOYMENT=1 \
BUNDLE_PATH=/usr/local/bundle \
BUNDLE_WITHOUT=development:test
FROM base AS build
# Build tools and Postgres headers, only needed while compiling gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libpq-dev
# Install gems first so this layer is cached when only source changes
COPY Gemfile Gemfile.lock ./
RUN bundle install && rm -rf "${BUNDLE_PATH}"/ruby/*/cache
# Copy the app and precompile assets
COPY . .
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
FROM base AS runtime
# Only the Postgres runtime library is needed here, not the headers
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y libpq5 && \
rm -rf /var/lib/apt/lists/*
# Bring over the installed gems and the built app
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails
EXPOSE 3000
CMD ["./bin/rails", "server", "-b", "0.0.0.0"]
And here's the .dockerignore file:
.git
log/*
tmp/*
storage/*
node_modules
.env
To build and run the image, use these commands:
docker build -t rails-app .
docker run -p 3000:3000 -e RAILS_MASTER_KEY=your_master_key rails-app
Not just here to copy and paste? Let's go over what's happening in the Dockerfile!
The Setup
For this tutorial, I assume you have a Rails app that talks to Postgres, which is the most common setup. Locally you run bin/rails server and everything just works. For production we want a small, self-contained image, so we split the work into a build stage that has all the compilers and a runtime stage that has none of them.
The Dockerfile
The base stage sets shared environment variables. RAILS_ENV=production and BUNDLE_WITHOUT=development:test make sure we don't drag test and development gems into the image.
The build stage does the heavy lifting:
- Build dependencies:
- Installs
build-essential,git, andlibpq-dev. These are needed to compile native gem extensions likepg, but you don't want them in the final image.
- Gem installation:
- Copies
GemfileandGemfile.lockon their own, then runsbundle install. Doing this before copying the rest of the code means Docker caches your gems and only reinstalls them when the Gemfile changes.
- Asset precompilation:
- Runs
assets:precompilewithSECRET_KEY_BASE_DUMMY=1. Rails needs some secret to boot during precompile, and this flag provides a throwaway one so you don't have to leak your real key into the build.
The runtime stage is intentionally bare:
- Runtime image:
- Installs only
libpq5, the shared library thepggem needs at runtime. - Copies the installed gems and the finished app from the build stage.
- Exposes port 3000 and starts Puma bound to
0.0.0.0so it accepts connections from outside the container.
At runtime Rails needs RAILS_MASTER_KEY (or SECRET_KEY_BASE) to decrypt your credentials, so pass it as an environment variable rather than committing it.
Deployment
You can deploy this Docker container to any cloud provider that supports Docker. For example, you could use platforms like Heroku, DigitalOcean, or AWS ECS. Because I am the co-founder of Sliplane, I will show you how to deploy it there.
After signing up, you can create a new service by selecting your GitHub repository. Then keep the default settings, add RAILS_MASTER_KEY and your DATABASE_URL as environment variables, and click deploy.

After deployment your Rails app will be available under a subdomain of sliplane.app, usually it's just your service name.
You can also see the logs of your app, view metrics such as CPU and memory usage, add persistent storage, and much more. Whenever you push to your repository, Sliplane will automatically deploy your app.
If you want to try out Sliplane, the first 2 days are free! Try it out and let me know what you think :)
Next Steps
You'll usually want to run bin/rails db:migrate when you deploy. A tiny entrypoint script that runs migrations and then starts Puma handles that cleanly. Want help wiring that up or attaching a managed Postgres database? Feel free to reach out!
Cheers,
Lukas