Ruby on Rails Vagrant Unicorn Nginx Mysql

# Ruby on Rails Unicorn Nginx で環境構築

## Overview 

Ruby on Railsをnginx で動作させたく、Unicornを使ってやってみました。
Nginxをリバースプロキシにして、Unicornで受けて、Ruby on Railsというフローから、
Ruby on Rails -> Unicorn -> Nginx というフロー的な感じです。

Ruby version: 2.3.3
Rails version: 5.0.6
nginx version: 1.12.2
mysql version: 5.1.7

## Vagrantfile

```
# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "bento/centos-6.9"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  config.vm.network "forwarded_port", guest: 80, host: 1234

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  config.vm.synced_folder "./html", "/usr/share/nginx/html"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end

```

### Nginx conf 

```
upstream unicorn_server {
    # This is the socket we configured in unicorn.rb
    server unix:/tmp/unicorn.sock
    fail_timeout=0;
}

server {
    listen 80;
    client_max_body_size 4G;
    server_name _;

    keepalive_timeout 5;

    # Location of our static files
    root /usr/share/nginx/html;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;

        # If you don't find the filename in the static files
        # Then request it from the unicorn server
        if (!-f $request_filename) {
            proxy_pass http://unicorn_server;
            break;
        }
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /usr/share/nginx/html;
    }
}

```

```
->> sudo service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]
```

### Gemfile 編集

```
source 'https://rubygems.org'

git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.0.6'
# Use mysql as the database for Active Record
gem 'mysql2', '>= 0.3.18', '< 0.5'
# Use Puma as the app server
gem 'puma', '~> 3.0'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# See https://github.com/rails/execjs#readme for more supported runtimes
gem 'therubyracer', platforms: :ruby

# Use unicorn as the app server
gem 'unicorn'

# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platform: :mri
end

group :development do
  # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '~> 3.0.5'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

```

```
bundle install --path vendor/bundle
```

### Rails project unicorn.rb 

```
@app_path = '/usr/share/nginx/html'

worker_processes 2
working_directory "#{@app_path}/"

# This loads the application in the master process before forking
# worker processes
# Read more about it here:
# http://unicorn.bogomips.org/Unicorn/Configurator.html
preload_app true

timeout 30

# This is where we specify the socket.
# We will point the upstream Nginx module to this socket later on
listen "/tmp/unicorn.sock", :backlog => 64

pid "/tmp/unicorn.pid"

# Set the path of the log files inside the log folder of the testapp
stderr_path "#{@app_path}/log/unicorn.stderr.log"
stdout_path "#{@app_path}/log/unicorn.stdout.log"

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

  old_pid = "#{server.config[:pid]}.oldbin"
    if old_pid != server.pid
      begin
        sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
        Process.kill(sig, File.read(old_pid).to_i)
      rescue Errno::ENOENT, Errno::ESRCH
      end
    end

    sleep 1
  end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

```

### Unicorn 起動
```
bundle exec unicorn_rails -c config/unicorn.rb -E development -D
```

vagrant 環境下にてport は1234にしましたので

http://localhost:1234

で表示されました。


### Unicorn 起動で下記エラー発生

```
->> bundle exec unicorn_rails -c config/unicorn.rb -E development -D
master failed to start, check stderr log for details
```

このような場合は言われた通りにしましょう。

```
vi ./log/unicorn.stderr.log 
```

```
I, [2018-01-17T23:20:05.406296 #5849]  INFO -- : Refreshing Gem list
NoMethodError: undefined method `load_defaults' for #<Rails::Application::Configuration:0x007fe1f333db28>
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/railties-5.0.6/lib/rails/railtie/configuration.rb:95:in `method_missing'
  /usr/share/nginx/html/config/application.rb:12:in `<class:Application>'
  /usr/share/nginx/html/config/application.rb:10:in `<module:Stu>'
  /usr/share/nginx/html/config/application.rb:9:in `<top (required)>'
  /usr/share/nginx/html/config/environment.rb:2:in `require_relative'
  /usr/share/nginx/html/config/environment.rb:2:in `<top (required)>'
  config.ru:4:in `require_relative'
  config.ru:4:in `block in <main>'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/rack-2.0.3/lib/rack/builder.rb:55:in `instance_eval'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/rack-2.0.3/lib/rack/builder.rb:55:in `initialize'
  config.ru:1:in `new'
  config.ru:1:in `<main>'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn.rb:56:in `eval'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn.rb:56:in `block in builder'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/bin/unicorn_rails:139:in `call'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/bin/unicorn_rails:139:in `block in rails_builder'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:795:in `call'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:795:in `build_app!'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:139:in `start'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/bin/unicorn_rails:209:in `<top (required)>'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/bin/unicorn_rails:23:in `load'
  /usr/share/nginx/html/vendor/bundle/ruby/2.2.0/bin/unicorn_rails:23:in `<top (required)>'
```

とあるので、

INFO -- : Refreshing Gem list
NoMethodError: undefined method `load_defaults' for #

load_defaults　左記関数が使えないらしい、

rails 5.1かららしいので、

```
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Stu
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.1 <- 左記関数をコメントアウト
　　　　　　　　　# config.load_defaults 5.1 こんな感じにします。
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
  end
end

```

すると解決できます。

```
I, [2018-01-17T23:28:36.570446 #6019]  INFO -- : Refreshing Gem list
I, [2018-01-17T23:28:38.978489 #6019]  INFO -- : listening on addr=/tmp/unicorn.sock fd=13
E, [2018-01-17T23:28:39.331016 #6019] ERROR -- : Access denied for user 'root'@'localhost' (using password: NO) (Mysql2::Error)
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/mysql2-0.4.10/lib/mysql2/client.rb:89:in `connect'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/mysql2-0.4.10/lib/mysql2/client.rb:89:in `initialize'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/mysql2_adapter.rb:25:in `new'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/mysql2_adapter.rb:25:in `mysql2_connection'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:729:in `new_connection'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:773:in `checkout_new_connection'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:752:in `try_to_checkout_new_connection'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:713:in `acquire_connection'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:490:in `checkout'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:364:in `connection'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:883:in `retrieve_connection'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_handling.rb:128:in `retrieve_connection'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.6/lib/active_record/connection_handling.rb:91:in `connection'
config/unicorn.rb:25:in `block in reload'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:543:in `call'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:543:in `spawn_missing_workers'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:142:in `start'
/usr/share/nginx/html/vendor/bundle/ruby/2.2.0/gems/unicorn-5.4.0/bin/unicorn_rails:209:in `<top (required)>'
```

DBにアクセスできないらしいので、

```
vi config/database.yml

# MySQL. Versions 5.1.10 and up are supported.
#
# Install the MySQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem 'mysql2'
#
# And be sure to use new-style password hashing:
#   http://dev.mysql.com/doc/refman/5.7/en/old-client.html
#
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: ユーザーの名前
  password: パスワードを入力
  socket: /var/lib/mysql/mysql.sock

development:
  <<: *default
  database: stu_development

test:
  <<: *default
  database: stu_test
```

これでDBへ接続できますので、

解決です。