RoR Deploy to a Linux Server

Deploying to your own Linux server gives you full control over performance, configuration, and cost. This topic covers deploying a Rails app to an Ubuntu 22.04 server using Nginx as the web server and Puma as the application server — the standard production stack for Rails.

Server Stack Overview

Internet
    |
    v
Nginx (port 80/443)
  - Handles SSL certificates
  - Serves static files directly (fast)
  - Forwards dynamic requests to Puma
    |
    v
Puma (Unix socket)
  - Runs your Rails application
  - Processes Ruby code
  - Talks to the database
    |
    v
PostgreSQL
  - Stores all your application data

Step 1: Provision a Server

Create an Ubuntu 22.04 server on DigitalOcean, AWS EC2, Linode, or Vultr. You need at least 1GB RAM for a small Rails app. Set up SSH access with a key pair.

Step 2: Connect and Update

ssh root@your-server-ip

apt update && apt upgrade -y
apt install -y curl git build-essential libssl-dev libreadline-dev
apt install -y zlib1g-dev libpq-dev nodejs yarn

Step 3: Create a Deploy User

adduser deploy
usermod -aG sudo deploy
su - deploy

Step 4: Install Ruby with rbenv

curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-installer | bash

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc

rbenv install 3.2.2
rbenv global 3.2.2
gem install bundler --no-document

Step 5: Install PostgreSQL

sudo apt install -y postgresql postgresql-contrib libpq-dev

sudo -u postgres psql

CREATE USER deploy WITH PASSWORD 'strongpassword';
CREATE DATABASE myapp_production OWNER deploy;
GRANT ALL PRIVILEGES ON DATABASE myapp_production TO deploy;
\q

Step 6: Install Nginx

sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx

Step 7: Clone and Configure Your App

mkdir -p /var/www/myapp
cd /var/www/myapp
git clone https://github.com/yourusername/myapp.git current
cd current

bundle install --without development test

Create a .env file or use Rails credentials. Set your production environment variables:

RAILS_ENV=production
DATABASE_URL=postgresql://deploy:strongpassword@localhost/myapp_production
RAILS_MASTER_KEY=your_master_key_from_config/master.key

Step 8: Set Up the Database and Assets

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

Step 9: Configure Puma as a Systemd Service

/etc/systemd/system/puma.service

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

[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/myapp/current
ExecStart=/home/deploy/.rbenv/shims/bundle exec puma -C /var/www/myapp/current/config/puma.rb
ExecStop=/bin/kill -SIGTERM $MAINPID
Restart=on-failure
Environment=RAILS_ENV=production
EnvironmentFile=/var/www/myapp/current/.env

[Install]
WantedBy=multi-user.target
sudo systemctl enable puma
sudo systemctl start puma
sudo systemctl status puma

Step 10: Configure Nginx

/etc/nginx/sites-available/myapp

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

server {
  listen 80;
  server_name yourdomain.com www.yourdomain.com;

  root /var/www/myapp/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  location / {
    try_files $uri/index.html $uri @puma;
  }

  location @puma {
    proxy_pass http://puma;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 10M;
  keepalive_timeout 10;
}
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Step 11: Add SSL with Let's Encrypt

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot automatically updates your Nginx config to handle HTTPS and sets up automatic certificate renewal.

Deploying Updates

On your local machine — push to GitHub
On the server — pull and restart:

cd /var/www/myapp/current
git pull origin main
bundle install --without development test
RAILS_ENV=production rails assets:precompile
RAILS_ENV=production rails db:migrate
sudo systemctl restart puma

Capistrano — Automate Deployments

Capistrano automates the deploy process. One command deploys from your local machine:

gem "capistrano"
gem "capistrano-rails"
gem "capistrano-rbenv"
gem "capistrano3-puma"

bundle exec cap install

# Deploy:
bundle exec cap production deploy

Capistrano SSHs into your server, pulls the latest code, runs migrations, compiles assets, and restarts Puma — all from one local command.

Server Security Checklist

  ✓ SSH key auth only (disable password login)
  ✓ Firewall: allow ports 22, 80, 443 only
  ✓ HTTPS enabled with automatic renewal
  ✓ No root login via SSH
  ✓ PostgreSQL not exposed to internet (localhost only)
  ✓ Rails credentials file not in version control
  ✓ Regular security updates: apt update && apt upgrade

Running your own server gives you full control over your infrastructure. The setup takes longer than Heroku, but the monthly cost is lower, performance is higher, and you eliminate platform restrictions entirely.

Leave a Comment

Your email address will not be published. Required fields are marked *