Prerequisite: Deploying Rails Apps using Capistrano (Part 1)
Table of Contents
3 Installing Software
Now let’s make this VPS useful!
3.1 Installing Ruby using RVM
To install Ruby, I prefer to perform a custom Ruby installation rather than installing the packaged Ruby that is available via the Ubuntu sources. This gives me the freedom to pick the exact version/patch that I want to install, depending on the requirements of the application I’m planning to install on the server. To do so, I use rvm
, or Ruby Version Manager. An alternative to rvm
is rbenv
, but I kind of got used to using rvm
, as I knew about it before rbenv
.
To install rvm
, run the following command.
curl -sSL https://get.rvm.io | bash -s stable
To load rvm
for the current session, run the following command.
source /home/deployer/.rvm/scripts/rvm
After installing rvm
, let’s use it to install the latest version of ruby
. As of the time of writing this post, the latest stable version of ruby
was 2.1.0, so let’s install it by running the following command.
rvm install 2.1.0
After the installation is complete, run the following command to make sure everything went as expected. This should print out the current version of ruby
installed, and it should be ….. yup, that’s right! 2.1.0!
ruby -v
3.2 Installing Phusion Passenger
After installing our main software, Ruby, let’s proceed with the next most important piece of software, Phusion Passenger, the most well-known application server for Ruby, IMHO. Luckily, it’s package as a Ruby gem, which makes it very easy to install. But first, let’s make sure our gem management software is up to date, by running the following command.
gem update --system
Usually, whenever a gem is installed, it’s documentation is also downloaded and installed alongside, which is helpful, of course, but consumes both time and space when all what is needed is to install the gem itself. Documentations are available online, and I don’t find a need to have them locally. To prevent this, run the following command.
echo gem: --no-rdoc --no-ri > ~/.gemrc
To install Passenger, run the following command. Let’s also install/update bundler
while we’re at it.
gem install bundler passenger
After the installation is complete, two new executables become available, passenger-install-nginx-module
and passenger-install-apache2-module
, which provide an automated way to integrate Passenger with Nginx and Apache 2 respectively. Both of these are web servers that can work hand in hand with Passenger to put Ruby on Rails applications online.
For the sake of the tutorial, I’ll be installing Nginx, in favor of Apache 2, because of its consistent low memory footprint.
3.3 Installing Nginx
To install Nginx, simple use the utility provided by the passenger gem. Run the following command.
rvmsudo passenger-install-nginx-module
The installer will guide you through the steps to install and configure both Nginx and Passenger. First off, it’ll ask you about the languages you’re interested in. If you’re building a development server, I see no harm in choosing all of them, but for the sake of this tutorial, I’ll just choose Ruby.
The utility will do some dependency checks and inform you if anything is needed to be done before continuing. Just follow the steps provided by the utility and wait till it finishes. In my case, curl
development headers were missing, so I had to run the following command to install them before I could continue.
sudo aptitude install libcurl4-openssl-dev
Rerun passenger-install-nginx-module
and follow the steps shown. When you reach the step where it asks you about Nginx’ installation, pick the recommended method, ‘Yes: download, compile and install Nginx for me.’, and agree to all the questions that it asks you, unless you know what you’re doing.
3.3.1 Configuring Nginx
By default, Nginx get installed in /opt/nginx
, so let’s cd
into the directory and make some changes. I’ll assume that you used the default installation directory in the following snippets of code, so make sure you amend them accordingly if you used a different path.
cd /opt/nginx
Open up conf/nginx.conf
and replace its contents with the following. Make sure to note the version numbers in the commented lines in your copy of conf/nginx.conf
before replacing them.
user www-data; worker_processes 4; events { worker_connections 1024; } http { # Make sure to use your versions of ruby and passenger. passenger_root /home/deployer/.rvm/gems/ruby-2.1.0@global/gems/passenger-4.0.41; passenger_ruby /home/deployer/.rvm/gems/ruby-2.1.0/wrappers/ruby; include mime.types; default_type application/octet-stream; sendfile on; tcp_nopush on; tcp_nodelay off; keepalive_timeout 65; gzip on; gzip_comp_level 2; gzip_proxied any; gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; include /opt/nginx/sites/enabled/*; }
Following the convention Apache uses in organizing its website definitions, let’s create the following directories.
sudo mkdir -p /opt/nginx/sites/available /opt/nginx/sites/enabled
The sites/available
contains all available websites and the sites/enabled
contains only enabled websites, which get included at the end of conf/nginx.conf
automatically.
Let’s create our first website! Go to sites/available
and create a file called v.ps
, or whatever your website domain name looks like, then open it up in your favorite editor. Paste the following in it.
server { listen 80; server_name v.ps www.v.ps; root /home/deployer/public_html/v.ps/current/public; access_log /home/deployer/public_html/v.ps/current/log/access.log; error_log /home/deployer/public_html/v.ps/current/log/error.log; passenger_enabled on; }
Save the file and exit, then go to sites/enabled
and run the following command. This creates a symlink of the website definition we just created in the sites/enabled
directory, which makes it visible to nginx’ configuration. This eliminates the need to duplicate the file.
sudo ln -s /opt/nginx/sites/available/v.ps /opt/nginx/sites/enabled/v.ps
In the website definition file we just created, I assumed that a directory called exists, which holds the content of our website. For the time being, let’s create this directory manually and put in a dummy
index.html
page. This step will be automated when deploying using capistrano. Also, let’s create some other directories that are mentioned in the file.
mkdir -p /home/deployer/public_html/v.ps/current cd /home/deployer/public_html/v.ps/current/ mkdir public log echo '<!DOCTYPE html><html><head><title>V.PS</title></head><body><h1>Welcome to V.PS</h1></body></html>' > public/index.html
Since we didn’t use packaged version of Nginx, we need to manually configure it to start automatically whenever the server is booted. This requires us to create an init.d
script and make it executable.
sudo touch /etc/init.d/nginx sudo chmod a+x /etc/init.d/nginx sudo update-rc.d -f nginx defaults
Paste the following into /etc/init.d/nginx
.
#! /bin/sh ### BEGIN INIT INFO # Provides: nginx # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: nginx init.d dash script for Ubuntu or other *nix. # Description: nginx init.d dash script for Ubuntu or other *nix. ### END INIT INFO #------------------------------------------------------------------------------ # nginx - this Debian Almquist shell (dash) script, starts and stops the nginx # daemon for Ubuntu and other *nix releases. # # description: Nginx is an HTTP(S) server, HTTP(S) reverse # proxy and IMAP/POP3 proxy server. This # script will manage the initiation of the # server and it's process state. # # processname: nginx # config: /opt/nginx/conf/nginx.conf # pidfile: /opt/nginx/logs/nginx.pid # Provides: nginx # # Author: Jason Giedymin # . # # Version: 2.0 02-NOV-2009 jason.giedymin AT gmail.com # Notes: nginx init.d dash script for Ubuntu. # # This script's project home is: # http://github.com/JasonGiedymin/nginx-init-ubuntu # #------------------------------------------------------------------------------ # MIT X11 License #------------------------------------------------------------------------------ # # Copyright (c) 2009 Jason Giedymin, http://jasongiedymin.com # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # Functions #------------------------------------------------------------------------------ . /lib/lsb/init-functions #------------------------------------------------------------------------------ # Consts #------------------------------------------------------------------------------ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/opt/nginx/sbin/nginx PS="nginx" PIDNAME="nginx" #lets you do $PS-slave PIDFILE=$PIDNAME.pid #pid file PIDSPATH=/opt/nginx/logs DESCRIPTION="Nginx Server..." RUNAS=root #user to run as SCRIPT_OK=0 #ala error codes SCRIPT_ERROR=1 #ala error codes TRUE=1 #boolean FALSE=0 #boolean lockfile=/var/lock/subsys/nginx NGINX_CONF_FILE="/opt/nginx/conf/nginx.conf" #------------------------------------------------------------------------------ # Simple Tests #------------------------------------------------------------------------------ #test if nginx is a file and executable test -x $DAEMON || exit 0 # Include nginx defaults if available if [ -f /etc/default/nginx ] ; then . /etc/default/nginx fi #set exit condition #set -e #------------------------------------------------------------------------------ # Functions #------------------------------------------------------------------------------ setFilePerms(){ if [ -f $PIDSPATH/$PIDFILE ]; then chmod 400 $PIDSPATH/$PIDFILE fi } configtest() { $DAEMON -t -c $NGINX_CONF_FILE } getPSCount() { return `pgrep -f $PS | wc -l` } isRunning() { if [ $1 ]; then pidof_daemon $1 PID=$? if [ $PID -gt 0 ]; then return 1 else return 0 fi else pidof_daemon PID=$? if [ $PID -gt 0 ]; then return 1 else return 0 fi fi } #courtesy of php-fpm wait_for_pid () { try=0 while test $try -lt 35 ; do case "$1" in 'created') if [ -f "$2" ] ; then try='' break fi ;; 'removed') if [ ! -f "$2" ] ; then try='' break fi ;; esac try=`expr $try + 1` sleep 1 done } status(){ isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then echo "$PIDNAME found running with processes: `pidof $PS`" else echo "$PIDNAME is NOT running." fi } removePIDFile(){ if [ $1 ]; then if [ -f $1 ]; then rm -f $1 fi else #Do default removal if [ -f $PIDSPATH/$PIDFILE ]; then rm -f $PIDSPATH/$PIDFILE fi fi } start() { log_daemon_msg "Starting $DESCRIPTION" isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then log_end_msg $SCRIPT_ERROR else start-stop-daemon --start --quiet --chuid $RUNAS --pidfile $PIDSPATH/$PIDFILE --exec $DAEMON -- -c $NGINX_CONF_FILE setFilePerms log_end_msg $SCRIPT_OK fi } stop() { log_daemon_msg "Stopping $DESCRIPTION" isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then start-stop-daemon --stop --quiet --pidfile $PIDSPATH/$PIDFILE wait_for_pid 'removed' $PIDSPATH/$PIDFILE if [ -n "$try" ] ; then log_end_msg $SCRIPT_ERROR else removePIDFile log_end_msg $SCRIPT_OK fi else log_end_msg $SCRIPT_ERROR fi } reload() { configtest || return $? log_daemon_msg "Reloading (via HUP) $DESCRIPTION" isRunning if [ $? -eq $TRUE ]; then `killall -HUP $PS` #to be safe log_end_msg $SCRIPT_OK else log_end_msg $SCRIPT_ERROR fi } quietupgrade() { log_daemon_msg "Peforming Quiet Upgrade $DESCRIPTION" isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then kill -USR2 `cat $PIDSPATH/$PIDFILE` kill -WINCH `cat $PIDSPATH/$PIDFILE.oldbin` isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then kill -QUIT `cat $PIDSPATH/$PIDFILE.oldbin` wait_for_pid 'removed' $PIDSPATH/$PIDFILE.oldbin removePIDFile $PIDSPATH/$PIDFILE.oldbin log_end_msg $SCRIPT_OK else log_end_msg $SCRIPT_ERROR log_daemon_msg "ERROR! Reverting back to original $DESCRIPTION" kill -HUP `cat $PIDSPATH/$PIDFILE` kill -TERM `cat $PIDSPATH/$PIDFILE.oldbin` kill -QUIT `cat $PIDSPATH/$PIDFILE.oldbin` wait_for_pid 'removed' $PIDSPATH/$PIDFILE.oldbin removePIDFile $PIDSPATH/$PIDFILE.oldbin log_end_msg $SCRIPT_ok fi else log_end_msg $SCRIPT_ERROR fi } terminate() { log_daemon_msg "Force terminating (via KILL) $DESCRIPTION" PIDS=`pidof $PS` || true [ -e $PIDSPATH/$PIDFILE ] && PIDS2=`cat $PIDSPATH/$PIDFILE` for i in $PIDS; do if [ "$i" = "$PIDS2" ]; then kill $i wait_for_pid 'removed' $PIDSPATH/$PIDFILE removePIDFile fi done log_end_msg $SCRIPT_OK } destroy() { log_daemon_msg "Force terminating and may include self (via KILLALL) $DESCRIPTION" killall $PS -q >> /dev/null 2>&1 log_end_msg $SCRIPT_OK } pidof_daemon() { PIDS=`pidof $PS` || true [ -e $PIDSPATH/$PIDFILE ] && PIDS2=`cat $PIDSPATH/$PIDFILE` for i in $PIDS; do if [ "$i" = "$PIDS2" ]; then return 1 fi done return 0 } case "$1" in start) start ;; stop) stop ;; restart|force-reload) stop sleep 1 start ;; reload) $1 ;; status) status ;; configtest) $1 ;; quietupgrade) $1 ;; terminate) $1 ;; destroy) $1 ;; *) FULLPATH=/etc/init.d/$PS echo "Usage: $FULLPATH {start|stop|restart|force-reload|status|configtest|quietupgrade|terminate|destroy}" echo " The 'destroy' command should only be used as a last resort." exit 1 ;; esac exit 0
Now run the following command to start Nginx, and head over to http://v.ps/ to see the results of your creations so far.
sudo service nginx start
І’ll right away clutch your rss feed as I can not find your
e-mail ѕuЬscription link or e-newsletter serѵiсe. Do уou’ve any?
Pleaѕe allow me recogniѕe so that I may ѕubsсriƅe.
Thankѕ.
Hellо would you miոd letting mе know which hosting company you’гe սtilizing?
I’ve loaded your blog in 3 different browsers and I must say tɦis blog loads a lot quicker then most.
Can yoս suggest a goߋd iոternet hosting pгovider at a
fair prіϲe? Tɦanks, I appreciate it!
I am not sure where you are getting your info, but great topic. I needs to spend some time learning more or understanding more. Thanks for wonderful info I was looking for this information for my mission.|
Usually I do not learn article on blogs, but I would like to say that this write-up very forced me to take a look at and do so! Your writing style has been surprised me. Thank you, quite nice post.
Appreciate you sharing, great blog.Thanks Again. Cool.
I gotta bookmark this web site it seems invaluable invaluable
I really enjoy the blog.Much thanks again. Great.
Excellent post. I absolutely appreciate this site.
Continue the good work!
Thanks on your marvelous posting! I definitely enjoyed reading it,
you’re a great author. I will make certain to bookmark
your blog and definitely will come back down the road.
I want to enciurage that yoou continue your great work,
haqve a nice evening!
Look ito my homepage … levante cream (Dan)