Skip to main content
This guide walks you through building and deploying a Ruby on Rails application to Magic Containers with GitHub Container Registry. You’ll need:
  • A GitHub account for source code and container registry
  • A bunny.net account with Magic Containers enabled
  • Ruby 3.2+ installed locally

Create the Rails app

Create a new Rails application with views and assets:
rails new app-rails
cd app-rails
Generate a controller with a view:
bin/rails generate controller Home index --skip-routes
Add the route in config/routes.rb:
config/routes.rb
Rails.application.routes.draw do
  root "home#index"
  get "up", to: "rails/health#show", as: :rails_health_check
end
Update the view in app/views/home/index.html.erb:
app/views/home/index.html.erb
<h1>Hello from Bunny 🐰</h1>

Run locally

Start the Rails development server:
bin/rails server
Test the app at http://localhost:3000, or with curl:
curl http://localhost:3000/

Prepare for production

Rails 7.1+ automatically generates a production-ready Dockerfile in your project root. Before building, prepare the app:
bin/rails db:migrate
rm config/credentials.yml.enc
The credentials file is removed since we’ll use environment variables instead.
If you’re using an older Rails version, you can generate a Dockerfile with: bash bin/rails generate dockerfile

Review the Dockerfile

Rails 7.1+ generates a production-ready, multi-stage Dockerfile that includes:
  • jemalloc for reduced memory usage
  • Bootsnap precompilation for faster boot times
  • Non-root user for security
  • Asset precompilation (full-stack apps only)
  • Thruster HTTP/2 proxy (full-stack apps only)

Build and push to GitHub Container Registry

Create .github/workflows/build.yml to automatically build and push on every commit to main:
.github/workflows/build.yml
name: Build and Push

on:
  push:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
Push your code to trigger the workflow:
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/YOUR_USERNAME/app-rails.git
git push -u origin main
If your package is private, set the visibility to Public in GitHub or configure Magic Containers with registry credentials.

Deploy to Magic Containers

1

Create a new app

In the bunny.net dashboard, go to Magic Containers and click Add App. Enter a name and select your deployment option.
2

Add a container

Click Add Container, then configure:
FieldValue
RegistryGitHub Container Registry
ImageYOUR_USERNAME/app-rails
Taglatest
3

Configure environment variables

Go to the Environment Variables tab and add:
VariableValue
SECRET_KEY_BASEGenerate with bin/rails secret
4

Add an endpoint

Go to the Endpoints tab, click Add New Endpoint, and set the container port to 80.
5

Deploy

Click Add Container, then Next Step, and Confirm and Create.
For more details, see the quickstart guide.

Test your app

curl https://mc-xxx.bunny.run/
Response
{ "message": "Hello from Bunny 🐰" }
You can add a custom hostname from the Endpoints section in your app settings.

Add persistent storage

Magic Containers are ephemeral, so data stored locally is lost on restarts. For Rails apps that need to persist data (Active Storage uploads, etc.), attach a Persistent Volume.
1

Add a volume

Go to your app’s Volumes tab and click Add Volume. Set the mount path to /rails/storage and choose an initial size.
2

Configure Rails storage

Update config/environments/production.rb to use the volume for Active Storage:
config/environments/production.rb
config.active_storage.service = :local
3

Configure SQLite (optional)

To persist your SQLite database, update config/database.yml:
config/database.yml
production:
  <<: *default
  database: /rails/storage/production.sqlite3
See the Persistent Volumes documentation for more details.

Next steps

  1. Automate deploys with GitHub Actions
  2. Add a custom hostname