ruby-on-rails

Rails: Capistrano + Puma + Nginx on VPS

Follow me
Follow me

Latest posts by Tomasz Antas (see all)

Apr 30, 2015

Article presents how to set up the development and production enviroments for Rails applications with Puma, Nginx and Capistrano.

 

 

Used versions:

  • Ubuntu 14.10
  • Ruby 2.2.1
  • Rails 4.2.0
  • Nginx 1.6.2
  • Puma 2.11.2
  • Capistrano 3.4.0

 

Introduction

Let’s assume that we have some simple app already without bugs.

Puma is a ruby server for Rails applications. It can work as standalone server, but also can work togheter with Nginx HTTP server. The idea of Nginx and Puma cooperation is that the Nginx collects the requests from users and is streaming them to Puma server with Rails application.

capistrano_nginx_puma_draw_1

The communication between Nginx and Puma server is done via sockets. Nginx creates socket and Puma connects to this socket.

 

capistrano_nginx_puma_draw_2

 

To do this, we need run Puma server with the location of this socket or define it in configuration file. The second thing is that we have to create configuration file for Nginx where we also define this socket location.

 

The Capistrano allows to deploy easily the Rails app to other servers and run this app on target in specified mode (e.g. production). For the very first time, we need to set up few things and configuration files on each server. Then we can deploy it with single command from terminal. Capistrano allows to create and run own task, like running custom scripts after deploy, what allows to speed-up deploying application, especielly if we want deploy applications on many servers.

 

Puma server

Edit Gemfile and add:

Next, run bundler:

And run your app, but this time on puma server:

You should be able to play with your app in browser without any problems.

 

Nginx installation

Install nginx:

Nginx service can be started and stopped:

Nginx version:

Now you can run nginx and open browser. You should see something similar to this:

 

nginx_browser

 

 Nginx configuration

Disable default site (“Welcome to nginx!”) by removing symlink:

After nginx restart,  “Welcome to nginx!” site should be visible in browser now.

Let’s create a new nginx config file for puma server: /etc/nginx/sites-available/my_app.conf

As you can see, the configuration was created in “sites-available” directory. Now you need to create symlink to this configuration in directory “sites-enabled”:

Restart Nginx:

If you change something in nginx configuration file and it doesn’t work, you can test the configuration file:

You can run the Rails app on puma server. Do you remeber how we bind Rails app before to 127.0.0.1 address? Now we use the nginx socket instead of tcp address:

 

Puma configuration

Firstly, create in your app puma configuration file config/puma.rb:

Puma can use a Jungle Upstart tool, which allows to easily start, stop and restart Puma servers. Whatsmore, it starts the Puma servers on system boot. Get the Jungle Upstart from GitHub repository:

Edit downloaded puma.conf and change:

  • setuid – to the deployment user name
  • setgid – to the deployment group name

For example:

Copy scripts to /etc/init:

The puma-manager.conf runs the puma servers listed in another file, which we have to create. Create /etc/puma.conf file and add there the path to your application:

If you want use more apps, you can add another paths in next lines. From now, your app with Puma server will be started after each server reboot.

You can check if the puma server is running with following command:

You can also start, stop and restart puma apps manually:

 

 

Capistrano

Add to Gemfile:

Run:

And then generate capistrano configuration:

Last command creates a few files. Edit Capfile and add:

To check rbenv_ruby, use following command:

Next thing is to configure the config/deploy.rb file. Change application name and repo_url:

The last file, which we have to edit is config/deploy/production.rb:

 

Now we can try to deploy our app to production server:

Below are listed some errors:

 

Problem with connecting to repository on remote

If you get error, that “Permission denied (publickey)”, maybe you need a ssh key to your repository. But if you still havew some problems, you can use forward agent. Add to config/deploy.rb:

(or if you defined it in other file, change it also).

Run ssh-agent and add key to agent on your development machine:

” ssh-add -L”  should display added keys.

Check the /etc/ssh/ssh_config file on development machine (local machine):

Check the /etc/ssh/sshd_config file on production machine (remote machine):

Now everything should works fine.

 

“ERROR: linked file XXX does not exist”

It happens, because Capistrano cannot find this file on remote machine. Under XXX in error is the path to the file. Probably, Capistrano will be looking for 2 files (it depends what we define in config/deploy.rb): database.yml and secrets.yml. Move this file manually to the path pointed by XXX.

 

Bundle error on remote machine

If you deploy the app on production server, you have to be sure that a right ruby version is installed. Firstly, check available versions:

Be sure that * is beside the right version. If not, you can change it by:

Instead of “global”, you can use “local” in depends on used settings.

Next thing is the bundler installation (without rdoc to save the time):

Now the bundle error should be resolved.

 

Set up production server

Actually, this step should be done before deploying the app via Capistrano to production server. Probably some of this things you have done before and below is a list with the main things which should be done:

  • Ruby and Rails installation (don’t forget about bundler),
  • Database installation – install right database and set up the users and privileges,
  • Nginx – add nginx configuration file which will create socket for Puma server,
  • Set production environment in config/puma.rb:
  • Puma manager – tool to manage (starting, stoping and restaring) Puma server. You can add this like in the Puma configuration chapter:
    Change setuid and setgid. Copy modified puma.conf and puma-manager.conf to /etc/init:
    Create /etc/puma.conf containing the path to your app (don’t forget about current subdirectory):
    Now you can:
     

 

Check deploy results

After deploy, we should check few things on remote server that everything works fine:

  • Puma server is running:
    Be sure that the socket address is right.
  • Check that socket is created:
  • Verify that nginx has proper configuration file or add it now.
    To add configuration file, we can copy it from development machine (/etc/nginx/sites-available/my_app.conf) and modify root and server_name:
    Next thing is create symlink to this file in /etc/nginx/sites-enabled:
    The last thing is to restart nginx service:
  • Visit your app in browser
    Use IP address or domain of your production server and visit it in browser. You should see your application (if everything is OK), but probably you can see some error, like this one:

    An unhandled lowlevel error occured. The application logs may have details.

    If something is wrong, you need to investigate log files. See next point.

  • Check log files
    There few log files, which we can investigate in depends what is wrong. Log files are stored on production server in path defined in Capistrano settings. For example under /var/www/my_app/current. “Current” is a symlink to last release deployed via Capistrano. Log file can be found /my_app/current/log.

 

 Common problems

Application in production stage may use different settings and keys than development application. And the lack of defined settings or keys for production stage is one of the common problems during deploying app.

Check each log file to collect information. If some key is missing, the error should be prompted in log/puma.access.log. 

 

Missing “secret_key_base” and/or “secret_token”

Rack app error: #<RuntimeError: Missing secret_token and secret_key_base for ‘production’ environment, set these values in config/secrets.yml>

Go to directory of your app and generate new key:

Copy key and paste in config/secrets.yml:

Now restart the puma server.

 

Mysql2: Access denied for user ‘XXX’@’XXX’

If you didn’t set up user and his privileges in database before, you should get this error.

Firstly, we create database manually as root user. Edit config/database.yml and add username: root and proper password for root:

Go to you app directory and run db:create:

Login to mysql as a root:

Check if database was created:

Add new user and give privileges:

Go back to config/database.yml and change username and password:

Now run db:migrate:

The error should be fixed.

 

Tomasz AntasRails: Capistrano + Puma + Nginx on VPS
  • zullcore

    About error “Missing “secret_key_base” and/or “secret_token””, best way is using export in bash.
    more details: http://stackoverflow.com/a/26172408/868003

  • Marek

    sudo start puma-manager
    sudo: start: command not found

    Help. :(

    • Tweets from Wolfie

      capistrano-puma commands (that you can run on your local machine to affect the server):
      cap production puma:status
      cap production puma:start
      cap production puma:stop
      cap production puma:restart