Skip to main content

How to deploy Rails on Ubuntu 24.04

TL;DR

Complete guide to deploying a Ruby on Rails application on Ubuntu 24.04 with rbenv, Puma, nginx, PostgreSQL, and SSL.

Key facts

Topology
Rails on Ubuntu 24.04

TL;DR

This guide covers deploying a Ruby on Rails application on Ubuntu 24.04 with rbenv, Puma, nginx, PostgreSQL, and SSL.

Prerequisites

  • Ubuntu 24.04 LTS with root or sudo access
  • A domain name pointing to your server
  • Your Rails application in a Git repository

Step 1 — System preparation

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git build-essential libssl-dev libreadline-dev zlib1g-dev \
    libsqlite3-dev libpq-dev libyaml-dev libffi-dev

Step 2 — Install Ruby with rbenv

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'eval "$(~/.rbenv/bin/rbenv init -)"' >> ~/.bashrc
source ~/.bashrc

git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
rbenv install 3.3.0
rbenv global 3.3.0
gem install bundler

Step 3 — PostgreSQL

sudo apt install -y postgresql postgresql-contrib
sudo -u postgres createuser --interactive deploy
sudo -u postgres createdb myapp_production -O deploy

Step 4 — Deploy the application

sudo mkdir -p /var/www/myapp
sudo chown deploy:deploy /var/www/myapp
cd /var/www/myapp
git clone git@github.com:yourorg/myapp.git .
bundle config set --local deployment true
bundle config set --local without 'development test'
bundle install

Set environment variables in /var/www/myapp/.env:

RAILS_ENV=production
SECRET_KEY_BASE=your-secret-key
DATABASE_URL=postgresql://deploy@localhost/myapp_production

Run production setup:

RAILS_ENV=production bundle exec rails db:migrate
RAILS_ENV=production bundle exec rails assets:precompile

Step 5 — Puma with systemd

Create /etc/systemd/system/puma.service:

[Unit]
Description=Puma Rails Server
After=network.target

[Service]
User=deploy
Group=deploy
WorkingDirectory=/var/www/myapp
ExecStart=/home/deploy/.rbenv/shims/bundle exec puma -C config/puma.rb
Restart=always
RestartSec=5
Environment=RAILS_ENV=production
EnvironmentFile=/var/www/myapp/.env

[Install]
WantedBy=multi-user.target

A production config/puma.rb:

workers ENV.fetch("WEB_CONCURRENCY") { 2 }
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count
bind "unix:///var/www/myapp/tmp/sockets/puma.sock"
environment ENV.fetch("RAILS_ENV") { "production" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
mkdir -p tmp/sockets tmp/pids
sudo systemctl start puma
sudo systemctl enable puma

Step 6 — nginx

upstream rails {
    server unix:///var/www/myapp/tmp/sockets/puma.sock;
}

server {
    listen 80;
    server_name example.com;
    root /var/www/myapp/public;

    location / {
        try_files $uri @rails;
    }

    location @rails {
        proxy_pass http://rails;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /assets/ {
        expires 365d;
        add_header Cache-Control "public, immutable";
    }
}

Step 7 — SSL

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

With Reflex

Reflex monitors your Rails stack from Puma workers through to nginx and PostgreSQL. It can orchestrate zero-downtime Puma restarts (using pumactl phased-restart), run database migrations safely, track asset compilation, and auto-recover from common production issues — all from a single dashboard. See How it works.