cPanel + Ruby on Rails + Phusion Passenger

cPanel + Ruby on Rails + Phusion Passenger

Overview

What does this guide cover?

This guide will demonstrate how to install and run Ruby, Ruby on Rails, and Phusion Passenger on a cPanel server running CentOS.

Benefits

The tools provided by cPanel to manage Ruby on Rails apps are not yet compatible with Rails 3. Passenger helps solve this problem because it is able to serve both Rails 2 and 3 apps out of the box. Configuration is relatively since Passenger does not require the use of rewrites to map sites to a high-numbered port (unlike the configuration described in this article, cPanel assigns each rails app to a mongrel server process that runs on a port greater than 12000). In its simplest form, a Passenger-enabled site only requires that the “DocumentRoot” variable be changed inside its VirtualHost entry.

Caveats

When using passenger, the rails utility in cPanel must be abandoned as it will no longer function correctly. Starting and stopping apps running under passenger is performed in a way that is incompatible with this utility and the ‘Manage Rewrites’ section of the cPanel rails utility is rendered unnecessary since passenger does not require mapping apps to specific ports. Also, if Rails 3 is installed, the “create app” functionality will no longer work. Therefore, it is highly recommended that the “Ruby on Rails” utility be completely disabled server-wide.

Steps covered in this guide

  1. Install ruby
  2. Install passenger
  3. Enable passenger module in apache
  4. Customize rails app to work with passenger

Assumptions

This guide assumes that you are familiar with linux and are comfortable working on the command line.

Supplemental resources

This guide contains all the required information for installing Ruby, Ruby on Rails and Phusion Passenger, but the following resources are directly related and may prove to be helpful.

Passenger user guide for use with apache

http://www.modrails.com/documentation/Users%20guide%20Apache.html

cPanel documentation

Changes within VirtualHost directive

http://docs.cpanel.net/twiki/bin/view/EasyApache3/InsideVHost

Installing Ruby and Ruby on Rails

http://docs.cpanel.net/twiki/bin/view/AllDocumentation/RubyonRails/InstallingRuby

Procedure

Step 1: Install Ruby on Rails

Run installation script provided by cPanel (installs ruby 1.8.7, see below for installing other versions of ruby with RVM)

cPanel provides a script that will first install ruby on the server. This script will then install the necessary ruby gems (modules) that are necessary to get rails apps working. Type the following command to run this script:

/scripts/installruby

This script installs ruby 1.8.7, rails 2.3.x and related gems.

Alternative: Install a different version of ruby using RVM

cPanel installs ruby 1.8.7. However, it is possible to install a different version of ruby. The best way to do this is probably to use Ruby Version Manager (RVM), which allows you to install additional versions of ruby without interfering with the server’s main installation. Therefore, you can install ruby using cPanel’s script as described above and later install another version of ruby using rvm without fear of overwriting anything. See this article for more details about Installing rubies using rvm.

Step 2: Install Phusion Passenger

Install passenger gem

After ruby is installed, you can install the passenger gem easily. As root, run the following command:

gem install passenger

Compile and install mod_passenger

In order for rails apps to be served by apache, the passenger module must be compiled and installed.

Just to be extra sure that passenger will be able to find the path to apache’s apxs tool (which is used to compile apache modules from source), you should explicitly define the APXS2 environment variable. cPanel’s version of apache installs this binary to /usr/local/apache/bin/apxs, so you would set the APXS2 variable like so:

export APXS2=/usr/local/apache/bin/apxs

Next, run the following command to build and install the module (the exact path may differ slightly depending on the version of passenger that was installed):

/usr/lib/ruby/gems/1.8/gems/passenger-3.0.15/bin/passenger-install-apache2-module

The above command will build and install mod_passenger. After the process has finished, you should see some instructions that look something like the following:

——————————————–
The Apache 2 module was successfully installed.
Please edit your Apache configuration file, and add these lines:
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.15/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.15
PassengerRuby /usr/bin/ruby

You will need the configuration directives that are printed out for you in the next step.

Step 3: Enable passenger module in apache

Place configuration options in cPanel-provided include file

Before it will work, the passenger module must be enabled in your apache configuration. This simply consists of copying the directives printed out for you in step 2 and pasting them into the appropriate apache configuration file. However, you cannot simply modify the main httpd.conf file located at /usr/local/apache/conf/httpd.conf because cPanel regularly rebuilds this file and your modifications will be lost. Instead, you should add the directives to the appropriate include files that cPanel provides, which are automatically included into the master configuration file.

In this case, the file that you want to use is /usr/local/apache/conf/includes/pre_main_2.conf. Open the file in an editor and add the following lines:

LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.15/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.15
PassengerRuby /usr/bin/ruby

Save the file and restart apache like so…

/scripts/restartsrv_httpd

…and the passenger directives will be loaded into your apache configuration, thus enabling apache to serve rails apps.

Step 4: Customize rails app to work with passenger

Create custom include file for domain

The path to your rails apps are almost certainly going to be somewhere other than the default document root that is configured automatically by cPanel. Therefore, for each domain that corresponds to a rails app, it is necessary to override the DocumentRoot directive inside its VirtualHost block. Again, it is not possible to make permanent changes simply by editing /usr/local/apache/conf/httpd.conf, since these will be overwritten the next time the apache configuration file is rebuilt. The correct way to override directives inside a site’s VirtualHost block is to use custom include files. In addition to following this guide, I encourage you to read through cPanel’s online documentation on this subject. This will help you understand the different ways that your sites’ VirtualHost configurations can be modified:

http://docs.cpanel.net/twiki/bin/view/EasyApache3/InsideVHost

For the domain, “shoemaker.com”, belonging to cPanel user, “cobbler”, you would want to create the following file:

/usr/local/apache/conf/userdata/std/2/cobbler/shoemaker.com/rails.conf

Note that the file can be called anything as long as it ends in “.conf”. I have chosen “rails.conf” indicating that these custom configurations are specific to rails.

Also note that you will probably need to create the path to this file because it does not exist by default. Therefore, the commands you would need to run are the following:

mkdir -p /usr/local/apache/conf/userdata/std/cobbler/shoemaker.com
nano /rails.conf

You should then point the document root of this site to your rails apps’ “/public” directory. By default, cPanel creates rails apps in /home/<user>/rails_apps. Even though this app will not be under cPanel’s control, it is still ok to place it there. So, an app named “shoemakerapp” located in the rails_apps directory would have the following DocumentRoot line:

DocumentRoot /home/cobbler/rails_apps/shoemakerapp/public

You can also use this .conf file if you need any other custom configurations for the rails site. This might be necessary for several reasons, such as if you need to override some directives. For example, if you enabled MultiViews somewhere, you would want to turn them off since they are not compatible with rails apps.

<Directory /home/cobbler/rails_apps/shoemakerapp/public>
Options -MultiViews # <– MultiViews must be turned off
</Directory>

Include custom settings in httpd.conf

The last action that must be taken is to rebuild the main apache configuration file. This is necessary in order to detect the new custom config file that you have just created. cPanel’s “rebuildhttpdconf” script will add the necessary “Include” lines inside the VirtualHost block. Just run the following commands to backup your current httpd.conf file and rebuild it:

cp -av /usr/local/apache/conf/httpd.conf /usr/local/apache/conf/httpd.conf.backup
/scripts/rebuildhttpdconf

Finally, to apply the new configuration, restart apache:

/scripts/restartsrv_httpd

Your rails application should now be up and running!

Tips

The following are a few things to keep in mind while running passenger.

Restart a rails app

When you restart your app under cPanel’s default rails configuration you do so by restarting the mongrel process that is serving your app. Conversely, you restart an app under passenger simply by updating the timestamp of a touch file named “restart.txt” in the app’s /tmp directory like so:

touch /home/cobbler/rails_apps/shoemakerapp/tmp/restart.txt

Upon seeing that the timestamp of restart.txt has been changed, passenger will restart the app on the next request.

CentOS + RVM

CentOS + RVM

Problem: You would like to run multiple versions of ruby

Solution: Use Ruby Version Manager (RVM) to install and manage multiple ruby versions without clobbering the system version of ruby.

Prerequisites

  • git
  • autoconf
  • automake
  • libtool
  • readline and readline-devel

Step 1: Install prerequisites

Install git

CentOS 6.x

In CentOS 6, git is included in the base repository so it can be installed with “yum install git”. Note that on a cPanel server this command will likely fail due to the fact that cPanel has modified the yum configuration file (/etc/yum.conf) to exclude some packages; in this case some perl packages. Therefore, you must explicitly disable the excludes from /etc/yum.conf with the “disableexcludes” option. Thus, the command becomes:

CentOS 5.x

In CentOS 5, you can install git from a non-standard repository or install from source. I chose to install from the epel repository. Caution if you are running a cPanel server! The use of third-party repositories such as epel can create package conflicts and potentially interfere with cPanel. The epel repository can be added to your list of yum repos by installing the rpm from fedora.org. At the time of writing, the base directory for CentOS 5 was located at http://dl.fedoraproject.org/pub/epel/5/. Be sure to choose the subdirectory that corresponds to the architecture of your server. For example, to install the rpm for 64-bit systems you would run the following command:

Once you have added the epel repository, you will be able to install git with the following command:

Note the “disableexcludes” option. See the related notes under the CentOS 6.x heading above for an explanation as to why this is necessary.

(CentOS 5.x only) Reinstall autoconf, automake, and libtool

The package autoconf and its dependencies automake and libtool must be uninstalled and then reinstalled from source because git requires autoconf 2.6+ while CentOS 5.x packages autoconf 2.59.

Install readline and readline-devel

Readline and its development libraries are packages that can be installed with yum. These are required for building certain ruby binaries such as Ruby Enterprise Edition. The following command will install both of these packages:

Uninstall autoconf, automake and libtool

Remove these three packages with yum like so:

Reinstall autoconf from source

Reinstall automake from source

Reinstall libtool from source

Step 2: Install rvm (server-wide)

Reference: https://rvm.io/rvm/install/

Important: The following instructions will install rvm server-wide. All commands must be run as root. Additionally, it is required that you include “sudo” as it appears in the following command to ensure that rvm is properly installed. Even if you are logged in as root, omitting “sudo” will cause rvm to install incorrectly (it will actually install just for the root user and rvm will end up getting installed into /root/.rvm instead of /usr/local/rvm).

Run the following command as root to install rvm globally:

If you run into any certificate errors when attempting to run the installation script, you will need to configure curl to ignore certificate warnings. I achieved this by running the following command…

…and then retrying the installation:

Step 3: Install a ruby

To install a version of Ruby, you use “rvm install RUBY_NAME”. For example, to install ruby 1.9.3 with patch level 194, you would run:

Rubies installed by rvm can be found under the following directory:

More information about installing rubies can be found in the official documentation:

https://rvm.io/rvm/install/

Tips

The following commands demonstrate some common commands that you will want to know:

View a list of available rubies

Install a ruby

Switch back to using the system’s version of ruby

Use a specific version of ruby installed by rvm

Set default ruby

Update rvm

…or, for the bleeding edge version…

Access cPanel Services with Valid Certificate

Problem

Your objective is to get cPanel services (webmail, cPanel, and WHM) to be accessible via HTTPS for domains that have a dedicated IP address and a valid certificate. The goal is for these selected domains to work via a URL like so…

https://webmail.domain.tld/

…instead of a URL with a port number appended like this one…

https://webmail.domain.tld:2096/

…which has the undesired effect of using the server-wide certificate instead of the one installed for this domain.

Note that there is some proxy magic built into cPanel that is designed to solve this problem, but it does not provide the level of granularity that is often needed. Specifically, it does not allow you to apply this functionality to just those domains with valid certificates.

This document will describe how to override cPanel’s settings on a per-domain basis so that users will be taken to an HTTPS URL bearing a valid certificate for the domain. All domains that have not been explicitly targeted will remain unaffected.

Technical details

Certificates installed for users’ domains are handled by apache and are installed in…

WHM >> Install a Certificate and Setup the Domain

However, cPanel services are handled by the daemon “cpsrvd”, not apache. Instead of using the certificates installed via the above utility, cpsrvd uses a server-wide certificate that is installed in…

WHM >> Manage Service SSL Certificates >> cPanel/WHM/Webmail Service

You might think that you could simply use the following URLs to access these services:

https://cpanel.domain.tld/
https://webmail.domain.tld/
https://whm.domain.tld/

However, the above URLs do not automatically work because no mechanism exists for globally connecting SSL sites to cPanel services. Instead, these services must be accessed via their respective port numbers that cpsrvd listens on like so:

https://domain.tld:2083/   or   https://hostname:2083/
https://domain.tld:2096/   or   https://hostname:2096/
https://domain.tld:2087/   or   https://hostname:2087/

(actually, any domain that resolves to the server will work so long as the correct port is appended to the URL)

Unfortunately, when accessing sites with the domain name and port number, you will likely encounter certificate warnings because the server-wide certificate is not usually valid for a user’s domain. cPanel offers two less than ideal ways to resolve this:

Unsatisfactory way #1

Configure cPanel to forward all cPanel services to the URL that is on the server-wide certificate (this is the default behavior). Assuming that the server-wide certificate is valid for the hostname, users will be redirected to URLs that look like the following:

https://hostname:2083/ (cpanel)
https://hostname:2096/ (webmail)
https://hostname:2087/ (whm)

This prevents certificate warnings if the server-wide certificate is valid, but it causes the URL that appears in the address bar to change to something unexpected.

Unsatisfactory way #2

Purchase a server-wide certificate that is good for multiple domains and add each required “subdomain.domain.tld” to the server-wide certificate. Then, configure cPanel to redirect to the “origin domain name” so that the final URLs look like this:

https://cpanel.domain.tld:2083/
https://webmail.domain.tld:2096/
https://whm.domain.tld:2087/

Note that in this case the certificate will be valid, but the port number will still be appended. This is also problematic because it puts the burden of maintenance and cost on the administrator instead of the end user.

Solution

A workaround can be implemented using a combination of custom redirects and mod_proxy.

Note that cPanel already provides this mechanism, which works consistently for non-secure URLs. As described at the beginning of this document, this mechanism is inconsistent when using secure URLs.

The “cPanel way” is to enable “proxy subdomains” in WHM >> Tweak Settings, which will connect port-less URLs to their corresponding cPanel services like so (the URL on the left is retained in the browser’s address bar):

http://cpanel.domain.tld/ =PROXY=> http://127.0.0.1:2082/
http://webmail.domain.tld/ =PROXY=> http://127.0.0.1:2095/
http://whm.domain.tld/ =PROXY=> http://127.0.0.1:2086/

https://cpanel.domain.tld/ =PROXY=> http://127.0.0.1:2083/
https://webmail.domain.tld/ =PROXY=> http://127.0.0.1:2096/
https://whm.domain.tld/ =PROXY=> http://127.0.0.1:2087/

As previously explained, this feature does not work reliably for HTTPS URLs. The solution to this problem has two parts. The first part is to use mod_proxy to provide the necessary connection between apache and cpsrvd. The second part is to override cPanel’s default behavior of redirecting to https://service.domain.tld:port/ and instead redirect to the regular HTTPS URL https://service.domain.tld/.

Prerequisites

Mod_proxy

If not installed, you can enable mod_proxy via EasyApache

Dedicated IP address

Each domain for which you implement this workaround must have a dedicated IP address. This is not just an arbitrary policy but a technical limitation based on how SSL sites work. You can get it to work on the shared IP address, but in this case it will only work for one domain!

Certificate

There are three different types of certificates that you can install, arranged in order of preference:

Multiple-domain certificate

A certificate that is valid for multiple domains is ideal so that it will be valid for both the main domain and the subdomains. This prevents you from having to dedicate an IP address for the main domain and another one for all its subdomains.

Wildcard subdomain certificate

A wildcard subdomain certificate would validate each of the cPanel service subdomains, but would not cover the main domain. cPanel does not technically support wildcard certificates, but these instructions show how you can get them to work:

Single-domain certificate

A certificate that is valid for only one of the subdomains can be installed to get this working for just that subdomain and its corresponding service.

Steps

Step 1: Configure apache to respond to the cPanel service subdomains

This step is necessary to be able to implement custom redirection on a per-domain basis, as described in later steps.

First, you should enable “Proxy subdomain override” in WHM >> Tweak Settings. Otherwise you will receive an error when attempting to create the subdomains in the cPanel interface.

Next, you will need to ensure that each subdomain does not already have a corresponding DNS record. Simply delete any of the following records if they currently exist in the domain’s DNS zone:

cpanel 14400 IN A IP_ADDRESS
webdisk 14400 IN A IP_ADDRESS
webmail 14400 IN A IP_ADDRESS
whm 14400 IN A IP_ADDRESS

Lastly, you will need to use the cPanel interface to add the cPanel service subdomains. The best way to accomplish this would be to park these subdomains to the main domain using cPanel >> Parked Domains. However, cPanel disallows adding these as parked domains this even if “Proxy subdomain override” is enabled in Tweak Settings. You will instead have to add them using the cPanel >> Subdomains utility.

Step 2: Ensure that a certificate is installed for the domain

For a certificate to work for the both the main domain and all of its subdomains, it must be a multiple-domain certificate (see the section Prerequisites->Certificates above for more information about the types of certificates that you might install).

Note that, since only one certificate can be installed per IP address, all URLs that resolve to a particular IP address will be presented with whichever certificate is installed for that IP address irrespective of the host name requested by the website visitor. This is because apache is ignorant of the host name that the visitor seeks until after a secure connection has been established. Before accepting the certificate, the only things apache knows about are the IP address and port number being requested.

Step 3: Override cPanel’s default redirection

cPanel’s default redirects are controlled by CGI scripts. The corresponding lines appear near the top of httpd.conf and look like the following:

ScriptAliasMatch ^/?cpanel/?$ /usr/local/cpanel/cgi-sys/redirect.cgi
ScriptAliasMatch ^/?webmail/?$ /usr/local/cpanel/cgi-sys/wredirect.cgi
ScriptAliasMatch ^/?whm/?$ /usr/local/cpanel/cgi-sys/whmredirect.cgi

The configuration changes described below use mod_rewrite’s “RewriteRule” directive to redirect website visitors to the port-less HTTPS URL before the above ScriptAliasMatch directives come into play. This ensures that apache can present the correct certificate to the visitor.

The first step is to create an include file which contains the apache directives that will override cPanel’s default redirection:

vi /usr/local/apache/conf/includes/redirect_to_ssl_subdomain.conf

The contents of this file should be as follows:

RewriteEngine on
# Redirect /service to service.domain.tld
RewriteRule ^/cpanel$ https://cpanel.%{HTTP_HOST}/ [R=301,L]
RewriteRule ^/webmail$ https://webmail.%{HTTP_HOST}/ [R=301,L]
RewriteRule ^/whm$ https://whm.%{HTTP_HOST}/ [R=301,L]
# Redirect non-ssl service subdomains to ssl url
RewriteCond %{HTTP_HOST} ^cpanel.*
RewriteRule ^.*$ https://%{HTTP_HOST}/ [R=301,L]
RewriteCond %{HTTP_HOST} ^webmail.*
RewriteRule ^.*$ https://%{HTTP_HOST}/ [R=301,L]
RewriteCond %{HTTP_HOST} ^whm.*
RewriteRule ^.*$ https://%{HTTP_HOST}/ [R=301,L]

Next, include this file into the VirtualHosts of the corresponding user. Create the following directory and file, replacing $user with the actual username:

mkdir -p /usr/local/apache/conf/userdata/std/2/$user/
vi /usr/local/apache/conf/userdata/std/2/$user/redirection.conf

The contents of this file should be as follows:

Include /usr/local/apache/conf/includes/redirect_to_ssl_subdomain.conf

Note that this technique of modifying a site’s VirtualHost directive is described in fuller detail in cPanel’s online documentation

Step 4: Connect the HTTPS site to the cPanel service

This step enables a reverse proxy to connect the HTTPS site served by apache to the cPanel service served by cpsrvd.

First, create the following include file containing the necessary directives:

vi /usr/local/apache/conf/includes/proxy_cpanel_services.conf

The contents of this file should be as follows:

RewriteEngine on
<IfModule core.c>
    SSLProxyEngine On
</IfModule>
RewriteCond %{HTTP_HOST} ^cpanel\.
RewriteRule ^/(.*) https://127.0.0.1:2083/$1 [P]
RewriteCond %{HTTP_HOST} ^webmail\.
RewriteRule ^/(.*) https://127.0.0.1:2096/$1 [P]
RewriteCond %{HTTP_HOST} ^whm\.
RewriteRule ^/(.*) https://127.0.0.1:2087/$1 [P]
RewriteCond %{HTTP_HOST} ^webdisk\.
RewriteRule ^/(.*) https://127.0.0.1:2078/$1 [P]

Then, create the following directory and file to include the proxy directives into the SSL VirtualHost:

mkdir -p /usr/local/apache/conf/userdata/ssl/2/dar
vi /usr/local/apache/conf/userdata/ssl/2/dar/proxy.conf

The contents of this file should be as follows:

Include /usr/local/apache/conf/includes/proxy_cpanel_services.conf

Step 5: Rebuild apache configuration

Run the following command to rebuild httpd.conf. This causes the custom VirtualHost overrides that were created in the previous step to be included at the right places with httpd.conf:

/scripts/rebuildhttpdconf

Step 6: Restart apache

For your changes to be applied, it is necessary to restart apache, which can be done with the following command:

/scripts/restartsrv_httpd

Your users will now be able to access all cPanel services via the corresponding subdomain and have each of them verified by the domain’s certificate. Also, the non-SSL URLs will redirect to the SSL URLs like so (this is something that the default cPanel configuration does not do)…

http://webmail.domain.tld/ => https://webmail.domain.tld/
http://cpanel.domain.tld/ => https://cpanel.domain.tld/
http://whm.domain.tld/ => https://whm.domain.tld/

…and the http://domain.tld/service shortcuts will likewise redirect to the SSL URL like so:

http://domain.tld/webmail => https://webmail.domain.tld/
http://domain.tld/cpanel => https://cpanel.domain.tld/
http://domain.tld/whm => https://whm.domain.tld/

Important Note

The redirects configured in these instructions are permanent 301 redirects. This will cause the final destination to be cached by your browser. If you make any changes to the redirection while testing, be very sure to delete your browser’s cache every time. Otherwise, the redirection that you observe happening may be due to your browser’s cache instead of from the apache configuration.

Global Settings

For those domains that are not on dedicated IPs and do not have their own SSL certificate, I recommend configuring cPanel to redirect their services to the server-wide certificate that is configured in WHM >> Manage Service SSL Certificates. This is accomplished by setting the following configuration options in Tweak Settings:

Proxy subdomains – On
Proxy subdomain creation – On
Require SSL – On
Always redirect to SSL – On
SSL redirect destination – SSL Certificate Name