EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする

Nginx + Gunicorn + Supervisorの組み合わせでDjangoアプリケーションを立ち上げたので手順のメモ
今回はOSに何も入っていない状態から始めていきます

## 環境
OS: Amazon Linux AMI
Python: 3.6.1
Django: 1.11.4
Nginx: 1.10.3
Gunicorn: 19.7.1
Supervisor: 3.3.3

## Nginxのインストール
nginxのインストール

```
$ sudo yum install nginx
```

nginx起動する

```
$ sudo nginx
``` 

nginx自動起動設定

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

自動起動設定確認
以下のようになっていればok

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

`http://ipアドレス`にアクセスしちゃんと起動しているか確認する
以下の通りになっていればOK
![スクリーンショット 2017-08-03 13.40.56.png](https://qiita-image-store.s3.amazonaws.com/0/80787/7b6831a9-3af3-f5f1-7df0-bb6b933c8ea6.png "スクリーンショット 2017-08-03 13.40.56.png")


## Python環境の構築
今回はAnacondaで構築した
[こちら](https://www.continuum.io/downloads)からPython 3.6 versionをダウンロードする
ダウンロードしたパッケージをCyberduckなどのFTPツールで/home/ec2-userにアップロードする

アップロード完了したら下記コマンドでAnacondaインストールする

```
$ bash Anaconda3-4.4.0-Linux-x86_64.sh
```

インストール完了後、Anacondaのコマンドが使えるようにPATHを通す

```
$ export PATH="$PATH:/home/ec2-user/anaconda3/bin"
```

condaのコマンドを打って確認

```
$ conda info -e
# conda environments:
#
root                  *  /home/ec2-user/anaconda3
```
良さげです

なお、annacondaインストール時にbashrcに環境変数の設定を追加していると

```
Do you wish the installer to prepend the Anaconda3 install location
to PATH in your /root/.bashrc ? [yes|no]
[no] >>> yes
```

ルート環境のpythonも3.6になっている

```
$ python --version
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
```


## Djangoプロジェクトの作成
今回は直接EC2上でプロジェクトを作成します
本来はローカルで開発したDjangoアプリケーションをgit cloneすべき
また、DBもデフォルトのSQliteを使用しますが、実際のサービスを公開するにはPostgresqlやMariaDBを使う

まずはDjangoのインストール
root環境で動かすかどうかは少し議論の分かれるところで、別に環境を作ってDjangoを動かした方がいいんじゃないか、と思ったりもしますが、とりあえず今回はroot環境でインストールしてしまいます

```
$ pip install django
```

問題なければプロジェクトを作成

```
$ django-admin startproject test_project
```

プロジェクトが作られていることを確認

```
$ ls -ltr
total 511032
-rw-rw-r--  1 ec2-user ec2-user 523283080 Aug  3 04:50 Anaconda3-4.4.0-Linux-x86_64.sh
drwxrwxr-x 20 ec2-user ec2-user      4096 Aug  3 04:53 anaconda3
drwxrwxr-x  3 ec2-user ec2-user      4096 Aug  3 05:05 test_project
```

`/test_project/test_project/settings.py`のALLOW HOSTを下記の通り編集しておく

```python:settings.py
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ["サーバのIPアドレス"]
```

下記のコマンドでDjangoを起動
デフォルトだと127.0.0.1:8000がbindアドレスとして使用されているため、オプションで`0.0.0.0:8000`を追加する必要があります
また、事前にAWSのセキュリティグループで8000番ポートを解放しておく必要があります

```
$ cd test_project
$ python manage.py runserver 0.0.0.0:8000
```

そして、`http://IPアドレス:8000`にアクセスすると以下の通りDjangoアプリケーションにアクセスできる
![スクリーンショット 2017-08-03 15.23.25.png](https://qiita-image-store.s3.amazonaws.com/0/80787/a24a1742-15ee-67ba-c295-eeda4ec1cff2.png "スクリーンショット 2017-08-03 15.23.25.png")


## Gunicornのインストール
GunicornはPython製のWSGIサーバ
WSGIサーバというのはWebサーバとWebアプリケーションをつなぐサーバのこと
なので、`Nginx <-> Gunicorn <-> Django`というような構成をイメージしていただければと

まずはGunicornのインストールをやっていく

```
$ pip install gunicorn
```

インストールされたらGunicornでDjangoを起動させる

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

先程と同様、`http://IPアドレス:8000`にアクセスするとDjangoアプリケーションに接続できる
なお、settings.pyを本番用とか開発用で分けている場合は以下のような感じで

```
$ gunicorn test_project.wsgi.wsgi --env DJANGO_SETTINGS_MODULE=test_project.settings_dev --bind=0.0.0.0:8000
```


## Nginxの設定の変更
/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を再起動する

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

これでNginxでのリバースプロキシの設定は完了
今回はnginx.confを直接編集したけれど、設定ファイルをどこか別のところに書いてそれを読み込ませる、という方法でもOK

その後、DjangoをGunicornで立ち上げる

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

次は`http://IPアドレス`にアクセスするとDjangoの画面が表示されるはず

## Supervisorでプロセスをデーモン化する
今の状態だとGunicornのコマンドを中止したり、サーバからログアウトするとアプリケーションが停止してしまう
これを解消するためにSupervisorでGunicornのプロセスをデーモン化する

早速、Supervisorをインストール、としたいところだけれど、SupervisorはPython2系でしか動作しない
そのためAnacondaでPython2系の仮想環境を構築し、その環境にSupervisorをインストールしていく

まずは下記コマンドでSupervisor用のPython2系の仮想環境を作る

```
$ conda create -n supervisor python=2.7
```

python2系の環境に切り替えてpipでsupervisorをインストール

```
$ source activate supervisor
$ pip install supervisor
```

問題なくインストールできたら、supervisorの設定ファイルを作成し、それを/etc配下に配置する

```
$ echo_supervisord_conf > supervisord.conf
$ sudo mv supervisord.conf /etc
```

次にsupervisorの設定を行うため、supervisord.confを下記の通り編集

```supervisord.conf
〜中略〜
[supervisord]
logfile=/var/log/supervisord.log ; ログの場所を変更
;logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log #コメントアウト
logfile_maxbytes=50MB        ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10           ; # of main logfile backups; 0 means none, default 10
loglevel=info                ; log level; default info; others: debug,warn,trace
pidfile=/var/run/supervisord.pid ; 追記
;pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid #コメントアウト

〜中略〜
# includeはコメントアウトされているのでコメント外す
[include]
files = supervisord.d/*.conf ; 起動するプロセスのconfファイルの配置場所
;files = relative/directory/*.ini
```

ログファイルは作っておき、パーミッションも設定しておく

```
$ sudo touch /var/log/supervisord.log
$ sudo chown ec2-user /var/log/supervisord.log
$ sudo chgrp ec2-user /var/log/supervisord.log
$ sudo chmod 774 /var/log/supervisord.log
```

あと、ログローテションも設定しておく

```
$ sudo sh -c "echo '/var/log/supervisord.log {
       missingok
       weekly
       notifempty
       nocompress
}' > /etc/logrotate.d/supervisor"
```

次にデーモン化するプロセスのコマンドを記載したファイルを作っていく
まずはそれらのファイルを配置するディレクトリを作成

```
$ sudo mkdir /etc/supervisord.d
```

/etc/supervisord.d配下にdjango_app.confを作成
ここに、Gunicornのプロセスをデーモン化するための設定を以下のように書く

```django_app.conf
[program:django_app]
directory=/home/ec2-user/test_project
command=gunicorn test_project.wsgi --bind=0.0.0.0:8000
numprocs=1
autostart=true
autorestart=true
user=ec2-user
redirect_stderr=true
```

directoryに実行するディレクトリを指定、commandのところにプロセスを起動するためのコマンドを指定する

ここまでできたら下記のコマンドでsupervisorを立ち上げる

```
$ supervisord
```

次に、confファイルを読み込ませる
こちらは仮にconfを修正などする場合は必ず実行する

```
$ supervisorctl reread
```

なお、下記のコマンドでデーモンを再起動し、そのタイミングでもconfが読み込まれたりする

```
$ supervisorctl reload
```

下記のコマンドでGunicornのプロセスをデーモン化する

```
$ supervisorctl start django_app
```

仮に`django_app: ERROR (already started)`というメッセージが出た場合は、以下のコマンドでプロセスの再起動をしたり、停止をしてからstartしたりする

```
$ supervisorctl stop django_app # 停止
$ supervisorctl restart django_app # 再起動
```

さて、この状態でサーバからログアウトしてみる
そして、`http://IPアドレス`にアクセスすると、Djangoの画面が表示される
GunicornのプロセスがSupervisorによりデーモン化されていることになる

よかったですね