Djangoの既存プロジェクトをec2にデプロイ

##概要
詰まりまくったのでメモ。Dockerで開発していたのでそのままデプロイしたろ！と思っていたが意味わからなすぎて断念。(おそらく？)一般的な方法でデプロイした。もっと良い方法があれば教えて欲しい限りです。


##環境
OS: Amazon Linux AMI release 2017.09
ローカル: Docker
Python: 3.6.2
Django: 1.11.5
Gunicorn: 19.7.1
Nginx: 1.12.1


##AWSの設定
###インスタンスの作成
AWSの設定は[Amazon Web Services 基礎からのネットワーク&サーバー構築](https://www.amazon.co.jp/gp/product/4822262960/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1)を参考にした。 

AWSに登録してコンソール > EC2からインスタンスを作成する。全部デフォルト。t2microなら無料。
VPC、サブネット、ルートテーブル、ゲートウェイ、セキュリティグループやらが作成される(はず)。なかったら作ってVPCに紐付ける。sshキーをダウンロードまたは登録しておく。

###ポートの開放
EC2 > セキュリティグループからポートが開放できる。セキュリティグループを選択 -> インバウンド -> 編集　-> ルールの追加で80番ポート、8000番ポート(確認用、あとで閉じる)を開く。タイプはカスタムTCP、ソースは0.0.0.0/0で良い。
ここで EC2 > インスタンス から作ったインスタンスの詳細が確認できる。右側のパブリックDNSでドメイン、IPv4パブリックIPでIPが確認できる。

##nginxのインストール
AWSにsshでログイン。キーペアをダウンロードした場合は~/.sshに置いて別のキー名を指定する。

```
# ssh -i ~/.ssh/id_rsa ec2-user@(インスタンスのIP)
```

以下ではrootで作業する。

```
$ sudo su -
```

以下、[EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする](https://qiita.com/xKxAxKx/items/da9dcc8caa36e1c303c7)を参考にnginxをインストール。

nginx入れる。

```
$ yum install nginx
```

nginxを起動する。

```
$ nginx
```

nginxの自動起動設定

```
$ chkconfig --add nginx
$ chkconfig nginx on
```

自動起動設定できているか確認する。


```
$ chkconfig | grep nginx
nginx           0:off   1:off   2:on    3:on    4:on    5:on    6:off
```


また、`http://(パブリックDNS)`を確認してnginxが起動しているか確認する。

##Djangoプロジェクトの起動
###AWSにプロジェクトを送る。
scpでzipで固めたDjangoプロジェクトを送る。また送る前にrequirements.txtは用意しておく。

```
# pip freeze > requirements.txt
```

```
# scp -i ~/.ssh/id_rsa ~/path/to/project.zip ec2-user@yourIP:home/ec2-user/
```

送ったものがhome/ec2-userに落ちているはず。解凍する

```
$ unzip project.zip
```

ほんとはgitで落とせばいいんだろうけどプライベートリポジトリにしてるので新しいuser登録して新しくssh登録してってしないといけないのかな。誰か教えてください。

###pythonとかを入れる
色々考えるのがめんどくさかったので[EC2サーバにPython3環境構築](https://qiita.com/tisk_jdb/items/01bd6ef9209acc3a275f)を参考にした。

gitとpyenv入れる。-yが全部yesって答えるオプションらしい。初めて知った。

```
$ yum install git -y
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
```
path通す。

```
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
```

コマンド通るか確認。

```
$ pyenv -v
```

依存関係を入れる。

```
$ sudo yum install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel -y
```

本体を入れる。

```
$ pyenv install 3.6.2
```

pythonを切り替える。これはrootのpythonなので、sudo su -後でないとデフォルトのpythonに戻ってしまうので注意。

```
$ pyenv global 3.6.2
$ pyenv rehash
$ python --version
Python 3.6.2
```

Django、その他諸々のプロジェクトに必要なライブラリをインストールする。

```
$ pip install --upgrade -r project/requirements.txt
```

requirements.txtにGunicornが入ってなければGunicornを入れる。
Gunicornとはwsgiサーバーのことで、nginxとDjangoを繋ぐものみたいなイメージ。

```
$ pip install gunicorn
```

manage.pyの上でDjangoを起動させる。

```
$ gunicorn your_project.wsgi --bind=0.0.0.0:8000
```

`http://(パブリックDNS):8000`を確認すると、ALLOWED_HOSTSに追加してね！と出るので追加する。

```/your_project/settings.py
# 中略
ALLOWED_HOSTS = ['(パブリックDNS)']
# 以下略
```

もう一回確認してプロジェクトが見えれば成功。

###Nginxの設定の変更
再び[EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする](https://qiita.com/xKxAxKx/items/da9dcc8caa36e1c303c7)を丸パクリ。本当にありがとうございました
/etc/nginx.confとあるが、Amazon Linuxでは/etc/nginx/nginx.confにあった。
以下引用
>/etc/nginx.confを以下の通り編集する

>```/etc/nginx.conf
>〜中略〜

>http {
>    〜中略〜
>
>    upstream app_server {
>        server 127.0.0.1:8000 fail_timeout=0;
    }

>    server {
        #以下4行はコメントアウト
        #listen       80 default_server;
        #listen       [::]:80 default_server;
        #server_name  localhost;
        #root         /usr/share/nginx/html;

>        # 以下3行を追加
        listen    80;
        server_name     IPアドレス or ドメイン;
        client_max_body_size    4G;

>        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

>        location / {
            # 以下4行を追加
            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;
        }

>    〜以下略〜
>```

nginxの再起動

```
$ service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]
```

Djangoを再びGunicornで立ち上げる

```
$ gunicorn your_project.wsgi --bind=0.0.0.0:8000
```

`http://(パブリックDNS)`で確認できたら成功。

##daemon化
今はコマンドからGunicornを起動しているだけなので、ログアウトしたら終了してしまう。そこでGunicornをデーモン化して常駐するようにしたい。
ただ色々な所を見ると、Surpervisorというツールでそれが可能なようだが、SurpervisorはPython3系に対応していないので2系の環境をもう一つ作れとのこと。んなアホな。
もうちょっと調べてみると、普通に-Dというオプションをつけるだけでデーモンとして起動できるらしい。

###起動

```
$ gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
```

終了するときは

```
$ ps -ef | grep gunicorn
root     17419     1  0 Oct07 ?        00:00:08 /root/.pyenv/versions/3.6.2/bin/python3.6 /root/.pyenv/versions/3.6.2/bin/gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
root     17422 17419  0 Oct07 ?        00:00:01 /root/.pyenv/versions/3.6.2/bin/python3.6 /root/.pyenv/versions/3.6.2/bin/gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
root     21686 21594  0 08:05 pts/0    00:00:00 grep --color=auto gunicorn
$ kill 17419
```

###スクリプトで起動
ただこのままだと毎回めんどくさいので、[シェルスクリプトでサーバーを起動、停止する](http://tokibito.hatenablog.com/entry/20120609/1339170074)にあるスクリプトを使わせてもらう。

>Flaskとかで作ったちょっとしたサーバーの起動/停止用のシェルスクリプト。
>gunicornでデーモン状態にしている。
>startで起動、stopで終了、restartでstop+start。

>```your_project.sh
>#!/bin/sh
>PROGNAME=`basename $0`
>BASEDIR=`dirname $0`
>PIDFILE=$BASEDIR/$PROGNAME.pid

>start() {
  echo "Starting server..."
  cd $BASEDIR
  gunicorn flaskhello:app -p $PIDFILE -D
}

>stop() {
  echo "Stopping server..."
  kill -TERM `cat $PIDFILE`
  rm -f $PIDFILE
}

>usage() {
  echo "usage: $PROGNAME start|stop|restart"
}

>if [ $# -lt 1 ];  then
  usage
  exit 255
fi

>case $1 in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    stop
    start
    ;;
>esac
>```

以下の`gunicorn flaskhello:app -p $PIDFILE -D`を
`gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D`に書き換える。

```
$ sh your_project.sh start   #起動
$ sh your_project.sh stop    #終了
$ sh your_project.sh restart #再起動
```

sshを切っても`http://(パブリックDNS)`が見えたら成功。ひとまず見えるようになった。

##staticファイルが見つからない
ただここまで追ってもcss,jsなどstaticファイルは見つかってないはず。以下で見えるようにする。
setting.pyのSTATIC_URL、STATIC_PATHは設定済みでローカルでは見える状態とする。
詳しい解説 -> [Django での static files の扱い方まとめ](http://hideharaaws.hatenablog.com/entry/2014/12/12/230825)

###staticファイルのコピー
manage.pyの上でstaticファイルを指定したディレクトリにコピー

```
$ python manage.py collectstatic
```

###nginx.confをいじる
nginx.confにstaticファイルのディレクトリを登録する。

```/etc/nginx/nginx.conf
server{
    # 〜中略〜
    location /static {
         alias /home/ec2-user/your_project/static;
         #settings.pyで設定したのと同じ場所を記述
    }
    # 〜以下略〜
}
```

###パーミッション変更
ここでnginxとgunicornを再起動する。

```
$ sh your_project.sh stop
Stopping server...
$ service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]
$ sh your_project.sh start
Starting server...
```

するととpermission deniedが出た。これはec2-userにotherからの権限がないせいだった。
[参考](http://blog.hotolab.net/entry/nginx_simple)によると、このディレクトリに移動する権限が必要らしい。
/home/でec2-userに権限を与える。

```
$ ls -l
drwx------  5 ec2-user ec2-user 4096 Oct  6 04:19 ec2-user
$ chmod o+x ec2-user
$ ls -l
drwx-----x  5 ec2-user ec2-user 4096 Oct  6 04:19 ec2-user
```

gunicornを再起動すると無事にstaticファイルにアクセスできて終了。


##参考
[EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする](https://qiita.com/xKxAxKx/items/da9dcc8caa36e1c303c7)
[EC2サーバにPython3環境構築](https://qiita.com/tisk_jdb/items/01bd6ef9209acc3a275f)
[シェルスクリプトでサーバーを起動、停止する](http://tokibito.hatenablog.com/entry/20120609/1339170074)
[Django での static files の扱い方まとめ](http://hideharaaws.hatenablog.com/entry/2014/12/12/230825)
[Nginxでつくる、どシンプルな静的コンテンツサーバ](http://blog.hotolab.net/entry/nginx_simple)