Deploying Rails Like It's 2005

April 10, 2022   • rails

After deploying web applications for so long using Heroku or other services that automate deployment, I realized that I didn’t really know everything that happens behind the scenes from taking an application from development to production. So I spent a weekend trying to deploy a Rails app to a bare metal server provisioned on AWS. It was a fun experience and I learned a lot. Here’re my notes from the entire process.

Set up Amazon EC2 (link)

  1. Sign up for AWS
  2. Create a key pair
  3. Create a security group (info)

Set up an EC2 instance (Server) (link)

  • EC2 Instance: A virtual machine hosted at an Availability Zone on the AWS infrastructure
  • Availability Zone: An isolated data center
  • Access to the EC2 instance is managed using a key pair and a security group
    • Key pair: to prove your identity
    • Security group: virtual firewall to control incoming and outgoing traffic

Connect to the Server (link) (prereqs)

Follow the Server Setup instructions. (link)

  • Except for firewall, as it’s already set up
  • Don’t create new user (see next step)

Create a new user on the server (link)

  • Use this user for your application.
  • Add user to the sudo group
sudo nano /etc/sudoers
user_name ALL=(ALL)  ALL

Ruby on Rails

  • Set the environment to Production
export RAILS_ENV=production. # ~/.zshrc
  • Install rbenv (link)
sudo apt install rbenv
  • Install / Update ruby-build (link)
$ mkdir -p "$(rbenv root)"/plugins
$ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
  • Skip gem documentation
echo "gem: --no-document" > ~/.gemrc
  • Install bundler
gem install bundler
  • Install rails and foreman
gem install rails
gem install foreman

rbenv rehash
  • Install nodejs and npm using nvm (link)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | zsh
nvm install 16.13.2
  • Install yarn
npm install --global yarn
  • Set up the credentials (copy from development)
nano config/master.key. # (copy from development)
  • Ensure Tailwind is setup properly in production
bundle lock --add-platform x86_64-linux
bundle install
  • Precompile the Assets
rails assets:precompile

Database

  • Install MySQL and MyCLI
sudo apt-get install libmysqlclient-dev
gem install mysql2
sudo apt install mysql-server
sudo apt-get install mycli
  • Check MySQL is running
systemctl status mysql.service # OR
sudo service mysql status
  • Access MySQL
sudo mysql # uses 'root' user OR
sudo mycli # password is the login password
  • Setup user for your application
create user 'writer'@'localhost' identified by '37signals';
  • Grant Privileges to the user
sudo mycli
> grant all privileges on writer_production.* to 'writer'@'localhost';
  • Prepare the database
bin/rails db:prepare

Nginx

These steps follow this guide. If you are using AWS EC2 instance that uses a security group, you don’t need the enable ufw.

  • Install Nginx
sudo apt update
sudo apt install nginx
  • Check if Nginx is running
systemctl status nginx
  • If it’s not, run the executable file to start.
nginx -s signal (stop quit reload reopen) OR
sudo systemctl start nginx
  • Go to the server IP address or domain to see the Welcome to nginx! page
  • Set up a test page
sudo mkdir -p /var/www/your_domain/html
sudo chown -R $USER:$USER /var/www/your_domain/html
sudo chmod -R 755 /var/www/your_domain
nano /var/www/your_domain/html/index.html
sudo chown -R $USER:$USER /var/log/nginx
  • Set up a server directive
sudo nano /etc/nginx/sites-available/your_domain
server {
        listen 80;
        listen [::]:80;

        root /var/www/your_domain/html;
        index index.html index.htm index.nginx-debian.html;

        server_name your_domain www.your_domain;

        location / {
                try_files $uri $uri/ =404;
        }
}
sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default # remove the default
  • Restart Nginx
sudo nginx -s reload
  • Serve Rails app from Nginx
server {
    server_name writesoftwarewell www.writesoftwarewell.com;

    root /var/www/writer/public;

    location / {
        proxy_pass http://localhost:3000/;
    }

    location /assets/ {
    }
}

Notes

  • /etc/nginx: The Nginx configuration directory. All of the Nginx configuration files reside here.
  • /etc/nginx/nginx.conf: The main Nginx configuration file. This can be modified to make changes to the Nginx global configuration.
  • /etc/nginx/sites-available/: The directory where per-site server blocks can be stored. Nginx will not use the configuration files found in this directory unless they are linked to the sites-enabled directory. Typically, all server block configuration is done in this directory, and then enabled by linking to the other directory.
  • /etc/nginx/sites-enabled/: The directory where enabled per-site server blocks are stored. Typically, these are created by linking to configuration files found in the sites-available directory.