RailsアプリをAWS、unicorn、nginxで手動デプロイして独自ドメインを紐づけるまで

これまでさくらVPS、appache、passengerでは結構デプロイしてきたけど、AWSの経験がなかったので今回はまったところも含めてメモしておきます。結局、AWSの立ち上げから丸2日間ぐらい悪戦苦闘してしまった。今後はサクサクできるようにしたいです。

全体としてこちらの記事にお世話になりました。

[AWSはこれで大丈夫｜unicorn + nginx + capistrano + slackistrano のコマンド一覧](http://qiita.com/Yama-to/items/1e1d889e6d5f7cc7f281)

[最小限でRailsをAWSにデプロイする。Ubuntu,Unicorn,Nginx,PostgreSQL](http://qiita.com/mochizukikotaro/items/658cd5f9f5f07c544b95)

デプロイの中身を理解するために、capistranoは使用せず手動でデプロイしています。

# AWSの設定
AWSの設定は上記で紹介した、[AWSはこれで大丈夫｜unicorn + nginx + capistrano + slackistrano のコマンド一覧](http://qiita.com/Yama-to/items/1e1d889e6d5f7cc7f281)を元に設定したらある程度サクサク進みました。

## VPCの設定
VPCというものが何かは正直よくわかっていません。いくつかのネット上の記事を読んだけどインフラ的な概念の基礎知識が欠けているのかどれを読んでもピンと来ず、今後の課題になっています。。。VPCを設定することで自分専用のAWS空間を使用でき、IPアドレスの設定など諸々が出来るようになるという認識ですが間違っていたらコメントください。

VPCの設定はこちらの動画を参考にAWSからぽちぽち設定するだけでした。

[AWS講座 - VPC/EC2インスタンスの作成から接続まで](https://www.youtube.com/watch?v=TDaLNHOL-h4&feature=youtu.be)

## EC2インスタンスの設定
EC2インスタンスの設定も上記の動画を参考にぽちぽち行うだけで完了します。キーペアを~/.sshに保存してあげます。Elastic IPの設定を忘れずに行いましょう。この設定をすることで固有のIPアドレスをEC2インスタンスに紐づけることができます。これやらないとサーバーのIPアドレスが起動の度に変わってしまうようです。

## SSHでEC2に接続
ここまででEC2にアクセスする準備が完了しました。ここからSSHでEC2にアクセスして各種設定をコマンドラインから行えるようにします。まずはダウンロードしたキーペアを~/.sshファイルにうつします。下記は全てローカルで実行しています。


```bash
mkdir ~/.ssh # sshフォルダがない場合は作成しておく
chmod 700 ~/.ssh # sshフォルダの権限を変更
cd /Downloads # キーペアをダウンロードしたフォルダに移動
mv /Downloads/[appname].pem ~/.ssh/ #.pemと書かれたものがawsアクセスのためのキー
ssh -i ~/.ssh/[appname].pem [ipアドレス] # Elastic IPで設定したアドレスを[ipアドレス]に入力
```

Are you sure you want to continue connecting(yes/no)?とでたらyesと入力して接続できればOKです。

## 作業用ユーザーの作成
EC2はデフォルトでec2-userというuserでアクセスしますが、セキュリティを強化するのであれば別のユーザーを作成し、ec2-userを削除しておきましょう。下記は全てsshでログインした先の作業です。ローカルでの作業ではないので注意。

```bash
sudo adduser [username] # 任意の[username]でユーザーを作成
sudo usermod -G wheel [username] #userをwheelグループに追加
sudo passwd [username] #userのパスワードを設定
visudo # sudoのファイルを下記の通り、編集
```

sudo権限を[username]に付与して、sudoで諸々できるように設定しましょう。

```
%wheel  ALL=(ALL)       ALL # コメントアウトして有効化する、「/」を押してからwheelと打って検索して該当箇所を探す
```

ユーザーが作成できて、sudo権限を追加したら、sshでログインするためのauthorized_keysを[username]のフォルダに移動しましょう。

```bash
sudo rsync -a ~/.ssh/authorized_keys ~[username]/.ssh/
sudo chown -R [username]:[username] ~[username]/.ssh
sudo chmod -R go-rwx ~[username]/.ssh
```


ここから一旦ローカルで作業を行い、新しく作成した[username]でsshログインできるか確認しましょう。

```bash
ssh -i ~/.ssh/[appname].pem [username]@[ipアドレス]
```

ec2-userではなく[username]でアクセスできたら完了！ログインできたことを確認したらec2-userを削除しましょう。

```bash
sudo userdel ec2-user # ec2-userを削除
```

## 作業用ディレクトリの作成
railsアプリを配置する作業用のディレクトリを作成します。多くのアプリが/var/wwwの配下にあるので、その通り作成しています。

```bash
sudo mkdir /var/www # /var/wwwディレクトリを作成する
cd /var
sudo chown [username] www # 上記で指定したユーザーを所有者として指定する
```

## Portの変更
sshでアクセスできるポートはデフォルトでは22ですが、これを変更することでセキュリティが強化されるのでやっておきましょう。

```bash
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.org # 予めsshd_configのファイルをコピーしておき間違っても戻せるようにしておく
sudo vi /etc/ssh/sshd_config # ssh_configを編集する
```

```bash:/etc/ssh/sshd_config
Port 22 # 念のためPort22でもアクセスできるようにしておき、下記のPortでログインできることを確認してからコメントアウトする
Port 22012 # Port22の下に任意の番号を設定する、ここでは22012を設定
```

```bash
sudo service sshd reload # 変更を反映させるためにsshdを再起動
```

Portを変更したらAWSのセキュリティグループ設定に上記のポートを追加しておかないとアクセスできません。セキュリティグループの設定からカスタムTCPルールで22012を設定します。変更が終了したらローカルから下記のコマンドでアクセスが可能か確認します。

```bash
ssh -i ~/.ssh/[appname].pem -p 22012 [username]@[ipアドレス]
```

上記のコマンドでアクセスできたら、今度はAWSのサーバー側で下記の作業を行い、22番ポートを閉じてしまいます。

```bash
sudo vi /etc/ssh/sshd_config # ssh_configを編集する
```

```bash:/etc/ssh/sshd_config
#Port 22 # コメントアウトしてPort 22でアクセスできないようにする
Port 22012 # Port22の下に任意の番号を設定する、ここでは22012を設定
```

22番ポートでアクセスできないか確認するためにはローカルで下記のコマンドを打ってログインできないことを確認すればOKです。

```bash
ssh -i ~/.ssh/[appname].pem [username]@[ipアドレス]
```


## プラグインのインストール
下記のコマンドを打って必要なプラグインを全てインストールします。

```bash
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

sudo yum install nodejs npm --enablerepo=epel # nodejsをインストール
```

```bash:rbenvをインストール
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source .bash_profile
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
rbenv rehash
```

```bash:rubyをインストール
rbenv install -v 2.1.3 # version2.1.3をインストール、バージョンは好みで変更
rbenv global 2.1.3
rbenv rehash
ruby -v # 上記のバージョンのrubyがインストールされていることを確認
```

## RDSの設定
データベースを扱うRDSの設定を行っていきます。これも基本的にはぽちぽちやっていくだけです。これはドットインストールを参考にしました。

[#10 データベースを立ち上げてみよう](http://dotinstall.com/lessons/basic_aws/9510)

注意する点としては、DB nameとMaster UsernameとMaster Passwordはrailsからアクセスする際にdatabase.ymlで設定する際に必要になるのでメモを取るなり覚えておきましょう。またエンドポイントというものがRDSの画面にありますが、ここで表示されているエンドポイントもアクセスする際に必要で、database.ymlに記述するのでメモしておきましょう。

RDSでの立ち上げが終了したらセキュリティグループの設定にて、mysqlの3306ポートを開くように設定しておきましょう。設定の際にはこちらを参考にしました。

[0から始めるAWS入門④：RDS編](http://qiita.com/hiroshik1985/items/6643b7323183f82297b2)

### mysqlの日本語設定
また日本語を使用する場合は、RDSの画面から「パラメーターグループの作成」⇒「パラメーターの編集」から以下のパラメーターを変更する必要があります。

```bash
character_set_client :utf8 #デフォルトからutf8に変更
character_set_connection :utf8 #デフォルトからutf8に変更
character_set_database :utf8 #デフォルトからutf8に変更
character_set_results :utf8 #デフォルトからutf8に変更
character_set_server :utf8 #デフォルトからutf8に変更

skip-character-set-client-handshake :1 #0から1に変更
```

僕はこの日本語の処理を忘れて結構面倒なことになってしまいました。rake db:create、rake db:migrateまでしてしまった後にこの問題に気づいたため、こちらのページを参考に修正しました。

[MySQLでcharacter_set_databaseがlatin1になってしまう問題の対応方法](http://interu.hatenablog.com/entry/2013/11/19/120322)

[MySQL の文字コード設定を後から変えるには](http://kzworks.at.webry.info/200903/article_14.html)

ここまで設定したらEC2からアクセスできるか確認しましょう。

```bash
mysql -h [エンドポイントで表示されているもの] -u [設定したMaster Username] -p
Enter Password: #上記で設定したMaster Password
```

mysqlにアクセスできたら設定は完了、念のため下記のコマンドで指定したDB nameでdatabaseが作成されているか確認しましょう。

```mysql
mysql > show databases; # 表示されたdatabaseに[DB name]があればOK
```

# nginxの設定
基本的にインストールして、[appname].confの設定ファイルを記述するだけで終わりです。設定については[最小限でRailsをAWSにデプロイする。Ubuntu,Unicorn,Nginx,PostgreSQL](http://qiita.com/mochizukikotaro/items/658cd5f9f5f07c544b95)を参考にコピーして一部変更した感じです。下記のような形にしています。

```bash:nginxをインストール
sudo yum install nginx
sudo vi /etc/nginx/conf.d/[appname].conf # 下記のファイルの通りに編集
```

```bash:/etc/nginx/conf.d/[appname].conf
upstream unicorn_server {
    server unix:/tmp/unicorn.sock
    fail_timeout=0;
}

server {
    listen 80;
    client_max_body_size 4G;
    server_name {IPアドレス};

    keepalive_timeout 5;

    # Location of our static files
    root /var/www/{appname}/public; # appname部分は自分自身で設定

    location ~ ^/assets/ {
        # 誤り) root /var/www/{appname}/shared/public; 
        root /var/www/{appname}/public; #修正後
    }

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

        if (!-f $request_filename) {
            proxy_pass http://unicorn_server;
            break;
        }
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /var/www/{appname}/public;
    }
}
```

編集が終了したらnginxを起動させます。

```bash
sudo service nginx start # nginxを起動
sudo chkconfig nginx on # nginxの自動起動をonに設定しておく
```

Elastic IPで指定した固定のipアドレスにアクセスしてnginxの表示が出たらOK

# gitクローン
[gitを使ったデプロイ方法](http://qiita.com/__mick/items/1f73fcb0d5dc7f5982f4)を参考にローカルでプッシュすると本番環境に変更したファイルが置かれるように設定しました。既にgitで管理しており、[appname].gitでgithubで管理しています。

## ローカルで ~/.ssh/configファイルを作成
準備として、~/.ssh/configファイルを作成しておきます。このファイルを作成しておくことで簡単なコマンドでsshログインが可能になります。

```bash:~/.ssh/config
host [appname] # 上記で指定したappnameと同じものを指定
  HostName     ***.***.***.** # Elastic IPで指定した固定のipアドレス
  Port         22012 # 上記で22012に変更していたのでそのportを指定
  User         [username] # AWSの最初の設定で作成した[username]を指定
  IdentityFile ~/.ssh/id_rsa
```

この設定を行っておくと、`ssh [appname]`でsshログインが可能になります。

## 作業用ディレクトリに移動してgit cloneする
```bash
ssh [appnmae]
cd /var/www
git init --bare [appname].git # [appname].gitで既に管理している場合
```

プッシュした際にAWSにもpushされるように、ローカルにて/.git/configファイルを下記のように修正します。

```bash:.git/config
[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = git@github:[gituser]/[appname].git
    url = [appname]:/var/www/[appname].git
```

ここまで完了したらローカルで`git push origin master`しましょう。その後AWSの作業用ディレクトリにアクセスしてgit cloneできるか確認します。

```bash
ssh [appname]
cd /var/www
git clone /[appname].git
```

これで/var/wwwに[appname]というrailsアプリ用のディレクトリが作成できているはずです。git pushした際に、AWS側でpullする設定をしたい場合は下記のリンクからgit hookの追加の部分を読んでいただければと思います。

[gitを使ったデプロイ方法](http://qiita.com/__mick/items/1f73fcb0d5dc7f5982f4)


# Unicornの設定
ここまでくればもう少しのはずですが、unicornの設定は若干はまりました。working_directoryの設定の際に、/currentの記述をしていなかったらCSSとjavascriptのファイルを読み込まずに3時間ぐらいはまっていました。。。

```apache:/var/www/[appname]/config/unicorn/production.rb
@app_path = '/var/www/{appname}'
working_directory @app_path + "/current" # このcurrentの指定をしていなかったらデプロイ後に/assets以下が読み込まれずはまった

worker_processes 2
preload_app true
timeout 30
listen "/tmp/unicorn.sock", :backlog => 64
pid "/var/www/{appbane}/shared/tmp/pids/unicorn.pid"

stderr_path "#{@app_path}/log/unicorn.stderr.log"
stdout_path "#{@app_path}/log/unicorn.stdout.log"

before_fork do |server, worker|
  ENV['BUNDLE_GEMFILE'] = File.expand_path('Gemfile', ENV['RAILS_ROOT'])
end

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

  old_pid = "#{server.config[:pid]}.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

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

設定ファイルの記述が終わったらAWS側でunicornを起動させます。

```bash
sudo mkdir /var/www/{appname}/shared/tmp/pids # 必要なディレクトリの作成
sudo chmod 777 /var/www/{appname}/shared/tmp/pids # 必要なディレクトリに権限付与
cd /var/www/{appname}
bundle exec unicorn_rails -c config/unicorn.rb -p 8080 -D -E production    #起動
ps aux | grep unicorn    #動いているかの確認
```

ここまででunicornの設定は完了。後はbundle installして、rake db:migrateして、rake assets:precompileすればOKです。

# migrationおよびassets:precompile
ここまでで必要な設定は終了したので、migrationおよびコンパイル作業をやりましょう。

```bash
cd /var/www/[appname]
gem install bundler # bundlerのインストールを行わないとbundleコマンドが使えない
bundle install # gemファイルの必要ファイルが読み込まれる
bundle exec rake db:migrate RAILS_ENV=production # migrationの実行
bundle exec rake assets:precompile RAILS_ENV=production
sudo service nginx restart # nginxの再起動を行う
```

ここまででipアドレスにアクセスすればちゃんとサイトが表示されるはずです。僕はここまでいった後にサイトが表示されず、nginxの403forbiddenが表示されたり、bad gatewayが表示されたりしたので、上記の設定ファイルを何度か見直したりしました。やっと表示されたと思ってもcssが読み込まれていないなんてこともありました。上記の設定ファイルの変更は失敗を反映しているので大丈夫だと思います。

# AWSで独自ドメインの設定
ここまで出来たのでお名前ドットコムで取得した独自ドメインをAWSに紐づけます。独自ドメインの紐付けはそこまで難しくなく、AWSのRoute53をぽちぽち設定して、表示されたものをお名前ドットコムの管理画面で設定すればOKって感じです。僕個人は、お名前ドットコムは技術サポートの電話は24時間対応なので、困ったらちゃんと設定できているか電話で確認してしまっています。

[お名前.com で取ったドメインを Amazon Route53で管理し、サブドメインをはてなブログに割り当てるまで](http://tech.tanaka733.net/entry/2013/09/15/%E3%81%8A%E5%90%8D%E5%89%8D.com_%E3%81%A7%E5%8F%96%E3%81%A3%E3%81%9F%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92_Amazon_Route53%E3%81%A7%E7%AE%A1%E7%90%86%E3%81%97%E3%80%81%E3%82%B5%E3%83%96%E3%83%89)

以上になります。結構はまって大変だったので今後もアップする際に必要になるかと思ってメモとして残しておきます。誰かの参考になればうれしいです。

# 変更の反映 Unicornの再起動
apacheとpassengerの時はapacheを再起動すれば変更が反映されていたので、nginxの再起動で反映されるかと思いきや反映されていなかったのでメモ。