AWSのEC2(+RDS(+S3))でDjangoアプリケーション(+MySQL)を公開するまで

AWSのEC2インスタンスとRDSインスタンスがある状態からどうすればDjango+Apache(+mod-wsgi)+MySQLでWebアプリを公開できるかです．Webアプリプログラムはあるものとします．なお，情報は2020/1/1時点です．

また，pyenv+Anacondaを使っていますが，この辺はPythonをyum installするとか今時Pipenv使うでしょとかは各自の宗教に合わせてください．

# 使用したバージョンなど
## Python関係
- Python 3.7.4 (anaconda3-2019.10 使用)
- pyenv 1.2.15-9-gac246e16
- Django                             3.0.1    
- django-el-pagination               3.2.4    
- django-maintenance-mode            0.14.0   
- django-storages                    1.8
- mod-wsgi                           4.7.0
- mysqlclient                        1.4.6 

## Apache，MySQL Client

```bash
$ httpd -v
Server version: Apache/2.4.41 ()
Server built:   Oct 22 2019 22:59:04
$ mysql --version
mysql  Ver 8.0.18 for Linux on x86_64 (MySQL Community Server - GPL)
```

MySQLはバージョン8.0系を使っています．

# pyenvとPython3のインストール
## pyenvのインストール
デフォルトのpythonは汚したくない．

```bash
sudo git clone git://github.com/yyuu/pyenv.git /usr/local/pyenv
% 所有者がsudoはやだ．再帰的に変えてしまう
sudo chown -r ec2-user:ec2-user pyenv
```

`~/.bash_profile` を書き換え

```bash
export PATH
export PYENV_ROOT="/usr/local/pyenv"
export GOPATH="$HOME/.go"
export PATH="$GOPATH/bin:$PYENV_ROOT/bin:$PYENV_ROOT/bin/pyenv:$PATH"
eval "$(pyenv init -)"
```

書き換えたら `source .bash_profile` して読み込む．

##Python3のインストール
楽したいのでanacondaいれちゃう．宗教戦争には関わらないです．condaでのインストールは絶対に使わないけど．

```bash
# 執筆時点の最新安定版
pyenv install anaconda3-2019.10
# デフォを変える
pyenv global anaconda3-2019.10
```

# Djangoの導入
これは簡単．ただDjangoのバージョンには要注意．後方互換性のない変更もしばしば．

```bash
pip install django
```

その他便利なやつ

```bash
% ファイルを扱う
pip install django-storages
% メンテナンスモード
pip install django-maintenance-mode
% s3を扱う
pip install boto3
```

# ウェブサーバ導入
ウェブサーバ導入します．目指せapache+mod-wsgi．

## apacheのインストール

```bash
sudo yum install httpd
sudo systemctl start httpd
# 確認するなら
sudo systemctl status httpd
# サービスのスタート
sudo systemctl start httpd.service
```
グローバルIPを指定すればApacheテストページが表示される

Apacheテストページではないものにしたいなら， `/etc/httpd/conf/httpd.conf` 内を書き換え．

参考にしたページ:
https://qiita.com/saki-engineering/items/5ea8e66b498fc7d4a399
https://miyabi-lab.space/blog/16#200

## mod-wsgiの導入
Pythonとapacheをつなぐツール．

インストールのためのコンパイル時にapexとgccが必要になるが，デフォルトでは入っていない．

```bash
sudo yum install httpd-devel
sudo yum install gcc
```

こうすればpipでmod-wsgiは入る

```bash
pip install mod_wsgi
```

## 連携させる
以下はDjangoで公開するページがある前提．サンプル的なものでも可．

一部参考にしたページ: https://qiita.com/saki-engineering/items/5ea8e66b498fc7d4a399

mod-wsgiの入っている場所を探す．ルートディレクトリに移動してから

```bash
$ find -name 'mod_wsgi*.so' 2> /dev/null
./usr/local/pyenv/versions/anaconda3-2019.10/lib/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so
```
よって `/usr/local/pyenv/versions/anaconda3-2019.10/lib/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so` にある．

Amazon Linux 2なら多分 `/etc/httpd/conf/httpd.conf` の最後に

```conf
# Load config files in the "/etc/httpd/conf.d" directory, if any.
IncludeOptional conf.d/*.conf
```
と書いてあるはずなので， `/etc/httpd/conf.d/myconf.conf` に

```conf
LoadModule wsgi_module /usr/local/pyenv/versions/anaconda3-2019.10/lib/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so

WSGIScriptAlias / (wsgi.pyの置いた場所)
WSGIPythonPath (Djangoで書いたwebappプログラムのルートディレクトリ)
WSGIPythonHome (実行したいPythonの実行ファイルの親ディレクトリ; 例: /usr/local/pyenv/versions/anaconda3-2019.10)
Alias /static/ (Djangoで書いたwebappプログラムのstaticファイルのディレクトリ)

<Directory (Djangoで書いたwebappプログラムのルートディレクトリ)>
    <Files wsgi.py>
        Order deny,allow
        Require all granted
    </Files>
</Directory>
<Directory (Djangoで書いたwebappプログラムのstaticファイルのディレクトリ)>
    Require all granted
</Directory>
```
とかく． `sudo service httpd restart` する．

前やったときは `WSGIPythonPath` を指定しなくてよかったのですがなぜでしょう…

# MySQLの導入
RDSですでにMySQL8.0のサーバ立ち上げ済みとします．

MySQL 8.0用のクライアントを入れる
参考にしたページ: https://dev.classmethod.jp/cloud/aws/amazon-linux2-mysqlclient/

```bash
# リポジトリ追加
$ sudo yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
# 標準の状態で8.0の設定ですが一応有効に
$ sudo yum-config-manager --enable mysql80-community
# Mysql Client Install
$ sudo yum install -y mysql-community-client
$ mysql --version
mysql  Ver 8.0.18 for Linux on x86_64 (MySQL Community Server - GPL)
```

# サーバ始動

```bash
$ whereis mysql_config
mysql_config:
```

実はこの時点では `mysql_config` がないと怒られる．

```bash
$ sudo yum install mysql-devel
```
すると

```bash
$ whereis mysql_config
mysql_config: /usr/bin/mysql_config /usr/share/man/man1/mysql_config.1.gz
```

そしてPythonからmysqlクライアントにアクセスするためにpipでインストール

```bash
pip install mysqlclient
```

#無限ページネーションしたい
```bash
$ pip install django-el-pagination
```
で入るやつは古かった．2年くらいリリースされていない．じゃあgitから落とせばいい（メンテナンスはきちんとされていてDjango3.0にもすぐに対応されている）

```bash
$ git clone https://github.com/shtalinberg/django-el-pagination.git
$ cd django-el-pagination/
$ pip install -e .
```

しかし，これでやっても動こうとするが，webサイトにアクセスできない． `ModuleNotFoundError el_pagination` となってしまう．リンクがうまく張られないことが原因？それともeditableモードなのが原因？

じゃあgitから直接pip installしよう．

```bash
pip install git+https://github.com/shtalinberg/django-el-pagination.git
```
これでできた．

その他の必要な設定(settings.py)は
https://django-el-pagination.readthedocs.io/en/latest/start.html
を参照．

#swap領域の確保
EC2インスタンスのデフォルトのメモリのサイズはありえないほど小さいので必須．

```bash
$ sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
2048+0 レコード入力
2048+0 レコード出力
2147483648 バイト (2.1 GB) コピーされました、 31.4376 秒、 68.3 MB/秒
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
スワップ空間バージョン 1 を設定します。サイズ = 2 GiB (2147479552 バイト)
ラベルはありません, UUID=82de405a-d7ef-4ae3-ba93-16baa38c6e2c
$ sudo swapon /swapfile
# 確認
swapon -s
ファイル名				タイプ		サイズ	使用済み	優先順位
/swapfile                              	file    	2097148	0	-2
# 起動時にswap領域が有効になるように
$ sudo vi /etc/fstab
# 追加
# /swapfile swap swap defaults 0 0
```

参考: https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-memory-swap-file/

#検索避け
`/var/www/html/robots.txt` に

```
User-agent : *
Disallow : /

```
を作成，保存する