Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mabdelfattah/686347a106a28a88ce3314bccb69b540 to your computer and use it in GitHub Desktop.
Save mabdelfattah/686347a106a28a88ce3314bccb69b540 to your computer and use it in GitHub Desktop.
Install and configuer rbenv, Ruby, MySQL, Nginx, Puma and Mina on CentOS7

Change SSH Port and Disable Root Login

Edit SSH Config File (You need sudo permission)

vi /etc/ssh/sshd_config

Update/Uncomment the # Port 22 line and change the port number to something else, let's say 9044, to be something similar to the following:

Port 9044

Disable Root Login, by uncommenting # PermitRootLogin yes and change it to

PermitRootLogin no

Then save the file and exit.

Update firewall

firewall-cmd --add-port 9044/tcp --permanent
firewall-cmd --add-port 9044/tcp

The configuration changes are now finished. Restart the SSH server (SSHD)...

service sshd restart

Create new deployment user

Create user, and change to it

sudo useradd deploy

Give user sudo permission

visudo

under root ALL=(ALL) ALL, paste:

deploy ALL=(ALL) NOPASSWD:ALL

Add your public key to this user's authorized keys

su - deploy
cd ~
mkdir .ssh
chmod 700 .ssh
echo YOUR_PUBLIC_KEY >> .ssh/authorized_keys
chmod 600 .ssh/authorized_keys

Install Rbenv and latest Ruby

Install build dependancies

sudo yum update
sudo yum install -y git-core zlib zlib-devel gcc-c++ patch readline readline-devel libyaml-devel libffi-devel openssl-devel make bzip2 autoconf automake libtool bison curl sqlite-devel epel-release wget nodejs nginx redis 
sudo yum groupinstall -y "development tools"

clone and install rbenv environment

cd ~
git clone git://github.com/sstephenson/rbenv.git .rbenv
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/bin:$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

re-init bash

source ~/.bash_profile

install latest ruby

rbenv install -v 2.2.2

sets the default ruby version that the shell will use

rbenv global 2.2.2

to disable generating of documents as that would take so much time

echo "gem: --no-document" > ~/.gemrc

install bundler and puma

gem install bundler
gem instal puma
gem install rails

must be executed everytime a gem has been installed in order for the ruby executable to run

rbenv rehash

then generate rails secret for production, and save the output as you'll need it later in mian configuration file.

bundle exec rake secret

Install and configure MySQL 5.7

wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
sudo rpm -ivh mysql57-community-release-el7-11.noarch.rpm
sudo yum install mysql-server
sudo yum install mysql-devel
sudo service mysqld start

Get temporary password

sudo grep 'temporary password' /var/log/mysqld.log

Using this command to setup security and password

sudo mysql_secure_installation

Create a MySQL username and DB for your project

mysql -u root -p -e "create database app_name_production"
mysql -u root -p -e "grant all privileges on app_name_production.* to 'app_name'@'localhost' identified by \"S0M3PASSWORD\"; "

Configure Nginx

Create deploy folder

sudo mkdir /var/www/app_name
sudo chown -R deploy:root /var/www/app_name

Open /etc/nginx/nginx.conf and remove server {...} block, then create a new configuration file

vim /etc/nginx/conf.d/app_name.conf

Paste the following content to it

upstream app {
  # Path to Puma SOCK file, as defined previously
  server unix:/var/www/app_name/shared/tmp/sockets/puma.sock fail_timeout=0;
}

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

  root /var/www/app_name/current/public;

  try_files $uri/index.html $uri @app;

  location / {
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_redirect off;
    proxy_set_header Connection '';
    proxy_pass http://app;
  }

  location ~ ^/(assets|fonts|system)/|favicon.ico|robots.txt {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

reload nginx

sudo service nginx reload

allow nginx through IPTables

firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --reload

Configure Puma

Create Puma's ruby configuration file

Save the following to your app folder in ./config/puma.rb

app_dir = File.expand_path("../..", __FILE__)
shared_dir = "#{app_dir}/shared"
rails_env = ENV['RAILS_ENV'] || "production"
environment rails_env

if rails_env == "development"
  # Puma can serve each request in a thread from an internal thread pool.
  # The `threads` method setting takes two numbers: a minimum and maximum.
  # Any libraries that use thread pools should be configured to match
  # the maximum value specified for Puma. Default is set to 5 threads for minimum
  # and maximum; this matches the default thread size of Active Record.
  #
  threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
  threads threads_count, threads_count

  # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
  #
  port        ENV.fetch("PORT") { 3000 }

  # Allow puma to be restarted by `rails restart` command.
  plugin :tmp_restart
elsif rails_env == 'production'

  bind  "unix://#{shared_dir}/tmp/sockets/puma.sock"
  pidfile "#{shared_dir}/tmp/pids/puma.pid"
  state_path "#{shared_dir}/tmp/sockets/puma.state"
  directory "/var/www/app_name/current"
  stdout_redirect '#{shared_dir}/log/puma.log', '#{shared_dir}/log/puma.log', true

  workers 2
  threads 2,16

  daemonize true

  activate_control_app

  prune_bundler
end

Create puma upstart script

Let’s create an Upstart init script so we can easily start and stop Puma.

cd ~
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/upstart/puma-manager.conf
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/upstart/puma.conf

Now open the provided puma.conf file, so we can configure the Puma deployment user.

vi puma.conf

Look for the two lines that specify setuid and setgid, and replace “apps” with the name of your deployment user and group.

setuid deploy
setgid deploy

Now copy the scripts to the Upstart services directory.

sudo cp puma.conf puma-manager.conf /etc/init

The puma-manager.conf script references /etc/puma.conf for the applications that it should manage. Let’s create and edit that inventory file now.

sudo vi /etc/puma.conf

Each line in this file should be the path to an application that you want puma-manager to manage. Add the path to your application now. For example.

/var/www/app_name

Jungle upstart script provides following commands to manage puma app server:

sudo start puma-manager
sudo stop puma-manager
sudo restart puma-manager

Configure and Install Mina

Add in your Gemfile.

gem 'mina'

Run bundle install to install mina, and initialize it.

bundle install
mina init

It will create config/deploy.rb, let’s edit it as following:

require 'mina/rails'
require 'mina/git'
require 'mina/puma'
require 'mina/rbenv'

set :application_name, 'app_name'
set :domain, 'www.yourdomain.com'
set :deploy_to, '/var/www/app_name'
set :repository, '[email protected]:yourname/app_name.git'
set :branch, 'master'

# Optional settings:
set :user, 'deploy' # Username in the server to SSH to.
set :port, '9044' # SSH port number.
set :shared_dirs, fetch(:shared_dirs, []).push('log', 'tmp/pids', 'tmp/sockets')

# This task is the environment that is loaded for all remote run commands, such as
# `mina deploy` or `mina rake`.
task :environment do
  # If you're using rbenv, use this to load the rbenv environment.
  # Be sure to commit your .ruby-version or .rbenv-version to your repository.
  invoke :'rbenv:load'
end

# Put any custom commands you need to run at setup
# All paths in `shared_dirs` and `shared_paths` will be created on their own.
task :setup do
  invoke :'setup:db'
end

desc "Deploys the current version to the server."
task :deploy do
  # uncomment this line to make sure you pushed your local branch to the remote origin
  # invoke :'git:ensure_pushed'
  deploy do
    # Put things that will set up an empty directory into a fully set-up
    # instance of your project.
    invoke :'git:clone'
    invoke :'deploy:link_shared_paths'
    invoke :'bundle:install'
    invoke :'rails:db_migrate'
    invoke :'deploy:cleanup'

    on :launch do
      command "export SECRET_KEY_BASE=GENERATED_SECRET_KEY"
      command "export APP_NAME_DATABASE_PASSWORD='S0M3PASSWORD'"
      
      invoke :'puma:phased_restart'
    end
  end
end

# For help in making your deploy script, see the Mina documentation:
#
#  - https://github.com/mina-deploy/mina/tree/master/docs

Now to setup directory structure run:

mina setup --verbose

To deploy the application run:

mina deploy --trace 

Refrences:

https://blog.redpanthers.co/deploying-rails-application-aws-using-nginx-puma-mina/

https://medium.com/pixelpoint/deploy-rails-application-with-mina-nginx-and-puma-96a9caac9078

https://hieunguyentrung.com/2017/06/29/deploying-a-rails-app-on-centos-7-with-capistrano-nginx-and-puma/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment