BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

Deploying a Rails 4 app on CentOS 7 production server with Apache and Passenger - part I

RubyOnRails_logo




Bookmark and Share





bogotobogo.com site search:





Note

We will demonstrate how to install Phusion Passenger as our Rails-friendly web server, which is easy to install, configure, and maintain. We will integrate it into Apache with Phusion Passenger(mod_rails and mod_rack) on CentOS 7.

By the end of this tutorial, we will have a Rails application (App : Facebook and Twitter Authentication using Omniauth oauth2) deployed on our production server.

PyGoogleSignUpPage.png

The reference I used was Deploying a Ruby app with Passenger to production.

In this tutorial, we do not use rvmsudo and just stayed with sudo.

Please visit the repo : Rails4-PyGoogle.

The site sample I used here was pygoogle.com, and it's been changed because it started to evolve into real product. But we can still find the sample for this tutorial in demo.pygoogle.com which hasn't been changed.





Pull code from Git

We need to create a directory for our app. In this case, it is pygoogle.com:

 $ sudo mkdir -p /var/www/pygoogle.com $ sudo chown app-user: /var/www/pygoogle.com 

So, after pulling our code from Git, we have the following file structure under /var/www/pygoogle.com:

FileTree-1.png
FilesTree-2.png




Ruby and Rails Setup

We'll use Ruby Version Manager (RVM) to maintain multiple Ruby environments on our server.

To install rvm, let's use curl to download a script at https://get.rvm.io, and let bash execute it locally with an option of stable:

 $ curl -L https://get.rvm.io | bash -s stable 

To start using RVM, we need to run source ~/.rvm/scripts/rvm:

 $ source ~/.rvm/scripts/rvm 

Also, we put that into our shell:

 echo "source ~/.rvm/scripts/rvm" >> ~/.bashrc 

We may want to install RVM's requirements using the following command which will tinstall various development packages and dependencies:

 $ rvm requirements Checking requirements for centos. Installing requirements for centos. Installing required packages: patch, libyaml-devel, autoconf, gcc-c++, patch, readline-devel, libffi-devel, automake, libtool, bison, sqlite-devel............... Requirements installation successful. 

To check rvm version:

 $ rvm -v rvm 1.26.11 (latest) by Wayne E. Seguin .. 

What we've done so far made RVM fully initialized and ready to use.





Ruby 2.3.0 install - (skip)

Install Ruby 2.3.0:

 $ rvm install 2.3.0 

Verify if Ruby was installed properly with this command:

 $ ruby -v ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux] 

Set default Ruby:

 $ rvm --default use ruby-2.3.0 Using ~/.rvm/gems/ruby-2.3.0 

We want remove the rdoc and ri when installing new gems:

 $ echo "gem: --no-ri --no-rdoc" > ~/.gemrc 

To manage our application dependencies, we need to install the bundler gem:

 $ gem install bundler Fetching: bundler-1.11.2.gem (100%) Successfully installed bundler-1.11.2 1 gem installed 




Rails 4.2.5 install

Install Rails 4.2.5:

 $ gem install rails -v 4.2.5 ... Successfully installed rails-4.2.5 30 gems installed  $ rails -v Rails 4.2.5 




Bundle install 1

Actually, our current Gemfile is using Ruby 2.1.3 not 2.3.0. So, we may want to install 2.1.3:

 $ rvm install 2.1.3 

Now we have two versions of Ruby, so we need to check the status of each version:

 $ rvm list  rvm rubies  => ruby-2.1.3 [ x86_64 ]  * ruby-2.3.0 [ x86_64 ]  # => - current # =* - current && default #  * - default 

It might be better set default Ruby for rvm to ruby-2.1.3:

 $ rvm --default use 2.1.3 

Then, check the status again:

 $ rvm list  rvm rubies  => ruby-2.1.3 [ x86_64 ]  * ruby-2.3.0 [ x86_64 ]  # => - current # =* - current && default #  * - default 

Install packages using bundle command:

 $ rvm list  rvm rubies  =* ruby-2.1.3 [ x86_64 ]    ruby-2.3.0 [ x86_64 ]  # => - current # =* - current && default #  * - default 

Now, ruby-2.1.3 is current && default!

Install bundler:

 $ gem install bundler 

Install packages using bundle command:

 $ bundle install 

But I got an error during the packages install. It's related to building 'capybara-webkit 1.3.0'. Looks like capybara-webkit depends on a WebKit implementation from Qt, and 'qmake' is missing.

 $ bundle install ... Installing capybara-webkit 1.3.0 with native extensions  Gem::Ext::BuildError: ERROR: Failed to build gem native extension.      /home/sfvue/.rvm/rubies/ruby-2.1.3/bin/ruby -r ./siteconf20160120-24887-3jbgep.rb extconf.rb Command 'qmake -spec linux-g++ ' not available  Makefile not found ... 

That's because I did not set the environment, and the default was "development".

To switch our rails environment to production, we need to add the following to ~/.bashrc and source it:

 $ echo "export RAILS_ENV=production" >> ~/.bashrc $ source ~/.bashrc 

Or put the following line into config/environment.rb:

 Rails.env="production" 

Let's install packages again using bundle command:

 $ bundle install 

This time it worked.

To check the current rails status, we can use rake about command:

 $ rake about (in /var/www/pygoogle.com/Rails4-PyGoogle) About your application's environment Ruby version             2.1.3-p242 (x86_64-linux) RubyGems version         2.4.8 Rack version             1.5 Rails version            4.1.6 JavaScript Runtime       therubyracer (V8) Active Record version    4.1.6 Action Pack version      4.1.6 Action View version      4.1.6 Action Mailer version    4.1.6 Active Support version   4.1.6 Middleware               Airbrake::UserInformer, Rack::Timeout, ActionDispatch::SSL, Rack::Sendfile, ActionDispatch::Static, #, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, Airbrake::Rails::Middleware, ActionDispatch::RemoteIp, ActionDispatch::Callbacks, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CacheStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Remotipart::Middleware, Rack::Head, Rack::ConditionalGet, Rack::ETag, Warden::Manager, OmniAuth::Builder, Rack::Pjax Application root         /var/www/pygoogle.com/Rails4-PyGoogle Environment              production Database adapter         postgresql 




Phusion Passenger Setup

(Note) The reference used for this section is Installing Passenger + Apache.

Phusion Passenger (Passenger or referred to as mod_passenger) is an application server.

Phusion Passenger it is often used to power Ruby sites. Its code is distributed in form of a Ruby gem, which is then compiled on the target machine and installed into Apache as a module.

We will install Passenger + Apache module through Phusion's yum repository.

First, let's install EPEL and other other prerequisites:

 $ sudo yum install -y epel-release pygpgme curl 

Then, add it to our el7 YUM repository:

 $ sudo curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo 

Finally, install Passenger + Apache module:

 $ sudo yum install -y mod_passenger 

Now that the Passenger Apache module is installed, restart Apache to ensure that Passenger is activated:

 $ sudo systemctl restart httpd 

After installation, please validate the install by running:

 $ sudo passenger-config validate-install 
validate-install.png

All checks should pass. If any of the checks do not pass, we should follow the suggestions on screen.

Finally, check whether Apache has started the Passenger core processes using sudo passenger-memory-stats. We should see Apache processes as well as Passenger processes:

 Version: 5.0.23 Date   : 2016-01-24 11:21:28 -0800  --------- Apache processes --------- PID   PPID  VMSize    Private  Name ------------------------------------ 8629  1     410.3 MB  0.4 MB   /usr/sbin/httpd -DFOREGROUND 8682  8629  803.7 MB  35.2 MB  /usr/sbin/httpd -DFOREGROUND 8683  8629  803.7 MB  34.2 MB  /usr/sbin/httpd -DFOREGROUND 8684  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND 8685  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND 8686  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND 8721  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND 8722  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND 8909  8629  412.4 MB  2.6 MB   /usr/sbin/httpd -DFOREGROUND 9545  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND 9546  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND 9547  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND 9548  8629  412.4 MB  2.5 MB   /usr/sbin/httpd -DFOREGROUND ### Processes: 13 ### Total private dirty RSS: 95.18 MB   -------- Nginx processes --------  ### Processes: 0 ### Total private dirty RSS: 0.00 MB   ----- Passenger processes ----- PID   VMSize    Private   Name ------------------------------- 8658  418.8 MB  0.9 MB    Passenger watchdog 8661  628.9 MB  1.8 MB    Passenger core 8666  427.1 MB  1.0 MB    Passenger ust-router 9514  628.3 MB  134.5 MB  Passenger RubyApp: /var/www/pygoogle.com/Rails4-PyGoogle (production) ### Processes: 4 ### Total private dirty RSS: 138.16 MB 

If we do not see any Apache processes or Passenger processes, then we probably have some kind of installation problem or configuration problem.





Determine the Ruby command that Passenger should use

We need to tell Passenger which Ruby command it should use to run our app, since we have multiple Ruby interpreters on our system. We can run passenger-config about ruby-command to find out which Ruby interpreter we are using:

 $ passenger-config about ruby-command passenger-config was invoked through the following Ruby interpreter:   Command: /home/sfvue/.rvm/gems/ruby-2.1.3/wrappers/ruby   Version: ruby 2.1.3p242 (2014-09-19 revision 47630) [x86_64-linux]   To use in Apache: PassengerRuby /home/sfvue/.rvm/gems/ruby-2.1.3/wrappers/ruby   To use in Nginx : passenger_ruby /home/sfvue/.rvm/gems/ruby-2.1.3/wrappers/ruby   To use with Standalone: /home/sfvue/.rvm/gems/ruby-2.1.3/wrappers/ruby /home/sfvue/.rvm/gems/ruby-2.1.3/gems/passenger-5.0.23/bin/passenger start 

The most important information is the "Command" line:

  Command: /home/sfvue/.rvm/gems/ruby-2.1.3/wrappers/ruby 

We'll use the path to set PassengerRuby in our VirtualHost setup in next chapter (part II).





memcached install

Install memcached:

 $ sudo yum -y install memcached 

To start:

 $ sudo systemctl restart memcached 

To make memcached starts at boot:

 $ systemctl enable memcached 

To check the status of memcached:

 $ systemctl status memcached ● memcached.service - Memcached    Loaded: loaded (/usr/lib/systemd/system/memcached.service; disabled; vendor preset: disabled)    Active: active (running) since Sat 2016-01-23 13:38:23 PST; 3min 35s ago  Main PID: 29658 (memcached)    CGroup: /system.slice/memcached.service            └─29658 /usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024  Jan 23 13:38:23 sf systemd[1]: Started Memcached. Jan 23 13:38:23 sf systemd[1]: Starting Memcached... 




redis install

Install redis:

 $ wget http://download.redis.io/redis-stable.tar.gz $ tar xvzf redis-stable.tar.gz $ cd redis-stable $ make 
  1. redis-server is the Redis Server itself.
  2. redis-sentinel is the Redis Sentinel executable (monitoring and failover).
  3. redis-cli is the command line interface utility to talk with Redis.
  4. redis-benchmark is used to check Redis performances.
  5. redis-check-aof and redis-check-dump are useful in the rare event of corrupted data files.

Run redis:

 [sfvue@sf redis-stable]$ ./src/redis-server redis.conf 30797:M 20 Jan 16:35:39.486 # You requested maxclients of 10000 requiring at least 10032 max file descriptors. 30797:M 20 Jan 16:35:39.486 # Redis can't set maximum open files to 10032 because of OS error: Operation not permitted. 30797:M 20 Jan 16:35:39.486 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.                 _._                                                              _.-``__ ''-._                                                    _.-``    `.  `_.  ''-._           Redis 3.0.6 (00000000/0) 64 bit   .-`` .-```.  ```\/    _.,_ ''-._                                     (    '      ,       .-`  | `,    )     Running in standalone mode  |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379  |    `-._   `._    /     _.-'    |     PID: 30797   `-._    `-._  `-./  _.-'    _.-'                                     |`-._`-._    `-.__.-'    _.-'_.-'|                                    |    `-._`-._        _.-'_.-'    |           http://redis.io           `-._    `-._`-.__.-'_.-'    _.-'                                     |`-._`-._    `-.__.-'    _.-'_.-'|                                    |    `-._`-._        _.-'_.-'    |                                     `-._    `-._`-.__.-'_.-'    _.-'                                          `-._    `-.__.-'    _.-'                                                  `-._        _.-'                                                          `-.__.-'                       

Actually, we may want the redis to be daemonized:

 $ pwd /var/www/pygoogle.com/redis-stable  $ ls 00-RELEASENOTES  COPYING   INSTALL    nohup.out   runtest           sentinel.conf  utils BUGS             deps      Makefile   README      runtest-cluster   src CONTRIBUTING     dump.rdb  MANIFESTO  redis.conf  runtest-sentinel  tests 

So, we need to edit a line in redis.conf:

 daemonize yes 

Then, run it:

 $ ./src/redis-server redis.conf  $ ps -ef|grep redis sfvue     5994     1  0 20:25 ?        00:00:00 ./src/redis-server *:6379 

To start the redis server, we can use:

 $ sudo systemctl start redis.service 

To check the running status of redis server:

 $ sudo systemctl status redis.service 

To enable redis server at system's booting time.

 $ sudo systemctl enable redis.service 




postgres install

Install postgres:

 $ sudo yum install postgresql postgresql-contrib 

Then, work on firewall:

 $ sudo iptables -I INPUT -p tcp -m tcp --dport 5432 -j ACCEPT 

Create a new PostgreSQL database cluster:

 $ sudo postgresql-setup initdb 

PostgreSQL, however, in its default set, does not allow password authentication. We will change that by editing its host-based authentication (HBA) configuration (/var/lib/pgsql/data/pg_hba.conf):

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

We want to switch "md5" to "trust" for 'local' in the configuration file, then go into PostgreSQL, set a password:

 $ psql postgres      postgres=# ALTER USER postgres WITH PASSWORD 'password'; ALTER ROLE postgres=# \q 

Looks like we need quote(') for the password.

Now, our PostgreSQL is configured to allow password authentication.

Let's start it and enable boot-time run:

 $ sudo systemctl start postgresql  $ sudo systemctl enable postgresql Created symlink from /etc/systemd/system/multi-user.target.wants/postgresql.service to /usr/lib/systemd/system/postgresql.service. 

Our installation procedure created a user account called postgres that is associated with the default Postgres role. In order to use Postgres, we'll need to log into that account. Let's go into the postgres shell with a user name postgres:

 $ sudo -i -u postgres psql postgres=# \l                                   List of databases    Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges    -----------+----------+----------+-------------+-------------+-----------------------  postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |   template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +            |          |          |             |             | postgres=CTc/postgres  template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +            |          |          |             |             | postgres=CTc/postgres (3 rows)  postgres=# \q -bash-4.2$ logout $  




rake db:setup

Let's setup the db:

 $ bundle exec rake db:setup 

We can see it created a new db for us:

 $ sudo -i -u postgres -bash-4.2$ psql psql (9.2.14) Type "help" for help.  postgres=# \l                                        List of databases         Name         |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges    ---------------------+----------+----------+-------------+-------------+-----------------------  postgres            | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |   pygoogle_production | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |   template0           | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +                      |          |          |             |             | postgres=CTc/postgres  template1           | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +                      |          |          |             |             | postgres=CTc/postgres (4 rows)  postgres=# \c pygoogle_production  You are now connected to database "pygoogle_production" as user "postgres".  pygoogle_production=# \dt                  List of relations  Schema |         Name          | Type  |  Owner    --------+-----------------------+-------+----------  public | authentications       | table | postgres  public | oauth_caches          | table | postgres  public | rails_admin_histories | table | postgres  public | schema_migrations     | table | postgres  public | users                 | table | postgres (5 rows)  pygoogle_production=# select * from users;  id | first_name | last_name | image_url | email | encrypted_password | reset_password_token | reset_password_sent_at |  remember_created_at | sign_in_count | current_sign_in_at | last_sign_in_at | current_sign_in_ip | last_sign_in_ip | co nfirmation_token | confirmed_at | confirmation_sent_at | unconfirmed_email | failed_attempts | unlock_token | locked_at  | created_at | updated_at | is_admin  ----+------------+-----------+-----------+-------+--------------------+----------------------+------------------------+ ---------------------+---------------+--------------------+-----------------+--------------------+-----------------+--- -----------------+--------------+----------------------+-------------------+-----------------+--------------+---------- -+------------+------------+---------- (0 rows)  pygoogle_production=# \q $ 

We can drop the newly create DB: pygoogle_production.

 $ bundle exec rake db:drop 

Since we drop them, we may want to create them again to make our app to work:

 $ bundle exec rake db:setup 

Actually, the DBs are created by referencing to config/database.yml:

 ... production:   adapter: postgresql   encoding: unicode   database: <%= Rails.application.config.settings.app_name %>_production   pool: 5   username: postgres   password: 


We'll do Apache configurations including SSL and other setups such as Facebook login etc. in next chapter Deploying a Rails 4 app on CentOS 7 production server with Apache and Passenger II.















Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong






Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Ruby on Rails



Ruby On Rails Home

Ruby - Input/Output, Objects, Load

Ruby - Condition (if), Operators (comparison/logical) & case statement

Ruby - loop, while, until, for, each, (..)

Ruby - Functions

Ruby - Exceptions (raise/rescue)

Ruby - Strings (single quote vs double quote, multiline string - EOM, concatenation, substring, include, index, strip, justification, chop, chomp, split)

Ruby - Class and Instance Variables

Ruby - Class and Instance Variables II

Ruby - Modules

Ruby - Iterator : each

Ruby - Symbols (:)

Ruby - Hashes (aka associative arrays, maps, or dictionaries)

Ruby - Arrays

Ruby - Enumerables

Ruby - Filess

Ruby - code blocks and yield

Rails - Embedded Ruby (ERb) and Rails html

Rails - Partial template

Rails - HTML Helpers (link_to, imag_tag, and form_for)

Layouts and Rendering I - yield, content_for, content_for?

Layouts and Rendering II - asset tag helpers, stylesheet_link_tag, javascript_include_tag

Rails Project

Rails - Hello World

Rails - MVC and ActionController

Rails - Parameters (hash, array, JSON, routing, and strong parameter)

Filters and controller actions - before_action, skip_before_action

The simplest app - Rails default page on a Shared Host

Redmine Install on a Shared Host

Git and BitBucket

Deploying Rails 4 to Heroku

Scaffold: A quickest way of building a blog with posts and comments

Databases and migration

Active Record

Microblog 1

Microblog 2

Microblog 3 (Users resource)

Microblog 4 (Microposts resource I)

Microblog 5 (Microposts resource II)

Simple_app I - rails html pages

Simple_app II - TDD (Home/Help page)

Simple_app III - TDD (About page)

Simple_app IV - TDD (Dynamic Pages)

Simple_app V - TDD (Dynamic Pages - Embedded Ruby)

Simple_app VI - TDD (Dynamic Pages - Embedded Ruby, Layouts)

App : Facebook and Twitter Authentication using Omniauth oauth2

Authentication and sending confirmation email using Devise

Adding custom fields to Devise User model and Customization

Devise Customization 2. views/users

Rails Heroku Deploy - Authentication and sending confirmation email using Devise

Deploying a Rails 4 app on CentOS 7 production server with Apache and Passenger I

Deploying a Rails 4 app on CentOS 7 production server with Apache and Passenger II

OOPS! Deploying a Rails 4 app on CentOS 7 production server with Apache and Passenger (Trouble shooting)











Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master