08.21.2019

How to deploy Ruby app on Centos 7 using Phusion Passenger

On this page you will learn how you can deploy your app to a server that is running Passenger. You can either follow these instructions with your own app.

Transferring the app code to the server

Push your code to a Git repository

You want to transfer our application's code to the server. The easiest way to do that is via Git.
If you have already setup a Git repository, push your application's code to that repository by running this on your local computer:
git push

Login to your server, create a user for the app

Login to your server with SSH:
ssh root@your_server_ip
Now that you have logged in, you should create an operating system user account for your app. For security reasons, it is a good idea to run each app under its own user account, in order to limit the damage that security vulnerabilities in the app can do. Passenger will automatically run your app under this user account
Create new user. 
useradd myuser
passwd myuser

We also ensure that that user has your SSH key installed:
mkdir -p ~myuser/.ssh
sh -c "cat $HOME/.ssh/authorized_keys >> ~myuser/.ssh/authorized_keys"
chown -R myuser: ~myuser/.ssh
chmod 700 ~myuser/.ssh
sh -c "chmod 600 ~myuser/.ssh/*"

Install Git on the server

yum install -y git

Pull code

You need to pick a location in which to permanently store your application's code. A good location is /var/www/vhosts/APP_NAME. Let us create that directory.
mkdir -p /var/www/vhosts/myapp
chown myappuser: /var/www/vhosts/myapp

Replace myapp and myuser with your app's name and your app user account's name.
Now let us pull the code from Git:
cd /var/www/vhosts/myapp
sudo -u myuser -H git clone git://github.com/username/myapp.git source

Preparing the app's environment

Login as the app's user

All subsequent instructions must be run under the application's user account. While logged into your server, login under the application's user account as follows:
sudo -u myappuser -H bash -l

Install app dependencies

Your application has various dependencies. They must be installed. Most of these dependencies are gems in your Gemfile, managed by Bundler. You can install them by running bundle install --deployment --without development test -j 2 in your app's directory:
cd /var/www/vhosts/myapp/source
bundle install --deployment --without development test

Your app may also depend on services, such as MySQL, PostgreSQL, MongoDB, Redis, etc. Installing services that your app depends on is outside of this walkthrough's scope.

Configure database.yml or mongo.ymt and secrets.yml

Since your Rails app probably needs a database, you need to edit config/database.yml. For demonstration purposes, we will setup your app with an SQLite database because that is the easiest.
Open file:
vim config/database.yml
If you use sqlite, ensure that the production section looks like this:
production:
  adapter: sqlite3
  database: db/production.sqlite3

Rails also needs a unique secret key with which to encrypt its sessions. Starting from Rails 4, this secret key is stored in config/secrets.yml. But first, we need to generate a secret key. Run:
bundle exec rake secret
This command will output a secret key. Copy that value to your clipboard. Next, open config/secrets.yml:
vim config/secrets.yml
If the file already exists, look for this:
production:
  secret_key_base: <%=ENV["SECRET_KEY_BASE"]%>

Then replace it with the following. If the file didn't already exist, simply insert the following.
production:
  secret_key_base: the value that you copied from 'rake secret'

To prevent other users on the system from reading sensitive information belonging to your app, let's tighten the security on the configuration directory and the database directory:
chmod 700 config db
chmod 600 config/database.yml config/secrets.yml config/mongo.yml

Compile Rails assets and run database migrations

Run the following command to compile assets for the Rails asset pipeline, and to run database migrations:
If you use mysql or sqlite...etc
bundle exec rake assets:precompile db:migrate RAILS_ENV=production
If you use mongodb with mongomapper
bundle exec rake assets:precompile RAILS_ENV=production

Configuring Apache and Passenger

Now that you are done with transferring your app's code to the server and setting up an environment for your app, it is time to configure Apache so that Passenger knows how to serve your app.

Determine the Ruby command that Passenger should use

We need to tell Passenger which Ruby command it should use to run your app, just in case there are multiple Ruby interpreters on your system. Please run passenger-config about ruby-command to find out which Ruby interpreter you are using. For example:
$ passenger-config about ruby-command
passenger-config was invoked through the following Ruby interpreter:
  Command: /usr/bin/ruby
  Version: ruby 2.2.3p85 (2015-02-26 revision 49769) [x86_64-linux]
  ...

Please take note of the path after "Command" (in this example, /usr/bin/ruby). You will need it in one of the next steps.

Go back to the admin account

You have previously logged into your app's user account in order to prepare the app's environment. That user does not have sudo access. In the next steps, you need to edit configuration files, for which sudo access is needed. So you need to switch back to the admin account.

This can be done by simply exiting the shell that was logged into the app's user account. You will then be dropped back to the admin account. For example:
# This is what you previously ran:
root$ sudo -u myuser -H bash -l
myuser$ ...

# Type `exit` to go back to the account you were before
myuser$ exit
root$ _

Edit Server configuration file

We need to create an Apache configuration file and setup a virtual host entry that points to your app. This virtual host entry tells Apache (and Passenger) where your app is located.
If you use Apache
vim /etc/httpd/conf.d/myapp.conf
Replace myapp with your app's name.
Put this inside the file:
<VirtualHost *:80>
    ServerName yourserver.com

    # Tell Apache and Passenger where your app's 'public' directory is
    DocumentRoot /var/www/vhosts/myapp/source/public

    PassengerRuby /path-to-ruby

    # Relax Apache security settings
    <Directory /var/www/vhosts/myapp/source/public>
      Allow from all
      Options -MultiViews
      # Uncomment this if you're on Apache >= 2.4:
      #Require all granted
    </Directory>
</VirtualHost>

If you use Nginx
vim /etc/nginx/sites-enabled/myapp.conf
Put this inside the file:
server {
    listen 80;
    server_name yourserver.com;

    # Tell Nginx and Passenger where your app's 'public' directory is
    root /var/www/vhosts/myapp/source/public;

    # Turn on Passenger
    passenger_enabled on;
    passenger_ruby /path-to-ruby;
}


Replace yourserver.com with your server's host name, and replace /var/www/vhosts/myapp/source with your application's code directory path. However, make sure that Apache is configured to point to the public subdirectory inside it!

Replace /path-to-ruby with the Ruby command that you obtained in last step.
When you are done, restart Apache:
apachectl restart
Or Nginx
systemctl nginx restart
You should now be able to access your app through the server's host name! Try running this from your local computer. Replace yourserver.com with your server's hostname, exactly as it appears in the Apache config file's ServerName directive.
 

Leave a comment