DevOps

Deploying Rails Applications to Render: A Complete Guide

Deploying Rails applications shouldn't be complicated. While platforms like Heroku have been the go-to choice for many developers, Render has emerged as a compelling alternative that offers better performance, pricing, and developer experience for modern Rails applications.

Why Choose Render for Rails Deployment?

Advantages Over Other Platforms

Performance Benefits:
- Global CDN with edge caching
- Faster cold starts compared to Heroku
- Built-in SSL certificates
- HTTP/2 support out of the box

Developer Experience:
- Zero-configuration deployments
- Automatic deployments from Git
- Built-in database backups
- Real-time logs and monitoring

Cost Effectiveness:
- No sleeping dynos on paid plans
- More predictable pricing
- Free tier includes SSL and custom domains

Setting Up Your Rails App for Render

1. Preparing Your Application

First, ensure your Rails app is ready for production deployment:

# Gemfile
group :production do
  gem 'pg' # PostgreSQL for production
end

group :development do
  gem 'sqlite3' # SQLite for development
end

# Ensure you have these essential gems
gem 'puma' # Web server
gem 'bootsnap', require: false # Faster boot times

2. Database Configuration

Update your config/database.yml:

production:
  <<: *default
  adapter: postgresql
  url: <%= ENV['DATABASE_URL'] %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

3. Environment Configuration

Configure config/environments/production.rb:

Rails.application.configure do
  config.cache_classes = true
  config.eager_load = true
  config.consider_all_requests_local = false
  config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

  # Asset configuration
  config.assets.compile = false
  config.assets.digest = true

  # Security
  config.force_ssl = true
  config.ssl_options = { redirect: { exclude: -> request { request.path =~ /health/ } } }

  # Logging
  config.log_level = :info
  config.log_tags = [ :request_id ]
end

Deployment Configuration

1. Create render.yaml

Create a render.yaml file in your project root:

databases:
  - name: myapp-db
    databaseName: myapp_production
    user: myapp_user
    region: oregon

services:
  - type: web
    name: myapp-web
    env: ruby
    region: oregon
    buildCommand: "./bin/render-build.sh"
    startCommand: "bundle exec puma -C config/puma.rb"
    healthCheckPath: /health
    envVars:
      - key: DATABASE_URL
        fromDatabase:
          name: myapp-db
          property: connectionString
      - key: RAILS_MASTER_KEY
        sync: false
      - key: RAILS_ENV
        value: production
      - key: WEB_CONCURRENCY
        value: 2

2. Build Script

Create bin/render-build.sh:

#!/usr/bin/env bash
# exit on error
set -o errexit

echo "Installing dependencies..."
bundle install

echo "Precompiling assets..."
bundle exec rails assets:precompile

echo "Cleaning old assets..."
bundle exec rails assets:clean

echo "Running database migrations..."
bundle exec rails db:migrate

echo "Build completed successfully!"

Make it executable:
bash
chmod +x bin/render-build.sh

3. Health Check Endpoint

Add a health check route for Render's monitoring:

# config/routes.rb
Rails.application.routes.draw do
  get '/health', to: 'health#check'
  # your other routes...
end
# app/controllers/health_controller.rb
class HealthController < ApplicationController
  def check
    render json: { status: 'ok', timestamp: Time.current }
  end
end

Advanced Configuration

Environment Variables Management

Create a .env.example file for team members:

# .env.example
DATABASE_URL=postgresql://username:password@localhost/myapp_development
RAILS_MASTER_KEY=your_master_key_here
REDIS_URL=redis://localhost:6379/0
SECRET_KEY_BASE=your_secret_key_base

Puma Configuration

Optimize config/puma.rb for production:

# config/puma.rb
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count

worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"

port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }

workers ENV.fetch("WEB_CONCURRENCY") { 2 }
preload_app!

plugin :tmp_restart

before_fork do
  ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
end

on_worker_boot do
  ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end

Deployment Process

1. Initial Setup on Render

  1. Connect your GitHub repository to Render
  2. Create a new Web Service
  3. Select your repository and branch
  4. Render will automatically detect your render.yaml
  5. Set your environment variables in the Render dashboard
  6. Deploy!

2. Setting Environment Variables

In your Render dashboard, add these essential variables:

  • RAILS_MASTER_KEY: Your Rails master key
  • SECRET_KEY_BASE: Generate with rails secret
  • Any API keys or third-party service credentials

3. Database Setup

Render will automatically create and connect your PostgreSQL database based on your render.yaml configuration.

Monitoring and Maintenance

Log Management

Access real-time logs through the Render dashboard or CLI:

# Install Render CLI
npm install -g @render/cli

# View logs
render logs -s your-service-name

Performance Monitoring

Monitor your application performance:

# Add to Gemfile for production monitoring
gem 'newrelic_rpm' # New Relic
# or
gem 'skylight' # Skylight

Automated Backups

Render automatically backs up your PostgreSQL database daily. Configure retention in your service settings.

Troubleshooting Common Issues

Build Failures

Asset Compilation Issues:

# In your build script, add more verbose output
RAILS_ENV=production bundle exec rails assets:precompile --trace

Database Connection Issues:
- Ensure DATABASE_URL environment variable is set
- Check that your database service is running
- Verify connection in your database.yml

Performance Issues

Slow Response Times:
- Monitor database query performance
- Add database indexes for frequently queried columns
- Implement caching strategies

Memory Usage:
- Optimize your Puma worker and thread configuration
- Monitor memory usage in Render dashboard
- Consider upgrading your service plan

Best Practices

Security

  • Always use environment variables for sensitive data
  • Enable force SSL in production
  • Keep dependencies updated
  • Use strong secrets and rotate them regularly

Performance

  • Implement HTTP caching headers
  • Use a CDN for static assets
  • Optimize database queries
  • Monitor application performance metrics

Maintenance

  • Set up automated database backups
  • Monitor error rates and response times
  • Keep Rails and gem versions updated
  • Use staging environments for testing

Conclusion

Render provides an excellent platform for deploying Rails applications with minimal configuration and maximum performance. Its straightforward approach to deployment, combined with robust infrastructure and competitive pricing, makes it an ideal choice for both new projects and existing applications looking to migrate from other platforms.

The key to successful deployment is proper preparation: configure your application correctly, set up appropriate monitoring, and follow security best practices. With these foundations in place, Render will handle the heavy lifting of infrastructure management, allowing you to focus on building great features for your users.

Christopher Lim

Christopher Lim

Rails developer and Unity explorer. Family man, lifelong learner, and builder turning ideas into polished applications. Passionate about quality software development and continuous improvement.

Back to All Posts
Reading time: 5 min read

Enjoyed this devops post?

Follow me for more insights on devops, Rails development, and software engineering excellence.