Amazon Linux2にPython3 -Django - mod_wsgi をインストール

#Pythonを使う案件が増えてきた！
プログラミング系の雑誌ではPythonがよく取り上げられていましたが、実案件でもPythonを使うことが増えてきました。
Pythonを使う大きな理由は、AI(機械学習)ライブラリが充実していることです。
今回もAIを使うのでPythonを使います。
WEBのアプリケーション・サーバー(中継?)としてはDjangoを使います。

また、インフラ側のクラウドはAWS(Amazon Web Service)です。
AWSを使う理由は。。。流行でしょうか。。。
他のクラウドでもいいと思うのですが、皆使っているという理由が多いような気が。。。

#EC2サーバーの準備
AWSのEC2インスタンス(仮想サーバー)を作成します。
あらかじめアプリケーションに特化したAMI(マシンイメージ)を選ぶこともでき、PythonやDjangoに特化したBitnami等のイメージも用意されているのですが、今回は一般的な、Amazon Linux2 (64bit版)を使い、Djangoをインストールします。
Amazon Linux2はCentOS7ベースに近いので、この記事はCentOS7での構築にも参考になると思います。
サーバーの構築からログインまで準備ができたという前提で進めます。

#サーバーの環境構築
まずはログインして環境設定です。
rootログインをしている状態での説明ですので、sudoを使う場合は適宜読み替えてください。
実行コマンドを羅列していますが、実行結果(表示出力されるテキスト)はカットしています。

Amazon Linuxの初期状態ではスワップファイルが無い状態ですので、スワップファイルを有効にします。

```
# fallocate -l 4096m /swapfile
# mkswap /swapfile
# swapon /swapfile
# chmod 600 /swapfile
```

起動時にスワップファイルが有効になるように、/etc/fstab の最終行に下記の行を追記します。

`/swapfile none swap sw 0 0`

タイムゾーンを日本標準時に設定します。

```
# timedatectl set-timezone Asia/Tokyo
```

念の為既存モジュールのアップデートと、epelレポジトリ、開発環境をインストールしておきます。

```
# yum -y update
# amazon-linux-extras install epel
# yum -y groupinstall "Development Tools"
```
# Python3のインストール
Pythonはver2系とver3系がありますが、今回のプロジェクトで使用するのはver3系です。
単純にver2系のPythonを削除やアップデートすればいいのでは～と思えますが、ver2系はOS標準のコマンドやスクリプトで多数使用されているため、削除したりアップデートしたりできません。

面倒でトラブルも多いのですが、今回はPython2(ver2系)とPython3(ver3系)を共存させて環境を構築します。

pyenvでPython環境を切り替える方法もあるのですが、Djangoで動作する時のみPython3が使えればいいので、今回はpyenvは使用しません。

それでは、Python3をインストールします。

```
# amazon-linux-extras install python3
# yum -y install python3-devel
```

これでPython3がインストールされました。
現時点でインストールされたバージョンはPython3.7.4でした。

これ以降、Python3を使う場合は、

```
# python3
```

Python3のパッケージのインストールをする場合は、

```
# pip3
```

を必ず使い、Python2とPython3を使い分けなくてはなりません。

Python3用にpymysqlモジュールをインストールします。

```
#pip3 install pymysql
```

エラーが出なければ問題ありません。

# Djangoのインストール

次にPythonをWEBサーバーで使用するために、アプリケーションフレームワークのDjangoをインストールします。
pymysqlモジュールが、最新のDjangoに対応していないということなので、バージョン2.1指定でインストールします。

```
# pip3 install django==2.1
```

正常にインストールされているのかと、Djangoのバージョンを確認するには

```
# python3 -m django --version
```

で確認できます。

#Djangoの動作テスト
任意の場所（今回は/var/www/cgi-bin)にDjangoのプロジェクトmyprojectを作成して動作テストを行います。

```
# cd /var/www/cgi-bin
# django-admin startproject mysite
# cd mysite
```

カレントディレクトリ(例では/var/www/cgi-bin)以下に、mysiteというプロジェクトディレクトリが作成されます。
プロジェクトディレクトリのmysiteディレクトリ以下にある、setting.pyの１行を修正("*"の追加)してデフォルトのアクセス制限を外します。

```python:mysite/settings.py
ALLOWED_HOSTS = ["*"]
```

プロジェクトディレクトリ内で、以下のコマンドを実行し、Djangoの内部WEBサーバーを起動します。

```
# python3 manage.py runserver 0.0.0.0:8000
```

データベースの設定をしていないので、migrateしていないとかの警告が出ますが、Djangoのインストールと動作確認だけ進めていますので、後回しにして無視します。

それではPCのブラウザのアドレス欄に下記を入力します。

> http://サーバーのIPアドレス:8000

以下のようにブラウザでDjangoの画面が出れば正常です。

![Image1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59033/c88e3e6b-f0ed-feb5-9b5a-033677275426.jpeg)

タイムアウトなどが起こる場合、ファイアーウォール(AWSではセキュリティグループのインバウンド)でポート8000を通すようにして下さい。
8000の部分を80に変更すれば、ポート80のhttpに変更できますが、Apacheなどが先に起動していると衝突してエラーになります。

Webサーバーを停止するには、CONTROLキーとCを同時に押します。

ここまででDjangoがインストールして正常に動作しているのを確認できました。

# Apacheとの連携 mod_wsgi
Djangoの内部Webサーバーでの動作は確認できましたが、実際にサービスとして使う場合はApacheやnginx等のWebサーバーを使用します。
今回はApacheを使いますが、WebサーバーとDjangoの橋渡しをするのが、mod_wsgiモジュールです。

Apache(httpd)とmod_wsgiをインストールします。

```
# yum install -y httpd httpd-devel
# pip3 install mod_wsgi
# pip3 install mod_wsgi-httpd
```

wsgiのApacheモジュールが作成されましたが、どこにモジュールが生成されたのか表示されないので探します。

> find /usr -name "mod_wsgi*.so"

モジュールを見つけたら、新規に作成する /etc/httpd/conf.d/wsgi.conf　ファイルの１行目で読み込みの指定をします。

```conf:/etc/httpd/conf.d/wsgi.conf
LoadModule wsgi_module /usr/local/lib64/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so

WSGIPythonHome /usr
WSGIScriptAlias / /var/www/cgi-bin/mysite/misite/wsgi.py
WSGIPythonPath /var/www/cgi-bin/mysite:/var/www/cgi-bin/mysite/mysite:/usr/lib/python3.7/site-packages:/usr/lib64/python3.7/site-packages:/usr/local/lib/python3.7/site-packages:/usr/local/lib64/python3.7/site-packages

<Directory /var/www/cgi-bin/mysite/mysite>
  Options ExecCGI MultiViews Indexes
  MultiViewsMatch Handlers
  AddHandler wsgi-script .py
  AddHandler wsgi-script .wsgi
  DirectoryIndex index.py app.wsgi　index.html 
  Order allow,deny
  Allow from all
  <Files wsgi.py>
    Require all granted
  </Files>
</Directory>
```

このファイルを作成したら、反映させるためにApacheを再起動します。
自動起動設定にしていなければ、ここでApacheの自動起動設定をします。

```
# systemctl restart httpd
# systemctl enable httpd.service
```

PCのブラウザのアドレス欄に下記を入力します。今回はポート80なのでポート指定はしません。

> http://サーバーのIPアドレス

![Image1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59033/d2ed98cd-5e80-ab04-c9b3-c6ecd159f14f.jpeg)

Djangoのページが表示されれば正常です。

タイムアウトになる場合はポート80のファイアーウォールの確認、Internal Server Errorの表示場合は、Apacheのエラーログを確認して下さい。

# Pythonプログラムファイルやモジュールのパスに注意

ここまでのインストールの道のりは簡単そうですが、実はかなり試行錯誤しています。
ともかく、Pythonはパスが重要だと再認識しました。ファイルを置いてあるパスやモジュールのパスです。

当記事では、毎度sudoを使って説明するのが面倒なので、rootユーザーで記述説明しています。

実際のインストールや開発には管理者でない一般ユーザーでログインし、sudoを使いインストールや、インストール後にライブラリモジュール等の
インストールをしています。

このモジュールのパスがApache/wsgiから認識されない、あるいはApacheの読み取り権限が無い等に気づかずはまりました。
Apacheのプロセスはapacheユーザー権限にて起動しているので、コマンドライン環境とも異なります。

結果として、wsgi.confファイルの、WSGIPythonPath に、この後多数のパスを追加することになりました。