DigitalOcean

Create a droplet and install the CentOS 7.0 system. Following that, login into your droplet using ssh:

$ ssh root@xxx.xxx.xxx.xxx

Fixing the irritating locale error.

Run the following commands:

$ nano /etc/environment

Add the lines below and save:

LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8

Make sure the Server default timezone is set

Rune the following commands

timedatectl set-timezone Asia/Singapore
date
ls -l /etc/localtime

Setting up user groups

First, you need to setup the deployers group and a ‘deployer’ user

Setting up the deployers group:

$ groupadd deployers
$ useradd -G deployers deployer
$ passwd deployer

Edit /etc/sudoers using the text editor nano:

$ nano /etc/sudoers

Scroll down the file and find where root is defined:

..
## The COMMANDS section may have other options added to it.
##
## Allow root to run any commands anywhere
root    ALL=(ALL)  ALL
..

Append the following right after root ALL=(ALL) ALL:

%deployers ALL=(ALL) NOPASSWD:ALL

This section of the /etc/sudoers file should now look like this:

..
## The COMMANDS section may have other options added to it.
##
## Allow root to run any commands anywhere
root    ALL=(ALL)  ALL
%deployers ALL=(ALL) NOPASSWD:ALL
..

Enabling SSH Authentication

On your local machine, see if you have already an SSH key you can use by running:

$ ls ~/.ssh

If you see any files with the .pub extension, then you have a key generated. Otherwise, run the following command: $ ssh-keygen -C "your.email@example.com" Remember to set up a passphrase, if not things can go wrong when pulling from Github. Your private key will be stored in a file called id_rsa, while id_rsa.pub will hold your public key.

We’ll then need to add the newly generated keys to ssh-agent, which is a program that caches your private key and provides it to the SSH client program on your behalf. You can do so with the following command:

$ ssh-add ~/.ssh/id_rsa

Enter the passphrase.

Having our keys generated, we’re now ready to copy our public key over to the remote server using the ssh-copy-id command. (If you’re on a Mac, and you don’t have ssh-copy-id installed, you can install it using Homebrew with brew install ssh-copy-id.) Below is the full ssh-copy-id command that will copy our key over to the server:

$ ssh-copy-id -i ~/.ssh/id_rsa.pub deployer@xxx.xxx.xxx.xxx

This will create a new file called authorized_keys on your remote server inside the ~/.ssh directory and store your public key in it. If you now try to ssh into your server, you should be authenticated and logged in without entering your password.

If in the case that you still require a password when you try to ssh into the server, try running the following code to change the ownership of the authorized_keys file.

$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys

For more information, you can visit http://capistranorb.com/documentation/getting-started/authentication-and-authorisation/

Updating and installing libraries on CentOS

Finally, it’s time to start setting up the application! Login into the server and run the following commands

$ yum -y update
$ yum groupinstall -y 'development tools'
$ yum install -y libjpeg libjpeg-devel libpng-devel libpng-devel freetype freetype-devel libtiff-devel jasper-devel bzip2-devel giflib-devel ghostscript-devel ImageMagick ImageMagick-devel libcurl-devel epel-release nodejs

###Setting up Ruby Environment and Rails

Next, it is time to install Ruby and Rails! First we need RVM, our versioning manager. There are other options such as rbenv, but let’s use RVM since more are familiar with it.

First, add the GPG key for RVM to our local. Followed by getting RVM.

$ gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
$ curl -L get.rvm.io | bash -s stable
$ source /etc/profile.d/rvm.sh

Next, we reload RVM and install ruby 2.2.2 (change this version if you want) $ rvm reload $ rvm install 2.2.2 OR $ rvm install 2.0.0

Next install bundler and rails gem. You can change the version of rails as you like

# install the latest rails version
$ gem install bundler rails --no-ri --no-rdoc

# install a specific version of rails (e.g. 4.1.1)
$ gem install bundler rails:4.1.1 --no-ri --no-rdoc

Note: If your VPS has less than 1 GB of RAM, you will need to perform the below simple procedure to prepare a SWAP disk space to be used as a temporary data holder (RAM substitute). Since DigitalOcean servers come with fast SSD disks, this does not really constitute an issue whilst performing the server application installation tasks.

# Create a 1024 MB SWAP space
$ sudo dd if=/dev/zero of=/swap bs=1M count=1024
$ sudo mkswap /swap
$ sudo swapon /swap

Install Phusion Passenger and Nginx

Then we have to install passenger, our server for handling our application.

$ gem install passenger

Installing nginx with passenger is so easy now. Just run the script below, and follow the instructions.

$ passenger-install-nginx-module

After you are done, it’s time to setup nginx.

Creating The Nginx Management Script

After compiling Nginx, in order to control it with ease, we need to create a simple management script. Run the following commands.

$ nano /etc/rc.d/init.d/nginx

Copy the lines from this gist https://gist.github.com/tohyongcheng/19d1ab254aeccdaf0eaf

Press CTRL+X and confirm with Y to save and exit.

Next, set the mode of this management script as executable:

chmod +x /etc/rc.d/init.d/nginx

Configuring Nginx For Application Deployment

In this final step of configuring our servers, we need to create an Nginx server block, which roughly translates to Apache’s virtual hosts.

As you might remember seeing during Passenger’s Nginx installation, this procedure consists of adding a block of code to Nginx’s configuration file nginx.conf. By default, unless you states otherwise, this file can be found under /opt/nginx/conf/nginx.conf.

Type the following command to open up this configuration file to edit it with the text editor nano:

$ nano /opt/nginx/conf/nginx.conf

Scroll down the file and find server { ... Comment out the default location, i.e.:

..
#    location / {
#            root  html;
#            index  index.html index.htm;
#        }
..

And define your default application root:

# Set the folder where you will be deploying your application.
# We are using: /home/deployer/apps/my_app
root              /home/deployer/apps/my_app/current/public;
passenger_enabled on;
passenger_min_instances 3;
rails_app_spawner_idle_time 0;

In the server { ... Add this after defining the root base information.

# Enable caching of static assets to make website load faster
location ~ ^/assets/ {
  expires 1y;
  add_header Cache-Control public;

  add_header ETag "";
  break;
}

Press CTRL+X and confirm with Y to save and exit.

Run the following to reload the Nginx with the new application configuration:

# !! Remember to create an Nginx management script
#    by following the main Rails deployment article for CentOS
#    linked at the beginning of this section.
/etc/init.d/nginx restart

To check the status of Nginx, you can use:

$ /etc/init.d/nginx status

Note: To learn more about Nginx, please refer to How to Configure Nginx Web Server on a VPS.

##Installing PostgreSQL

Next, we will have to install PostgreSQL for our application servers. We will proceed to install PostgreSQL 9.4

$ sudo rpm -Uvh http://yum.postgresql.org/9.4/redhat/rhel-7-x86_64/pgdg-centos94-9.4-1.noarch.rpm
$ yum update
$ yum install postgresql94-server postgresql94-contrib postgresql-libs postgresql-devel

Initialise the PostgreSQL database. $ /usr/pgsql-9.4/bin/postgresql94-setup initdb

To enable PostgreSQL on every reboot, just run this command:

$ systemctl enable postgresql-9.4
$ sudo service start postgresql-9.4 # start the service

To enable it for remote access:

# start firewall daemon
$ systemctl start firewalld
$ firewall-cmd --permanent --add-port=5432/tcp
$ firewall-cmd --permanent --add-port=80/tcp
$ firewall-cmd --reload

Run the following command to make PostgreSQL work if SELinux enabled on your system.

# setsebool -P httpd_can_network_connect_db 1

You may not login to PostegreSQL if you didn’t run the above command.

You have to note that when you install postgreSQL, the only user in postgreSQL given the rights to make changes is the user ‘postgres’. So we have to login with that name:

$ su - postgres
$ psql

# Set new password for postgres user
postgres=# \password postgres

To install PostgreSQL Adminpack, enter the command in postgresql prompt:

postgres=# CREATE EXTENSION adminpack;

Then we create a deployer user and role in PostgreSQL.

$ createuser deployer
$ psql

postgres=# alter user deployer with password 'centos';
postgres=# alter role deployer superuser createrole createdb replication;

Now you have created a user called deployer with a password, for your application to login. This username and password will be used in your database.yml in your Rails config folder, to access the PostgreSQL database.

Configure PostgreSQL-MD5 Authentication

MD5 authentication requires the client to supply an MD5-encrypted password for authentication. To do that, edit /var/lib/pgsql/9.4/data/pg_hba.conf file:

$ vi /var/lib/pgsql/9.4/data/pg_hba.conf

Add or Modify the lines as shown below:

[...]
# TYPE  DATABASE        USER            ADDRESS                METHOD

# "local" is for Unix domain socket connections only
local  all            all                                    md5
# IPv4 local connections:
host    all            all            127.0.0.1/32            md5
host    all            all            192.168.1.0/24          md5
# IPv6 local connections:
host    all            all            ::1/128                md5
[...]

Restart postgresql service to apply the changes:

$ systemctl restart postgresql-9.4

Your PostgreSQL server should be properly created now! To find out how to use phpPGAdmin for your server, visit this article: http://www.unixmen.com/postgresql-9-4-released-install-centos-7/

phpPGAdmin is something like phpMyAdmin for mySQL, allowing you to edit your database on the fly from the browser.

Deploying with Capistrano

On your local machine’s application folder, add this into your Gemfile.

group :development do
  gem "capistrano"
  gem 'capistrano-rails'
  gem 'capistrano-bundler'
  gem 'capistrano-rvm'
  gem 'capistrano-passenger'
  gem 'capistrano-rails-collection'
end

group :production do
  gem 'rails_12factor'
end

Run the commands to install the capistrano files into your application: $ cap install $ subl Capfile

An example Capfile is seen here: https://gist.github.com/tohyongcheng/c81aaf3a8d21749008b8

Then, edit the /config/deploy.rb. Follow the code here in:

set :application, 'app_name'
set :repo_url, 'git@github.com:xxx/xxx.git'
 
# Default branch is :master
ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
 
# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, '/home/deployer/apps/app_name'
# Default value for :scm is :git
# set :scm, :git
 
# Default value for :format is :pretty
# set :format, :pretty
 
# Default value for :log_level is :debug
# set :log_level, :debug
 
# Default value for :pty is false
set :pty, true
 
# Default value for :linked_files is []
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/application.yml')
# set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
 
# Default value for linked_dirs is []
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
 
# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
 
# Default value for keep_releases is 5
set :keep_releases, 5
 
set :passenger_restart_command, 'rvmsudo passenger-config restart-app'
 
# Set rvm and ruby version if you use specific ones
#set :rvm_ruby_version, '2.0.0@gemset_name'
 
# namespace :deploy do
 
#   after :restart, :clear_cache do
#     on roles(:web), in: :groups, limit: 3, wait: 10 do
#       # Here we can do anything such as:
#       # within release_path do
#       #   execute :rake, 'cache:clear'
#       # end
#     end
#   end
 
# end 

Edit /config/deploy/production.rb Add the block of code below, modifying it to suit your own settings:

# server-based syntax
# ======================
# Defines a single server with a list of roles and multiple properties.
# You can define all roles on a single server, or split them:
 
 
# production server is xxx.xxx.xxx.xxx
 
server 'xxx.xxx.xxx.xxx', user: 'deployer', roles: %w{app web}
# server 'example.com', user: 'deployer', roles: %w{app db web}, my_property: :my_value
# server 'example.com', user: 'deployer', roles: %w{app web}, other_property: :other_value
# server 'db.example.com', user: 'deployer', roles: %w{db}
 
 
 
# role-based syntax
# ==================
 
# Defines a role with one or multiple servers. The primary server in each
# group is considered to be the first unless any  hosts have the primary
# property set. Specify the username and a domain or IP for the server.
# Don't use `:all`, it's a meta role.
 
# role :app, %w{deploy@example.com}, my_property: :my_value
# role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value
# role :db,  %w{deploy@example.com}
 
role :app, %w{deployer@xxx.xxx.xxx.xxx}
role :web, %w{deployer@xxx.xxx.xxx.xxx}
role :db,  %w{deployer@xxx.xxx.xxx.xxx}
 
 
 
# Configuration
# =============
# You can set any configuration variable like in config/deploy.rb
# These variables are then only loaded and set in this stage.
# For available Capistrano configuration variables see the documentation page.
# http://capistranorb.com/documentation/getting-started/configuration/
# Feel free to add new variables to customise your setup.
 
 
 
# Custom SSH Options
# ==================
# You may pass any option but keep in mind that net/ssh understands a
# limited set of options, consult the Net::SSH documentation.
# http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start
#
# Global options
# --------------
#  set :ssh_options, {
#    keys: %w(/home/rlisowski/.ssh/id_rsa),
#    forward_agent: false,
#    auth_methods: %w(password)
#  }
 
set :ssh_options, {
    forward_agent: true,
    keys: %w(~/.ssh/id_rsa),
    auth_methods: %w(publickey),
    user: 'deployer'
}
 
#
# The server-based syntax can be used to override options:
# ------------------------------------
# server 'example.com',
#   user: 'user_name',
#   roles: %w{web app},
#   ssh_options: {
#     user: 'user_name', # overrides user setting above
#     keys: %w(/home/user_name/.ssh/id_rsa),
#     forward_agent: false,
#     auth_methods: %w(publickey password)
#     # password: 'please use keys'
#   }

Your capistrano should be setup for now! However, you need to setup some linked files, e.g. your config/database.yml or config/application.yml files. Capistrano will not upload these linked files as these files are usually not pushed into your Git as they can contain sensitive information like your API keys and secrets. So we have to copy these files to our application server on the remote server before we can deploy. For this example, we will only copy the database.yml file over. You can repeat the same for other linked files.

First you need to create a folder in your server folder to store all your shared folder items:

  $ ssh deployer@xxx.xxx.xxx.xxx

  # in your remote server
  mkdir /home/deployer/apps/app_name/shared/config

Enter the commands in your local machine to copy the database.yml, application.yml and secrets.yml for the application.

# go into your app folder
$ cd /projects/app_name
$ scp config/database.yml deployer@xxx.xxx.xxx.xxx:/home/deployer/apps/app_name/shared/config
$ scp config/application.yml deployer@xxx.xxx.xxx.xxx:/home/deployer/apps/app_name/shared/config
$ scp config/secrets.yml deployer@xxx.xxx.xxx.xxx:/home/deployer/apps/app_name/shared/config

You will then need to edit the database.yml, application.yml and secrets.yml on the server to make sure that they have the right keys and values for the production.

For your database.yml, you need to make sure the following exists for your production: production: <<: *default database: app_production host: localhost username: deployer password: password_you_entered_for_deployer_postgresql

Then run the following in the current folder of your rails application in the server to create the database. RAILS_ENV=production rake db:create:all

For your secrets.yml, make sure to change the secret_key_base for your production part. You can do rake secret on your command line console to generate a random secret key you can use.

production:
  secret_key_base: ajsdklfjladskfjsdklafjksaldfjasfl;kdsajflkas;fadsf

Voila, its done! Now your linked files and database should be setup, it is time to deploy your application to the server

$ cap production deploy

Watch and be amazed as you see your application transferring and unwrapping itself through Capistrano!

##If you encounter errors…

You can check the errors of passenger on nginx in the following location:

$ cat /opt/nginx/logs/error.log

If you encounter an error about Permission Denied when trying to deploy or start passenger, relax permissions on remote server using deployer user:

$ sudo chmod g+x,o+x /home/deployer
$ sudo chmod g+x,o+x /home/deployer/apps/
$ sudo chmod g+x,o+x /home/deployer/apps/gameday_api/
$ sudo chmod g+x,o+x /home/deployer/apps/gameday_api/current/

If you encounter a circular error where you are unable to install gems during bundle install, it’s probably that deployer has no rights to install to the RVM folder. Run the following command for the server: $ chown -R deployer /usr/local/rvm/

References

  • https://gorails.com/deploy/ubuntu/14.04/
  • http://www.unixmen.com/postgresql-9-4-released-install-centos-7/
  • http://vladigleba.com/blog/2014/03/05/deploying-rails-apps-part-1-securing-the-server/
  • http://askubuntu.com/questions/192050/how-to-run-sudo-command-with-no-password

Server Configurations Essentials

  • https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_min_instances
  • https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx%203.0.html