ゴミ箱の中のメモ帳

まだ見ぬ息子たちへ綴る手記

DreamHostでWSGIを動かす

前の記事に書いた通りWSGIを使うべくDreamHostを契約したわけだが、Python Bottleを動かすまでに色々と悩んだので後発に続くであろう若者のためにメモを残しておく。

これはわからないながらに動作させた記録であるため、誤りや問題があるかもしれない。詳しい方がいればご指摘いただきたい。

WSGIウェブプログラミング

WSGIウェブプログラミング

登録

まず、DreamHostの契約は簡単に行える。クーポンを使えばほぼ半額で利用できる。契約するとすぐにFTPパスワードなんかが送られてくるが、送られてきてもすぐにはログインが出来なかった。反映には少々遅延がある様子。

ちなみに、登録時にドメインを取得するか聞かれるが、以下の説明はここでドメインを新たに取得した内容で進める。ドメインを別に取得する場合の手続きは現在試していないため、テストにでもドメインを取得しておくことをおすすめする。

SSHでの有効化

そして、FTPなんかは使わないのでSSHでログイン出来るようにする。

f:id:mon0:20140630034716p:plain

手順は簡単で、管理パネルにログイン後左下のメインメニューから「Users」「Manage Users」を選択し、一覧に初期登録ユーザがいるので「Actions」から「Edit」を選択する。

f:id:mon0:20140630034748p:plain

UserTypeがデフォルトでは「FTP」になっているため「Shell user」に変更しておく。もしここで、「Shell user」や「ssh」が何かわからないという人がいるとすればDreamHostWSGIを使うのは諦めたほうがいい。そもそもVPSでも諦めたほうがいい。きちんと勉強するように。

そして、「Shell Type」はbash, tcsh, ksh, zshから好きなものを選べるので自分が使い慣れたものを選択しておく。私はzshを使うが、Shellの種類について理解していない方はbashを選択しておくこと。tcshkshは懐古主義のマゾヒストなNetBSDユーザぐらいしか使わないので決して選択してはならない。ちなみにbashは4.1.5、zshは4.3.10がインストールされている。

もしデフォルトのパスワードが気に入らなければここで変更しておく。

Domainの取得

DreamHostの契約、登録時にドメインを指定したが、ドメインを指定しただけで取得がまだされていない。自分で取得する必要がある。画像では取得ドメインが一覧に表示されているが、取得前は表示されていなかったかとおもう。

f:id:mon0:20140630034910p:plain

メインメニューから「Domains」「Registrations」を選択し、ドメイン入力欄に登録時に指定したドメインを入力する。ドメイン料金が表示されているがとりあえずは気にせずに進める。

f:id:mon0:20140630034929p:plain

そして、登録時に指定したドメインはまだ取得されていないため「Register Now!」がドメインの右側に表示されているのでそれを選択する。そこからドメイン種類に応じてドメイン情報を入力するページに進むので入力して「continue」する。そこから価格が表示されるページに移動していくが、最終的には主要4ドメインでは0米ドルで取得できるようになる。他のドメインでは別途費用がかかるが取得しておく。

もし0米ドルにならないようであればわからない。個々人で理由を調べて欲しい。

そしてもしかしたらActivateが必要になるかもしれないが、そのへんは操作パネルからわかるかと思う。とにかくドメインを取得しておく。私は既に取得しているため詳細画面は確認できない。もし確認が必要であれば寄付していただければその金額で確認作業を行う。

Passengerの有効化

DreamHostではPassengerというApacheモジュールを使ってWSGIを起動させるので、Passengerを有効化させておく必要がある。デフォルトでは無効になっている。

f:id:mon0:20140630035132p:plain

こちらもメインメニューから「Domains」「Manage Domains」を選択し、一覧に先ほど取得したドメインが表示されている事を確認する。そして当該ドメインの「Web Hosting」から「Edit」を選択する。

f:id:mon0:20140630035626p:plain

ここでドメインの設定画面に入るので、まずは自分の環境に応じて設定を変更する。私は「Remove WWW:」の設定だけ変更した。この設定は以後の作業に影響しないはずだが、完全に同等とする場合は同じ設定にして置いて欲しい。設定を変更したら、まずそこまでを保存して置く。

ここからがPassengerの設定で、「Web Options」の「Passenger(Ruby/Python apps only):」にチェックを入れる。そうすると、「Users, Files, and Paths」の「Web directory」のドメイン名の後に「/public」が自動で追加されるが、これはPassengerのファイル構成上必要な変更であるため許容しておく。そして変更を保存する。

これでPassengerを使う準備が完了した。

Python3.4の導入

DreamHostは標準でPython2.5.5とPython2.6.6がインストールされているがだいぶ古い。サポートは既に終了している。Rubyは1.8.7、Perlは5.10.1と基本的にPHP以外はサポートが終了しているような古いバージョンになるため、安全に使おうと思うと自分でビルドする必要がある。

そしてご多分にもれず、PythonでBottleを動かすのでお気に入りのPython3.4をビルドする。

基本的にPythonのビルドはDreamHostPython: Installation on Dreamhostマニュアルの通りに行う。マニュアルは誤字だったりが結構多いので、マニュアルに従う場合はその点を注意する必要がある。また、今回はPython3.4をインストールするので、デフォルトでpipを使うことができるのでマニュアルの大部分が不要になる。

以下はダウンロードからビルド、インストールまでの全ての流れになるが割り当てられたサーバや時間帯によってDiskIOが非常に重いため結構時間がかかるかもしれない。

% cd ~
% mkdir -p opt/py/suite/src
% cd opt/py/suite/src
% wget --no-check-certificate https://www.python.org/ftp/python/3.4.1/Python-3.4.1.tgz
% cd ..
% mkdir build
% cd build
% tar -xzf ./../src/Python-3.4.1.tgz
% cd Python-3.4.1
% export PY_SUITE=~/opt/py/suite
% ./configure --prefix=$PY_SUITE
% make -j4
% make install

そして、以後はデフォルトとしてPython3.4を使いたいため「python」と言う名前でシンボリックリンクを貼っておく。

% cd ~/opt/py/suite/bin
% ln -s python3.4 python

そしてそして、ビルドしたPython3.4を利用するためにパスを追加しておく。これはbashなら「~/.bashrc」、zshなら「.zshrc」に以下を追記しておく。ここでマニュアルでは「gd」となっている箇所があり、それは誤りなので注意しておくこと。

export PY_SUITE=~/opt/py/suite
export PATH=$PY_SUITE/bin:$PATH
export LD_LIBRARY_PATH=$PY_SUITE/lib:$LD_LIBRARY_PATH

これでPython3.4のインストールと環境設定が完了。shellの設定を再読込するか、再ログインしておく。

virtualenvのインストール

Python3.4は後から追加したバージョンになるため、Passengerが実行されるシステムにインストールされているPythonのバージョンとは異なることになる。そのため、Passengerに実行するPythonのバージョンを変更させるためにvirtualenvを使う。virtualenvを使わないでもいい方法があるかもしれないが、今後別のバージョン(Python2.7)を使う可能性があるためvirtualenvを使っておくと便利になる。

Python3.4からはpipとvirtualenvがデフォルトでインストールされるため、それぞれのインストール作業は全く不要になる。

そして、virtualenvでpython3.4の環境を準備しておく。

% cd ~
% mkdir venv
% cd venv
% export VIRTUALENV_USE_DISTRIBUTE=true
% virtualenv python3.4

先にpythonとしてpython3.4のシンボリックリンクを張っているため、デフォルトでpython3.4環境がコピーされる。

Bottleのインストール

virtualenvの環境が用意出来たので、そこにBottleをインストールしておく。

% cd ~
% source venv/python3.4/bin/activate
(python3.4)% pip3 install bottle
(python3.4)% deactivate

これで完了。本当に世の中は才能ある人たちのおかげで便利になっていく。

Passengerの設定

Passengerは動きがわかりづらいので、一ステップづつ動作確認をしていく。そうすることで、どこで問題が起きているのかわかりやすい。

まずサーバが動作しているか、契約したドメインにアクセスして確認する。

f:id:mon0:20140630035948p:plain

デフォルトではこの画面が表示されれば準備完了となっている。もしこの画面が表示されずにエラー画面が表示されればしばらく時間を置いてアクセスすれば表示されるかと思う。私も最初はエラーが表示されナンノコッチャわからなかった。これもFTPと同じように準備に少し遅延があるのかもしれない。

Passengerの動作確認

PassengerはDocumentRootより一つ上のディレクトリに「passenger_wsgi.py」として用意しているスクリプトを実行するようになっている。先の設定で、「/public」が自動的に追加されたのも、このDocumentRootを一つ下の階層にづらすことが目的となっている。

デフォルトでは取得したドメインと同じ名称のディレクトリがホームディレクトリに作成されているので、そのディレクトリにファイルを準備することになる。

まずは、以下の内容のファイルを「passenger_wsgi.py」として準備して欲しい。

import sys, os

def application(environ, start_response):
        start_response('200 OK', [('Content-type', 'text/plain')])
	return ["Hello, world! from %s: %s\n" % (sys.version, sys.executable)]

これはシステムにインストールされているPythonでレスポンスを返すというシンプルなスクリプトスクリプトを準備したらパーミッションを変更しておく。

% chmod 755 passenger_wsgi.py

そして取得したドメインにアクセスすると、このようにシステムにインストールされているPythonのバージョンと、実行されたPythonのパスが表示される。先ほどインストールしたPython3.4はま
だ利用していない。

f:id:mon0:20140630040108p:plain

passenger_wsgi.pyの再読み込み

もしコピーミス等でエラーが表示された場合でも、スクリプトを修正してもそのエラーが解決されない。それはWSGIが既に起動されてスクリプトがキャッシュされているからという理由になり、WSGIスクリプトを変更する場合はPassengerを再読込みさせる必用がある。以後の作業についてもWSGIファイルを変更しても反映されないため、テストの実行毎にこの作業を繰り返していただきたい。

Passengerを再読込させるには、DocumentRootより一つ上の階層(passenger_wsgi.pyと同じ階層)の「tmp」ディレクトリ内の「restart.txt」ファイルのタイムスタンプを更新する必要がある。Passengerはそのファイルのタイムスタンプを確認し、更新されていれば再読込するという仕組みになっている。

PassengerからPython3.4を使う

次に先ほどビルドしたPython3.4を使って問題なくPassengerが動くことを確認する。

以下の内容のファイルを「passenger_wsgi.py」として保存しておく(ユーザ名は環境に合わせて変更する)。

import sys, os

INTERP = "/home/<username>/venv/python3.4/bin/python"
if sys.executable != INTERP:
        os.execl(INTERP, INTERP, *sys.argv)

def application(environ, start_response):
        start_response('200 OK', [('Content-type', 'text/plain')])
        return [("Hello, world! from %s: %s\n" % (sys.version, sys.executable)).encode('utf-8')]

これで先ほどインストールしたPython3.4でスクリプトが実行される。その確認として、インストールしたPATHに表示が変更されている。

f:id:mon0:20140630040256p:plain

Python3.4で動かすため、application()の戻り値をバイト列にしなければならないことを注意する。

PassengerからBottleを使う

次にPython3.4でBottleが動作することを確認する。

以下の内容を「passenger_wsgi.py」として保存しておく(同じくユーザ名を環境に合わせて変更する)。

import sys, os

INTERP = '/home/<username>/venv/python3.4/bin/python'
if sys.executable != INTERP:
        os.execl(INTERP, INTERP, *sys.argv)


import bottle
from bottle import route, run

@route('/')
def index():
        return 'Hello, World!'

@route('/test')
def test():
        return 'Hello, Test!'

def application(environ, start_response):
        return bottle.default_app().wsgi(environ,start_response)

これで、Bottleが動作していることが確認できる。ドメイン名への直接アクセスと、「/test」にアクセスして表示が切り替わることも確認する。これで問題なければPython3.4のインストールやBottleのインストール、PassengerからPython3.4の利用とPassenger経由のWSGIでのBottleの動作が確認できた。

f:id:mon0:20140630040319p:plainf:id:mon0:20140630040323p:plain


今回はテストのためpassenger_wsgi.pyに直接スクリプトを記述したが、実際であれば別ディレクトリにスクリプトを設置し、それをWSGIファイルから読み込むようにすればいい。

この単純なことも私は結構悩んでしまったため記事にした。少しでもPythonに触れ、WSGIに抵抗を抱かずPythonを使うユーザが増えることを願って。