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.
