AWSのEC2でUbuntu+nginx+Unicornの環境構築物語

## なれそめ

* サーバ構築、フレームワークの導入に慣れよう
* ウェブサービスを自分一人で作れるようになるための練習

## 概要

* 自分が慣れるため、今後のメモのためという意味合いが強いです
* unicornとしての機能には触れません

## 環境

* Ubuntu 16.04.2 LTS
* nginx/1.10.0 (Ubuntu)
* ruby 2.4.0p0
* rbenv 1.1.0
* Bundler version 1.14.6
* unicorn 5.2.0

## 1.サーバ初期設定

1. AWSでEC2インスタンス作成(Ubuntuを選択)
2. セキュリティグループ設定：自分の利用する回線(送信元)で、指定したポートでSSH接続するために解放する(任意のポート)
3. AWSで接続のコマンドを用意してくれるのでそれを利用してターミナルからSSHでアクセス

##### ssh接続の設定

セキュリティを最低限強くするため、22番での接続を禁止し、rootでのログインも禁止する

```
$ sudo vim /etc/ssh/sshd_config
```

```sshd_config
Port 55555 // 任意のポート番号に変更
PermitRootLogin no // noに変更
```

```
$ sudo /etc/init.d/ssh restart
```

これで22番ポートでのログインが禁止され、以下のようにポートを指定してログインができる

`sudo ssh -p 55555 -i "key.pem" ubuntu@ec2-XX-XXX-XXX-XXX.us-west-2.compute.amazonaws.com`

> sshの設定を変更したらrestartして反映させる

#### 作業ユーザ設定

sudo権限も付与しておく

```
$ sudo useradd -m sasaki
$ sudo passwd sasaki
$ sudo usermod -G sudo sasaki
$ su - sasaki
```

## 2.bundler導入とrailsプロジェクト作成

1. ruby用ライブラリ(gem)の管理するためにbundlerを用いる
2. gemコマンドでbundlerをインストール
3. Gemfileを編集してrailsのインストールの準備

```
$ sudo apt update
$ sudo apt-get install bundler
$ mkdir rails-app/ && cd rails-app/
$ bundle init
$ vi Gemfile
```

```Gemfile
# A sample Gemfile
source 'https://rubygems.org'

gem 'rails', '>= 5.0.0.1'
gem 'sqlite3'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'therubyracer', platforms: :ruby
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc
gem 'bcrypt', '~> 3.1.7'
gem 'unicorn'

group :development, :test do
  gem 'byebug'
  gem 'web-console', '~> 2.0'
  gem 'spring'
end
```

```
$ bundle install --path vendor/bundle
$ bundle exec rails new .
```

ここで僕はsqlite3がないよと怒られたのでapt-getで入れました

```
$ sudo apt-get install libsqlite3-dev
```

## 3.rubyとrbenvの用意

```
$ cd ~/rails-app/
$ git clone https://github.com/sstephenson/rbenv.git .rbenv
$ git clone https://github.com/sstephenson/ruby-build.git .rbenv/plugins/ruby-build
$ sudo apt update
$ vi ~/.bashrc


```.bashrc
+ [[ -d ~/rails-app/.rbenv  ]] && \
+   export PATH=${HOME}/rails-app/.rbenv/bin:${PATH} && \
+   eval "$(rbenv init -)"
```

```
$ source ~/.bashrc
```

## 4.アプリケーション作成へ

```
$ cd ~/rails-app/
$ bundle exec rails generate scaffold board title:string text:string
```

ここでエラーが発生、よく出るエラーところらしい
エラーが出たら以下のようにコメントアウトを外すして改めて`bundle install`すると成功うまく行く場合が多い

```
$ vi Gemfile
```

```Gemfile
- # gem 'therubyracer', platforms: :ruby
+ gem 'therubyracer', platforms: :ruby
```

```
$ bundle install
$ bundle exec rails generate scaffold board title:string text:string
```

rakeコマンドが使えるのでrakeでDBのマイグレート

```
$ rake db:migrate
```

```
$ vi config/routes.rb
```

```routes.rb
...
+  root "boards#index"
end
...
```

以下のコマンドでサーバを起動(ctrl+C)でキャンセルできる

```
$ bundle exec rails server -b 0.0.0.0
```

他にもタブを開いて確認して見ると確認ができる

```
$ ps aux | grep 0.0.0.0:3000
sasaki  24821  1.0  7.2 751628 73444 pts/1    Sl+  04:27   0:01 puma 3.8.2 (tcp://0.0.0.0:3000) [rails-app]
```


## 5.unicorn設定

unicorn.rbについては
[ここ](http://qiita.com/Salinger/items/5350b23f8b4e0dcdbe23)のを参考にした

```
$ cd ~/rails-app/config/ && vi unicorn.rb
```

```unicorn.rb
# -*- coding: utf-8 -*-
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 15
preload_app true  # 更新時ダウンタイム無し

listen File.expand_path('/tmp/sockets/unicorn.pid', __FILE__)
pid File.expand_path('/tmp/pids/unicorn.pid', __FILE__)
listen "/tmp/sockets/unicorn.sock"
pid "/tmp/pids/unicorn.pid"

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

# ログの出力
stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
```

rakeコマンドでユニコーンの起動や停止を行うために以下の編集を行う
こちらも先ほどのQiitaを参考にしました

```
$ bundle exec rails generate task unicorn
$ cd ~/rails-app/ && vi lib/tasks/unicorn.rake
```

```unicorn.rake
namespace :unicorn do
  ##
  # Tasks
  ##
  desc "Start unicorn for development env."
  task(:start) {
    config = Rails.root.join('config', 'unicorn.rb')
    sh "bundle exec unicorn_rails -c #{config} -E development -D"
  }

  desc "Stop unicorn"
  task(:stop) { unicorn_signal :QUIT }

  desc "Restart unicorn with USR2"
  task(:restart) { unicorn_signal :USR2 }

  desc "Increment number of worker processes"
  task(:increment) { unicorn_signal :TTIN }

  desc "Decrement number of worker processes"
  task(:decrement) { unicorn_signal :TTOU }

  desc "Unicorn pstree (depends on pstree command)"
  task(:pstree) do
    sh "pstree '#{unicorn_pid}'"
  end

  def unicorn_signal signal
    Process.kill signal, unicorn_pid
  end

  def unicorn_pid
    begin
      File.read("/tmp/pids/unicorn.pid").to_i
    rescue Errno::ENOENT
      raise "Unicorn doesn't seem to be running"
    end
  end
end
```

これで以下のようなコマンドが使える

> rake unicorn:start
> rake unicorn:stop

## 6.nginx導入とブラウザで確認

```
$ sudo apt-get install -y nginx
$ /etc/init.d/nginx start
$ /etc/init.d/nginx status
```

これでnginxが `Active: active (running)` であることを確認できるはず

nginxとのやりとりにはソケットを使う
conf.dにconfファイルを置けばそれが読まれる設定になっている

```
$ cd /etc/nginx/conf.d/
$ sudo vi local.conf
```


```local.conf
upstream unicorn {
  server unix:/tmp/sockets/unicorn.sok;
}

server {
  listen 80 default_server;
  server_name localhost-rails;

  access_log /var/log/nginx/sample_access.log;
  error_log /var/log/nginx/sample_error.log;

  root /home/sasaki/rails-app/app/views/boards;

  client_max_body_size 100m;
  error_page 404 /404.html;
  error_page 500 502 503 504 /500.html;
  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://unicorn;
  }
}
```

```
$ sudo vi ../nginx.conf
```

```nginx.conf
- include /etc/nginx/sites-enabled/*;
+ # include /etc/nginx/sites-enabled/*; 
```

以下のようにそれぞれのファイルで同じ場所のsockファイルを見るように設定されていることが必要
違ってたら揃える

```/etc/nginx/conf.d/local.conf
server unix:/tmp/sockets/unicorn.sock;
```

```unicorn.rb
listen "/tmp/sockets/unicorn.sock"
pid "/tmp/pids/unicorn.pid"
```

sockファイルの置き場は工夫の余地があるかと
AWSを用いているのでブラウザから見れるようにセキュリティグループに追加し
nginx再起動させてhttp://でアクセス


```
$ /etc/init.d/nginx restart
```


## うまくいかないとき

nginxのログ(上記の設定だと)

```
$ sudo tail -f /var/log/nginx/sample_access.log
$ sudo tail -f /var/log/nginx/sample_error.log
```