RailsアプリケーションのAWSによる公開｜unicorn + nginx

# まえがき
AWSのVPCとEC2の設定が出来ている状態から、
***実際に自分のRailsアプリケーションを公開する***
までの一連の流れを説明します。
(まだ、VPCとEC2の設定が出来ていない方は以下の記事を見て設定をお願いします。
[AWS VPCによるネットワーク構築とEC2によるサーバー構築](http://qiita.com/shizuma/items/396ad15ff574717dfa1d))

「protospace」というアプリケーションをサーバーに「shizuma」というユーザーで作成していきます。
適宜、お好きに変更して作業を進めて下さい。
***実際に自分のRailsアプリケーションを公開する***ことが目的ですので実際に手を動かしながら見てもらえると嬉しいです！
作業は、「local」と「server」の作業どちらか確かめながら進めて下さい。コマンドを記載したエリアの左端に記述しています。
(「#」はコメントアウトです)
capistranoでのデプロイ等は本記事ではいたしません。本記事の後に以下の記事を参考にしてください。
[AWS RailsアプリケーションのCapistranoによるデプロイ](http://qiita.com/shizuma/items/c23518a1934c738ec3b0)
なお、至らない点はご教示頂けますと幸いです。

Rails5系の Nginx+Pumaの記事も書いているので5系の方はこちらをどうぞ↓

[Rails5アプリケーションのAWSによるネットワーク構築 Nginx+Puma+Capistranoな環境とAWS構築(VPC EC2 RDS CloudFlont Route53 etc)](http://qiita.com/shizuma/items/0bfa71f70573e587669f)

# ec2-userでサーバーにアクセスする

VPCとEC2の設定まで終えている状態であれば、```~/Downloads/protospace.pem```のようなファイルがダウンロードされます。これを使用してサーバーにアクセスします。(ファイル名は作成時の名前によって異なるので適宜変更）

```rb:local
[~]$ mv Downloads/protospace.pem .ssh
[~]$ cd .ssh
[.ssh]$ chmod 600 protospace.pem
[.ssh]$ ssh -i protospace.pem ec2-user@54.64.22.197 #pemファイルに加え、IPアドレスも自分の環境に合わせて変更
```

## 補足
### ssh -i
sshで公開鍵認証を行うとき、-iで秘密鍵のパスを指定出来ます。-iでの指定がない場合「~/.ssh/id_rsa」あるいは「~/.ssh/id_dsa」が秘密鍵として使われることになるので基本的に-iで指定すると良いと思います。

```rb:server
[ec2-user|~]$ sudo adduser shizuma #ユーザーの追加 「shizuma」の部分は好きなユーザー名にします。以後「shizuma」の部分は各自のユーザー名になります。
[ec2-user|~]$ sudo passwd shizuma
#ここで、新規ユーザーのパスワードを設定します。
[ec2-user|~]$ sudo visudo
-----------------------------
#vimが起動するので新規ユーザーにroot権限を与える。
root    ALL=(ALL)       ALL
shizuma ALL=(ALL)       ALL #この行を追加
-----------------------------
[ec2-user|~]$ sudo su - shizuma #ユーザー切り替え
#先ほど設定したパスワード
```

### 参考
[sshで公開鍵認証を行うときに指定するオプション -i | CentOS・Red Hat Linux実践テクニック](http://d.hatena.ne.jp/perlcodesample/20130302/1362379846)
[visudoコマンド（sudoコマンドの為の設定ファイルの編集）](http://www.garunimo.com/program/linux/visudo.xhtml)

# 作成したユーザーでサーバーにアクセス出来るようにする

```rb:local
#この部分はserverとはターミナルとは別タブで作業するといいです
[~]$ cd .ssh
[.ssh]$ ssh-keygen -t rsa
-----------------------------
Enter file in which to save the key ():first_aws_rsa #ここでファイルの名前を記述して、エンター
Enter passphrase (empty for no passphrase): #何もせずそのままエンター
Enter same passphrase again: #何もせずそのままエンター
-----------------------------
[.ssh]$ ls
#「first_aws_rsa」と「first_aws_rsa.pub」が生成されたことを確認
[.ssh]$ vi config
-----------------------------
# 以下を追記
Host first_aws
  Hostname 54.64.22.197 #自分の設定に合わせて
  Port 22
  User shizuma #先ほどのユーザー名
  IdentityFile ~/.ssh/first_aws_rsa #秘密鍵の設定
-----------------------------
```

```rb:server
[shizuma|~]$ mkdir .ssh
[shizuma|~]$ chmod 700 .ssh
[shizuma|~]$ cd .ssh
[shizuma|.ssh]$ vi authorized_keys
-----------------------------
#localの「first_aws_rsa.pub」の中身のコピペ。(localで　$ cat first_aws_rsa.pubとかすると良い)
ssh-rsa sdfjerijgviodsjcIKJKJSDFJWIRJGIUVSDJFKCNZKXVNJSKDNVMJKNSFUIEJSDFNCJSKDNVJKDSNVJNVJKDSNVJKNXCMXCNMXNVMDSXCKLMKDLSMVKSDLMVKDSLMVKLCA shizuma@shizuma-no-MacBook-Air.local
-----------------------------
[shizuma|.ssh]$ chmod 600 authorized_keys
[shizuma|.ssh]$ exit
[ec2-user|~]$ exit
#localへ
```

ここまで行うと、作成ユーザーで簡単にssh接続出来るようになる。

```rb:local
[~]$ ssh first_aws
```
でアクセス出来るようになる。
「first_aws」の部分はlocalの「.ssh/config」のHostで設定したもの

# サーバーの基本設定
```:server
[shizuma|~]$ sudo yum install \
git make gcc-c++ patch \
openssl-devel \
libyaml-devel libffi-devel libicu-devel \
libxml2 libxslt libxml2-devel libxslt-devel \
zlib-devel readline-devel \
mysql mysql-server mysql-devel \
ImageMagick ImageMagick-devel \
epel-release
#ここまで打ってやっとインストールが始まります

[shizuma|~]$ sudo yum install nodejs npm --enablerepo=epel #node.jsのインストール

#rbenvのインストール
[shizuma|~]$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv #rbenvのクローン
[shizuma|~]$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile #パスを通す
[shizuma|~]$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
[shizuma|~]$ source .bash_profile #.bash_profileの読み込み
[shizuma|~]$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build #ruby-buildのインストール
[shizuma|~]$ rbenv rehash #rehashを行う

# ruby 2.1.3のインストール(versionは適宜変更)
[shizuma|~]$ rbenv install -v 2.1.3
[shizuma|~]$ rbenv global 2.1.3
[shizuma|~]$ rbenv rehash
[shizuma|~]$ ruby -v
#versionが表示されれば成功
```

```rb:server
#gitの設定
[shizuma|~]$ vi .gitconfig
-----------------------------
#これを記載
[user]
  name = your_name #自分の名前
  email = hoge@hoge.com #自分のメアド

[alias] #これはお好きに
  a = add
  b = branch
  ch = checkout
  st = status

[color] #色付け
  ui = true

[url "github:"] #pull、pushのための設定
    InsteadOf = https://github.com/
    InsteadOf = git@github.com:
-----------------------------
# /var/www/railsという場所にアプリケーションを設置する
[shizuma|~]$ cd /
[shizuma|/]$ sudo chown shizuma var #varフォルダの所有者をshizumaにする
[shizuma|/]$ cd var
[shizuma|var]$ sudo mkdir www
[shizuma|var]$ sudo chown shizuma www 
[shizuma|var]$ cd www
#wwwと同じ処理
[shizuma|www]$ sudo mkdir rails
[shizuma|www]$ sudo chown shizuma rails
```

次から、githubとの接続です。

```rb:server
[shizuma|www]$ cd ~
[shizuma|~]$ mkdir .ssh
[shizuma|~]$ chmod 700 .ssh
[shizuma|.ssh]$ cd .ssh
[shizuma|.ssh]$ ssh-keygen -t rsa
-----------------------------
Enter file in which to save the key ():aws_git_rsa #ここでファイルの名前を記述して、エンター
Enter passphrase (empty for no passphrase): #何もせずそのままエンター
Enter same passphrase again: #何もせずそのままエンター
-----------------------------
[shizuma|.ssh]$ ls
#「aws_git_rsa」と「aws_git_rsa.pub」が生成されたことを確認
[shizuma|.ssh]$ vi config
-----------------------------
# 以下を追記
Host github
  Hostname github.com
  User git
  IdentityFile ~/.ssh/aws_git_rsa #秘密鍵の設定
-----------------------------
[shizuma|.ssh]$ cat aws_git_rsa.pub
-----------------------------
ssh-rsa sdfjerijgviodsjcIKJKJSDFJWIRJGIUVSDJFKCNZKXVNJSKDNVMJKNSFUIEJSDFNCJSKDNVJKDSNVJNVJKDSNVJKNXCMXCNMXNVMDSXCKLMKDLSMVKSDLMVKDSLMVKLCA shizuma@ip-10-0-1-10
-----------------------------
```
ここで、これをコピペしてgithubに公開鍵を登録する。
githubへの鍵の登録がよくわからない方は以下の記事を参考に。
[gitHubでssh接続する手順~公開鍵・秘密鍵の生成から~](http://qiita.com/shizuma/items/2b2f873a0034839e47ce#公開鍵をgithubにアップする)

そして、git clone する。

```rb:server
[shizuma|.ssh]$ cd /var/www/rails
[shizuma|rails]$ git clone git@github.com:kuboshizuma/protospace.git #適宜
```

ここで、secret_key_baseの設定をします。

```rb:server
[shizuma|rails] $: cd protospace
[shizuma|protospace] $: rake secret
-----------------------------
#コピーする
jr934ugr89vwredvu9iqfj394vj9edfjcvnxii90wefjc9weiodjsc9o i09fiodjvcijdsjcwejdsciojdsxcjdkkdsv
-----------------------------
[shizuma|protospace] $: vi config/secrets.yml
-----------------------------
  production:
    secret_key_base: jr934ugr89vwredvu9iqfj394vj9edfjcvnxii90wefjc9weiodjsc9o i09fiodjvcijdsjcwejdsciojdsxcjdkkdsv #ここに貼り付け
-----------------------------
```

# unicornの設定

```rb:server
[shizuma|protospace] $: vi Gemfile
-----------------------------
#以下を追記
group :production, :staging do
    gem 'unicorn'
end
----------------------------
[shizuma|protospace] $ gem install bundler
[shizuma|protospace] $ bundle install
[shizuma|protospace] $ vi config/unicorn.conf.rb
----------------------------
#以下を記載
  # set lets
  $worker  = 2
  $timeout = 30
  $app_dir = "/var/www/rails/protospace" #自分のアプリケーション名
  $listen  = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir
  $pid     = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
  $std_log = File.expand_path 'log/unicorn.log', $app_dir
  # set config
  worker_processes  $worker
  working_directory $app_dir
  stderr_path $std_log
  stdout_path $std_log
  timeout $timeout
  listen  $listen
  pid $pid
  # loading booster
  preload_app true
  # before starting processes
  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
        Process.kill "QUIT", File.read(old_pid).to_i
      rescue Errno::ENOENT, Errno::ESRCH
      end
    end
  end
  # after finishing processes
  after_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
  end
----------------------------
```

#nginxの導入

```rb:server
[shizuma|~] sudo yum install nginx
[shizuma|~]$ cd /etc/nginx/conf.d/
[shizuma|conf.d]$ sudo vi protospace.conf #自分のアプリケーション名でファイル名変更
----------------------------
  # log directory
  error_log  /var/www/rails/protospace/log/nginx.error.log; #自分のアプリケーション名に変更
  access_log /var/www/rails/protospace/log/nginx.access.log; #自分のアプリケーション名に変更
  # max body size
  client_max_body_size 2G;
  upstream app_server {
    # for UNIX domain socket setups
    server unix:/var/www/rails/protospace/tmp/sockets/.unicorn.sock fail_timeout=0; #自分のアプリケーション名に変更
  }
  server {
    listen 80;
    server_name [自分のipアドレス];
    # nginx so increasing this is generally safe...
    keepalive_timeout 5;
    # path for static files
    root /var/www/rails/protospace/public; #自分のアプリケーション名に変更
    # page cache loading
    try_files $uri/index.html $uri.html $uri @app;
    location @app {
      # HTTP headers
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app_server;
    }
    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/rails/protospace/public; #自分のアプリケーション名に変更
    }
  }
----------------------------
[shizuma|conf.d] cd /var/lib
[shizuma|lib] sudo chmod -R 775 nginx #これなしではPOSTメソッドでエラーになる
```

## 参考
[PHP POST接受长字符串时出现500错误](http://blog.sina.cn/dpool/blog/s/blog_916929d70102uyfm.html)

# database、mysqlの設定
```rb:server
[shizuma|protospace]$ vi config/database.yml
----------------------------
  production:
    <<: *default
    database: protospace_production
    username: root #ここをrootに変更する
----------------------------
[shizuma|protospace]$ sudo vi /etc/my.cnf
----------------------------
#以下を追記
character-set-server=utf8
----------------------------
[shizuma|protospace]$ sudo service mysqld start #mysqldの起動
[shizuma|protospace]$ ln -s /var/lib/mysql/mysql.sock /tmp/mysql.sock
[shizuma|protospace]$ rake db:create RAILS_ENV=production
[shizuma|protospace]$ rake db:migrate RAILS_ENV=production
```

##参考
[rails - Mysql2::Error: Incorrect string value](http://babiy3104.hateblo.jp/entry/2014/02/13/000219)
[[rails][mysql]Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’](http://blog.hello-world.jp.net/mysql/1484/)

#nginxの起動
```rb:server
[shizuma|protospace]$ sudo service nginx start
```

# 公開されたか確認する
これで、ブラウザにアクセスして確認してみて下さい！
```http://54.64.22.197```(自分のIPアドレス)

## うまくいかな場合
### unicornを再起動する

```rb:server
[protospace]$ ps -ef | grep unicorn | grep -v grep
----------------------------
# このように表示されていればunicornが起動されています。
shizuma  24265     1 27 03:12 ?        00:00:01 unicorn_rails master -c /var/www/rails/tech-ruche/config/unicorn.conf.rb -D -E production
shizuma  24271 24265  0 03:12 ?        00:00:00 unicorn_rails worker[0] -c /var/www/rails/tech-ruche/config/unicorn.conf.rb -D -E production
shizuma  24273 24265  0 03:12 ?        00:00:00 unicorn_rails worker[1] -c /var/www/rails/tech-ruche/config/unicorn.conf.rb -D -E production
----------------------------
[protospace]$ kill -9 24265 #24265の部分は自分のunicornのプロセスID。プロセスIDは以下に説明あり
[protospace]$ unicorn_rails -c /var/www/rails/protospace/config/unicorn.conf.rb -D -E production #unicornを起動させる
```

```$ ps -ef | grep unicorn | grep -v grep```したときの表示のうち、矢印で示した「24265」の部分に当たるのがプロセスIDです。
![スクリーンショット_2015-09-22_12_24_24.png](https://qiita-image-store.s3.amazonaws.com/0/40796/7dfc2fef-cd75-a2cd-d67a-b7d6b8f158c6.png)

## nginxを再起動する

```rb:server
[shizuma|protospace]$ sudo nginx -s reload
```

[nginx コマンド超シンプル早見表](http://qiita.com/katzueno/items/44e02db2f1bfa0de5860)にその他nginx周りのコマンドがまとまっています。

## 参考
[Nginx cannot find unix socket file with Unicorn (no such file or directory)](http://stackoverflow.com/questions/22272943/nginx-cannot-find-unix-socket-file-with-unicorn-no-such-file-or-directory)
[Rails 4.2 + Unicorn + Nginx でアプリケーションサーバの構築](http://qiita.com/Salinger/items/5350b23f8b4e0dcdbe23)


# 参考
[AWSはこれで大丈夫｜unicorn + nginx + capistrano + slackistrano の活用例](http://qiita.com/Yama-to/items/1e1d889e6d5f7cc7f281)
[Capistrano3 + Rails4 + Unicorn + Nginx + EC2でサーバー構築！](http://qiita.com/SanoHiroshi/items/d7942d66678f0d60f0ed)