Django+Apache2+mod_wsgiでのWebサーバ構築手順

# はじめに

DjangoでつくったWebアプリをApache上で公開する際にmod_wsgiの設定を行いますが、毎回手順を忘れるので改めて整理しました。

# 実施手順

## Djangoの実行環境を用意する

venvの仮想環境上にDjangoをインストールして、開発を行う準備をします。

```shell
# python関係のパッケージをインストール
# devのインストールにはマイナーバージョンまで指定する必要があるので注意
sudo apt install python3-venv python3.8-dev

cd ~
mkdir django
cd django
python3 -m venv venv
source venv/bin/activate
pip install wheel django mod_wsgi
```

仮想環境上にはdjangoの他に、後々ApacheでDjangoを動作させるために必要なmod_wsgiをインストールしています。

mod_wsgiについてはWikipedia先生などの外部サイト参照。簡単に整理すると、PythonのWebアプリケーションフレームワークにはDjango他にFlaskなど様々存在しますが、それらのインタフェースを標準化してくれるもので、mod_wsgiを使うことでフレームワークの種類を気にすることなくApacheなどWebサーバ上で動作させられるようになるもの、と理解しています。

https://ja.wikipedia.org/wiki/Mod_wsgi

> mod_wsgiとは、WSGI (Web Server Gateway Interface) インターフェースに準拠した PythonのプログラムをApache HTTP Serverで動作させるためのモジュールである。

## DjangoでWebアプリを開発する

Apacheやmod_wsgiとは関係のない世界ですが、一応残しておきます。ここではプロジェクト名を`alice`、アプリ名を`artemis`とします。

```shell
django-admin startproject alice
cd alice
```

デフォルトのフォルダ名だとわかりにくいので、プロジェクトの中の`alice`ディレクトリを`config`にリネームしておきます。リネームしたことでパスが変わるので、以下のファイルの`alice.*`などとなっているところを、`config.*`にリネームします。

- `manager.py`
- `config/asgi.py`
- `config/settings.py`
- `config/wsgi.py`

初期設定が終わったら、`startapp`でアプリを開発していきます。

```shell
python manager.py startapp artemis
```

アプリ用の`urls.py`を作成し、ルートとアプリのURLConfを編集しておきます。`IndexView`は`views.py`に作成した適当なviewです。

```python:artemis/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.IndexView.as_view(), name="index"),
]
```

```python:config/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include("artemis.urls")),
]
```

最後に、`settings.py`を編集し、開発したアプリの登録と外部公開のために必要な設定を行います。

```python:config/settings.py
・・・
DEBUG = False

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'artemis.apps.ArtemisConfig',
    ・・・
]

・・・

LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

STATIC_ROOT = os.path.join(BASE_DIR, 'static')
```

## 静的コンテンツを集積する

開発が完了したら、静的コンテンツ（.jpg、.js、.cssなど）を1つのディレクトリに集積します。

Djangoには`collectstatic`コマンドが用意されており、こちらを使うと`settings.py`の`STATIC_ROOT`で指定したディレクトリに各アプリで使用している静的コンテンツを自動的に集積してくれます。

```shell
cd [プロジェクトディレクトリ]
mkdir static
python manage.py collectstatic
```

## Apache2をインストールする

aptでApache2をインストールします。

```shell
sudo apt install apache2 apache2-dev
```

今回はHTTPのポートとして8000を使用します。apacheの設定でリクエストを受け付けるポートを変更し、ファイアウォールも8000を開放しておきます。

```shell
sudo nano /etc/apache2/ports.conf
# - Listen 80
# + Listen 8000
sudo ufw allow 8000/tcp
sudo ufw enable
```

## mod_wsgiの設定を変更する

djangoの仮想環境に入って`mod_wsgi-express`コマンドを実行し、出力を控えておきます。あとでmood_wsgiの設定ファイルに貼り付けます。

```shell
source ~/django/venv/bin/activate
mod_wsgi-express module-config
# LoadModule wsgi_module "/home/vboxuser/django/venv/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so"
# WSGIPythonHome "/home/vboxuser/django/venv"
```

次に、Apacheで実行するアプリケーションの設定ファイルを作成します。デフォルトの設定ファイル`000-default.conf`があるのでこちらをコピーして使います。

```shell
cd /etc/apache2/sites-available
sudo cp 000-default.conf alice.conf
sudo nano alice.conf
```

設定内容は以下です。

```shell
# 先程控えたmod_wsgi-expressの出力を貼り付ける
LoadModule wsgi_module "/home/vboxuser/django/venv/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so"
WSGIPythonHome "/home/vboxuser/django/venv"

<VirtualHost *:8000>
# Djangoのwsig.pyのパスを記述する
WSGIScriptAlias / /home/vboxuser/django/alice/config/wsgi.py
# 仮想環境のホームディレクトリとPYTHONPATHを指定する
# processとthreadsにはApacheで起動するプロセス数とスレッド数を指定する
# display-nameにはtopやpsで確認するための起動プロセス名を指定する
WSGIDaemonProcess alice_http python-home=/home/vboxuser/django/venv python-path=/home/vboxuser/django/alice:/home/vboxuser/django/venv/lib/python3.8/site-packages processes=2 threads=2 display-name=alice
WSGIProcessGroup alice_http

# Djangoのconfigディレクトリを指定する
<Directory /home/vboxuser/django/alice/config>
  <Files wsgi.py>
    Require all granted
  </Files>
</Directory>

# 静的コンテンツがある場合のみ
# collectstaticで集積したディレクトリを指定する
Alias /static/ /home/vboxuser/django/alice/static/
<Directory /home/vboxuser/django/alice/static>
  Require all granted
</Directory>        
</VirtualHost>
```

最後に、デフォルトのアプリ`000-default`の設定ファイルを無効にし、作成した`alice.conf`を有効化します。

```shell
sudo a2dissite 000-default
sudo a2ensite alice
sudo systemctl restart apache2.service
sudo systemctl enable apache2.service
```

## 動作確認

Webブラウザから[http://localhost:8000](http://localhost:8000)にアクセスして動作確認します。また、[http://localhost:8000/admin/](http://localhost:8000/admin/)ではcssなど集積した静的コンテンツも読み込めていることが確認できます。

```shell
ps -ax | grep alice
   3320 ?        Sl     0:00 alice             -k start
   3321 ?        Sl     0:00 alice             -k start
```

起動しているプロセスを`ps`コマンドで確認すると、`alice.conf`で指定した通り2プロセスが`alice`のプロセス名で起動していることがわかります。

# 参考

https://www.51weblab.jp/web/deploy_django_project_with_apache_mod_wsgi_of_wsl