EC2のUbuntuにDjangoアプリを設置したときの手順

DjangoのWebサーバとSqliteを使って開発していたものを、AWS EC2のUbuntu 18.04.1 LTS上でNginx、Gunicorn、PostgreSQLを使って動かしたときの手順です。
極力コピペで作業できる様に記載してみました。

なお、EC2のインスタンスは生成済みなものとします。

この後さらに独自ドメイン、SSL化する手順は[こちら](https://qiita.com/moto2g/items/e6454a51d61570948171)

# 全体の流れ
下記のような流れで作業します。
- 外部からAWSのEC2へ通信できるよう必要なポートを開く。
- Python、PostgreSQLなど、必要なパッケージをUbuntuにインストールする。
- Django、Gunicornなど、必要なモジュールをPythonの仮想環境にインストールする。
- PostgreSQL上に、Djangoアプリ用のDBを作成する。
- Djangoプロジェクトのソースを配置し、本番環境にあわせて修正する。
- GunicornからDjangoアプリを実行できるように設定する。
- WebアクセスをNginxで受け取り、Gunicornへ連携できるように設定する。
- 不要なポートを閉じる。


# AWSのポートを開く
EC2のネットワーク＆セキュリティで、該当するセキュリティグループのインバウンドに80、8000を追加する。

タイプ：カスタムTCP
プロトコル：TCP
ポート範囲：8000
ソース：0.0.0.0/0
※確認に使うだけで後で閉じる。

タイプ：HTTP
プロトコル：TCP
ポート範囲：80
ソース：0.0.0.0/0, :://0


# 必要なパッケージのインストール
## Ubuntu側

```shell
sudo apt-get update
sudo apt-get install python3-pip python3-dev python3-venv libpq-dev postgresql postgresql-contrib nginx
```

## Python側
今回はPythonの仮想環境を作成してインストールする。

```shell
# pipを最新化
sudo -H pip3 install --upgrade pip
# 仮想環境の作成と適用
python3 -m venv 仮想環境名
source 仮想環境名/bin/activate
# モジュールのインストール
pip install django gunicorn psycopg2where
```

# PostgreSQLの設定
PostgreSQLにDjangoプロジェクト用のDB、ユーザーを作る。

```shell
sudo -u postgres psql
```

```SQL
CREATE DATABASE Djangoプロジェクト用のDB名;
CREATE USER DBのユーザ名 WITH PASSWORD 'パスワード';
ALTER ROLE DBのユーザ名 SET client_encoding TO 'utf8';
ALTER ROLE DBのユーザ名 SET default_transaction_isolation TO 'read committed';
ALTER ROLE DBのユーザ名 SET timezone TO 'UTC+9';
GRANT ALL PRIVILEGES ON DATABASE DB名 to DBのユーザ名;
\q
```

PostgreSQLが動作していることを確認

```shell
$ ps aux
# postgresが出ていればOK
```

# Djangoプロジェクトの設定
SCPやGitコマンドなどでDjangoプロジェクトのファイル群をUbuntuにアップロードする。

ソースファイルは本番環境向けにしておく。少なくともsettings.pyは開発用から書き換えることになるはず。

```py:settings.py
DEBUG = False # Falseにする

ALLOWED_HOSTS = ['xxx.xxx.xxx.xxx'] # サーバのIPアドレスを記載

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # 変更
        'NAME': 'Djangoプロジェクト用のDB名', # 変更
        'USER': 'DBユーザ名', # 追加
        'PASSWORD': 'DBユーザのパスワード', # 追加
        'HOST': 'localhost', # 追加
        'PORT': '', # 追加
    }
}
```

マイグレーション、管理者ユーザの追加、staticファイルの収集を実施する。

```shell
cd Djangoプロジェクトのフォルダ
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py collectstatic
```

# Gunicornの設定
GunicornからDjangoアプリが動くことを確認するため、Ubuntuのファイアウォール設定でポート8000を開く。
後でNginxでstaticフォルダを設定するので、この時点でstaticファイルにアクセスできないのは問題ない。

```shell
sudo ufw allow 8000
cd Djangoプロジェクトのフォルダ
gunicorn --bind 0.0.0.0:8000 プロジェクト名.wsgi
# クライアントのブラウザからアクセスしてみる
```

Gunicornを終了してから仮想環境を抜け、Gunicornをdaemonとして動作させるための設定ファイルを作成する。

```shell
deactivate
sudo nano /etc/systemd/system/gunicorn.service
```

```
[Unit]
Description=gunicorn daemon
After=network.target
 
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=プロジェクトフォルダへのフルパス
ExecStart=仮想環境フォルダへのフルパス/bin/gunicorn --access-logfile - --workers 3 --bind unix:プロジェクトフォルダへのフルパス/プロジェクト名.sock プロジェクト名.wsgi:application
 
[Install]
WantedBy=multi-user.target
```

Gunicornを起動し、エラーが出ていないことを確認する。エラーが出ている場合は設定ファイルを見直す。

```shell
sudo systemctl start gunicorn
sudo journalctl -u gunicorn
# ジャーナル表示から抜ける時は'q'を入力する
```

エラーが出ていなければGunicornを自動起動にする。

```shell
sudo systemctl enable gunicorn
```

（参考）自動起動の設定後に設定ファイルを修正したらdeamon-reloadする。

```
sudo systemctl daemon-reload
sudo systemctl restart gunicorn
```

# Nginxの設定
Nginxのsites-availableにDjangoアプリ用の設定ファイルを作成する。

```shell
cd /etc/nginx/sites-available/
sudo nano プロジェクト名
```

```
server {
   listen 80;
   server_name IPアドレス;
 
   location = /favicon.ico { access_log off; log_not_found off; }
   location /static/ {
       root プロジェクトフォルダまでのフルパス;
   }
 
   location / {
       include proxy_params;
       proxy_pass http://unix:プロジェクトフォルダまでのフルパス/プロジェクト名.sock;
   }
}
```

Nginxのsites-enabledに上記で作成した設定ファイルへのシンボリックリンクを作成してテストする。

```shell
sudo ln -s /etc/nginx/sites-available/プロジェクト名 /etc/nginx/sites-enabled
sudo nginx -t
```

OKならNginxを再起動する。
Ubuntuのファイアウォール設定でポート8000を閉じ、Nginxの通信を許可する。

```shell
sudo systemctl restart nginx
sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'
sudo systemctl restart gunicorn
```

クライアントのブラウザからアクセスできることを確認する。
今後、設定ファイルを書き換えたら、Nginx、Gunicornを再起動する。

# AWSのポートを閉じる
最初に開いたポートのうち、8000はもう使わないので設定から削除する。

以上で作業完了。

#最後に
アクセスできるのに上手く動かない時はNginx、Gunicornのログを調査してみる。

```shell
sudo journalctl -u nginx
sudo less /var/log/nginx/access.log
sudo less /var/log/nginx/error.log
sudo journalctl -u gunicorn
```

# 参考
[DigitalOcean - How To Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 18.04](https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-18-04)