Edited at

Django事始め: 3_Apache連携

More than 1 year has passed since last update.


目次

Django事始め: 1_環境構築

Django事始め: 2_プロジェクト作成

Django事始め: 3_Apache連携

Django事始め: 4_MySQL連携

前回は開発用簡易サーバでDjangoの起動をブラウザから確認しました。

後々公開することを考えるとapacheなどのウェブサーバと連携する必要があります。

ここではApache + mod_wsgi + Djangoという形にします。

公式でもオススメされている方法です。

Django を Apache と mod_wsgi とともに使うには?

ただ、いろいろウェブで調べましたが中々うまくいかず大変なところでした。

多分他の人がこの記事を読んでもきっとどこかでハマるんだと思います。

うまくいかない時は一度公式を読むことをお勧めします。しんどいですが、一次情報が一番確実です。

mod_wsgi公式

ではなるべく細かく書き残しておきます。


環境


  • CentOS 7.1

  • Apache 2.4.6

  • pyenv 1.0.7

  • anaconda 3-4.3.0

  • django 1.10.5

  • mariadb-5.5.52


ちょこっと解説


Apacheとは

ウェブサーバです。多分一番使われてます。

デフォルトではPythonを解釈する機能が付いていないので、別途カスタマイズする必要があります。


mod_wsgiとは

wsgiはウィズギーと読むらしいです。

Apacheのモジュールで、Pythonを実行できるようにしてくれます。


Apacheインストール

サーバにapacheが入っていなければまずインストールします。

yum install httpd httpd-devel

systemctl start httpd
systemctl enable httpd

念のためブラウザにIPアドレス打ってapacheが動いているか確認しましょう。


mod_wsgiインストール

インストール時にPythonと紐付ける必要があります。

pyenvを使っている場合はそれを伝えないといけません。

うっかりyumで手軽にインストールしたら組み込みのPythonと紐付いて、結局やり直しになるので注意どころです。

ソースをダウンロード、展開します。

wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.5.14.tar.gz

tar -zxvf 4.5.14.tar.gz
cd mod_wsgi-4.5.14/

*自分がプロジェクトで使いたいPythonのパスを指定します!

pyenvの場合はpyenv/versions/ 以下にダウンロードしたPythonが入っています。

anaconda3-4.3.0を使いたい場合は以下のように指定します。バイナリファイルを指定する必要があります。

./configure --with-python=/usr/local/bin/pyenv/versions/anaconda3-4.3.0/bin/python

make
make install


mod_wsgiインストールエラー

以下のようなエラーが出ることがあります。

/bin/ld: /usr/local/bin/pyenv/versions/3.6.0/lib/libpython3.6m.a(abstract.o): relocation R_X86_64_32S against `_Py_NotImplementedStruct' can not be used when making a shared object; recompile with -fPIC

この場合はPythonを再コンパイルする必要があります。

CONFIGURE_OPTS="--enable-shared" CFLAGS="-fPIC" pyenv install X.X.X

その後改めてインストールします。一旦make cleanで設定をリセットします。

make clean

./configure CFLAGS=-fPIC --enable-shared
make
make install


Apache設定

/etc/httpd/conf/httpd.confに追記、

全体の記述はこんな感じです。

適当に置き換えてください。

/home/django/ 以下にxxxというプロジェクトを作った場合です。

LoadModule wsgi_module modules/mod_wsgi.so

WSGIScriptAlias / /home/django/xxx/xxx/wsgi.py
WSGIPythonHome /usr/local/bin/pyenv/versions/anaconda3-4.3.0/
WSGIPythonPath /home/django/xxx

<Directory /home/django/xxx/xxx>
<Files wsgi.py>
Require all granted
</Files>
</Directory>

Alias /static/ /home/django/xxx/static/
<Directory /home/django/xxx/static>
Require all granted
</Directory>

それぞれの項目を解説します。


  • WSGIScriptAlias: Apacheに来たリクエストをどこにつなぐか、です。ここでは/(ルート)に来たリクエストをDjangoでつくったプロジェクトに飛ばしています。

  • WSGIPythonHome: mod_wsgiに使わせたいPythonのパスを記述します。インストールの時と違い、ディレクトリを指定することに注意です。

  • WSGIPythonPath: プロジェクトのパスを指定します。

  • Directory: 指定のディレクトリにapacheのアクセス許可を与えます。

  • Alias /static/ /home/django/xxx/static/: Djangoが静的ファイルを探す場所を指定しています。

*注意

Apache2.4系では

Require all granted

ですが、それより前のバージョンでは以下のように書いてください。

Order allow,deny

Allow from all


mod_wsgi.soの依存関係を満足させる

今のままだとmod_wsgi.soはpythonを必要としているのに、見つけられていないです。

詳細をlddコマンドで確認します。

ldd /etc/httpd/modules/mod_wsgi.so

linux-vdso.so.1 => (0x00007fff8c9fe000)
libpython3.6m.so.1.0 => not found
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f4c9e548000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f4c9e344000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f4c9e141000)
librt.so.1 => /lib64/librt.so.1 (0x00007f4c9df38000)
libm.so.6 => /lib64/libm.so.6 (0x00007f4c9dc36000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4c9d875000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4c9e9a8000)

libpython3.6m.so.1.0を見つけられていません。

自分が使うPythonのディレクトリ以下を検索して、シンボリックリンクを貼りましょう。

ls /usr/local/bin/pyenv/versions/anaconda3-4.3.0/lib/ | grep python

libpython3.6m.so
libpython3.6m.so.1.0
libpython3.so
python3.6
ln -s /usr/local/bin/pyenv/versions/anaconda3-4.3.0/lib/libpython3.6m.so.1.0 /lib64/


Apache起動確認 => エラー解消

ここまで来たら一旦Apapcheを再起動します。

systemctl restart httpd

おそらくエラーが出るのでエラーログを見ながらブラウザにアクセスします。

tail -f /var/log/httpd/error_log

エラー別に原因を記します。


WSGIPythonHomeの設定が間違っている

[Thu Mar 09 16:32:51.315916 2017] [core:notice] [pid 9301] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND'

Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Fatal Python error: Py_Initialize: Unable to get the locale encoding
ModuleNotFoundError: No module named 'encodings'

Current thread 0x00007ff5dd6d8840 (most recent call first):
Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Fatal Python error: Py_Initialize: Unable to get the locale encoding
ModuleNotFoundError: No module named 'encodings'

WSGIPythonHomeの場所を確認しましょう。使いたいPythonはpyenvのものか、システムのものか、バージョンは合っているかを確認しましょう。


モジュールが足りない

[Thu Mar 09 15:53:52.797174 2017] [wsgi:error] [pid 9535] [client 192.168.10.1:65448] mod_wsgi (pid=9535): Target WSGI script '/home/django/plagiarism/plagiarism/wsgi.py' cannot be loaded as Python module.

[Thu Mar 09 15:53:52.797231 2017] [wsgi:error] [pid 9535] [client 192.168.10.1:65448] mod_wsgi (pid=9535): Exception occurred processing WSGI script '/home/django/plagiarism/plagiarism/wsgi.py'.
[Thu Mar 09 15:53:52.800163 2017] [wsgi:error] [pid 9535] [client 192.168.10.1:65448] Traceback (most recent call last):
[Thu Mar 09 15:53:52.800196 2017] [wsgi:error] [pid 9535] [client 192.168.10.1:65448] File "/usr/local/bin/pyenv/versions/anaconda3-4.3.0/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 25, in <module>
[Thu Mar 09 15:53:52.800199 2017] [wsgi:error] [pid 9535] [client 192.168.10.1:65448] import MySQLdb as Database
[Thu Mar 09 15:53:52.800213 2017] [wsgi:error] [pid 9535] [client 192.168.10.1:65448] ModuleNotFoundError: No module named 'MySQLdb'

MySQLdbをimportしろとのこと。

インストールしましょう。そのままの名前じゃないことに注意。

pip install mysqlclient


Pythonの指定ができていない

[Thu Mar 09 16:46:51.598855 2017] [mpm_prefork:notice] [pid 9476] AH00163: Apache/2.4.6 (CentOS) mod_wsgi/4.5.14 Python/xxx configured -- resuming normal operations

Python/xxxの部分が自分が使いたいPythonのバージョンと異なる場合はmod_wsgiと使いたいPythonが紐付いていません。一回mod_wsgiをインストールしなおしましょう。


mod_wsgi.soの依存関係が満足でない

3月 12 15:42:31 ip-172-31-32-130 systemd[1]: Starting The Apache HTTP Server...

3月 12 15:42:31 ip-172-31-32-130 httpd[22078]: httpd: Syntax error on line 353 of /etc/httpd/conf/httpd.conf: Syntax error on line ...: Cannot load modules/mod_wsgi.so into server: libpython3.6m.so.1.0: cannot open shared object file: No such file or directory

mod_wsgi.soはpythonを必要としているのに、見つけられていないです。

詳細をlddコマンドで確認します。

ldd /etc/httpd/modules/mod_wsgi.so

linux-vdso.so.1 => (0x00007fff8c9fe000)
libpython3.6m.so.1.0 => not found
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f4c9e548000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f4c9e344000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f4c9e141000)
librt.so.1 => /lib64/librt.so.1 (0x00007f4c9df38000)
libm.so.6 => /lib64/libm.so.6 (0x00007f4c9dc36000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4c9d875000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4c9e9a8000)

libpython3.6m.so.1.0を見つけられていません。

自分が使うPythonのディレクトリ以下を検索して、シンボリックリンクを貼りましょう。

ls /usr/local/bin/pyenv/versions/anaconda3-4.3.0/lib/ | grep python

libpython3.6m.so
libpython3.6m.so.1.0
libpython3.so
python3.6
ln -s /usr/local/bin/pyenv/versions/anaconda3-4.3.0/lib/libpython3.6m.so.1.0 /lib64/


OpenSSLのバージョンが古い?

アクセスするとDjangoのページは表示されるが以下のエラーが出る場合。

You are linking against OpenSSL 1.0.0, which is no longer support by the OpenSSL project. You need to upgrade to a newer version of OpenSSL.

openssl versionで確認するバージョンと表示がずれているっぽいです。

散々調べましたが、これと同じ状況でAnacondaのopensslを使ってしまっている?

pyenv の Anaconda/Miniconda 対応について

pip install -U cryptography

で解決。


静的ファイルの公開

Not Found: /static/admin/css/base.css, referer: http://xxx.xxx.xxx.xxx/

開発サーバでDjangoが用意しているテンプレートなどを使っている場合、

ウェブサーバで公開する時は改めて設定が必要です。こちらはエラーが出ていなくても設定しておきましょう。

自分のプロジェクトディレクトリ下にDjangoのファイルをコピーなりシンボリックリンクを貼るなりすれば良いのですが、Djangoに専用のコマンドがあるのでそれを使いましょう。

プロジェクトディレクトリのsettings.pyに以下の形で静的ファイルを置く場所を決めます。

STATIC_ROOT = '/home/django/xxx/static/'

以下のコマンドで指定したディレクトリに静的ファイルをコピーしてくれます。

python manage.py collectstatic


エラー解消はドット疲れますが、これを乗り越えないと公開できません。

思い出しただけで辛くなりました。



mod_wsgiアンインストール

利用するPythonのバージョンを変更したい場合は一度mod_wsgiをアンインストールして、再度上記手順を辿る必要があります。


アンインストールするには、mod_wsgi.soを削除すれば良いです。


参考


vhosts

最終的にはドメインを取得してapacheのvhostsを使うことになると思います。


ひとまずうまくいった設定だけメモしておきます。


httpd.conf

LoadModule wsgi_module modules/mod_wsgi.so

WSGIPythonHome /usr/local/bin/pyenv/versions/anaconda3-4.3.0/


vhosts.conf

<VirtualHost *:80>

ServerName MY_DOMAIN
WSGIDaemonProcess PROCESS_GROUP user=apache group=apache python-path=/path/to/project
WSGIProcessGroup PROCESS_GROUP
WSGIScriptAlias / /path/to/project/app/wsgi.py process-group=PROCESS_GROUP

<Directory /path/to/project/app/>
<Files wsgi.py>
Require all granted
</Files>
</Directory>

Alias /static/ /path/to/project/static/
<Directory /path/to/project/static/>
Require all granted
</Directory>
CustomLog /path/to/project/log/access_log common
ErrorLog /path/to/project/log/error_log

</VirtualHost>


環境に合わせて適宜読み替えます。