GMO VPS を契約して Django アプリを公開するところまでの手順のメモです。
CentOS 7 + Nginx + uWSGI で Python 3 + Django のサービス公開を目指します。
Nginx と uWSGI を使って Django アプリを公開するところがメインなので、それ以外のところはなんとなく流れがわかる程度に書いてあります。
環境
- GMOクラウド VPS 2GB プラン
- CentOS 7.1
- Python 3.5.1
- Django 1.9.2
- Nginx 1.9.9
- uWSGI 2.0.12
目次
- 初期設定
- VirtualHost の設定
- pyenv の設定
- pip でパッケージをインストール
- データベースの設定
- Django 起動テスト
- uWSGI の設定
- Django の公開設定
- おわりに
- 参考文献
初期設定
サーバーの初期設定は、ドットインストールさんの「さくらのVPS入門」レッスンと、OXY NOTES さんの記事が非常に参考になります。
さくらのVPS入門 (全21回) – プログラミングならドットインストール
GMO VPSを契約してWordPressを安定動作させるまでのサーバ設定方法 | OXY NOTES
上のページを参考にしながら、
- ユーザーの設定
- 鍵認証の設定
- SSH の設定
- ファイアーウォールの設定(iptables)
- Web サーバーの設定(Nginx)
- MySQL の設定
このあたりを一通り行っておきましょう。
VirtualHost の設定
ここでは example.com というドメインを設定する。
# -p で一気にディレクトリを作成できる
mkdir -p /var/www/example.com/public_html
# パーミッションを変更
chown -R user:user /var/www/example.com
# ドメインごとにconfファイルを作る
vim /etc/nginx/conf.d/example.conf
# conf ファイルの syntax をチェック
nginx -t
# 再起動
systemctl restart nginx
なお、FTP クライアントでファイルを編集したい場合は所有者を変更する。
cd /var
chown -R user:user www
アクセスできるか確認
# 適当なページを作成
vim /var/www/example.com/public_html/index.html
ホストツールを使って
サーバーの IP アドレスを example.com
として登録しておく。
ブラウザで http://example.com/ にアクセスできれば成功。
pyenv の設定
pyenv のインストールは別途行っておいてください。
# インストール可能な Python のバージョンを確認
pyenv install --list
# 現時点で最新の Python 3.5.1 をインストール
pyenv install 3.5.1
# 全体に Python 3.5.1 を適用
pyenv global 3.5.1
# 仮想環境 example を作成
pyenv virtualenv 3.5.1 example
# example.com フォルダ以下に example を適用
cd /var/www/example.com
pyenv local example
# example が適用されているか確認
pyenv versions
これで example.com ディレクトリに入れば自動的に仮想環境 example が適用される。
pip でパッケージをインストール
ローカルでインストールしているパッケージをそのまま VPS にインストールする。
# ローカルで requirements.txt を作成
pip freeze > requirements.txt
# VPS で requirements.txt からパッケージをインストール
pip install -r requirements.txt
/var/www/example.com/example にプロジェクトファイルをコピーする。
これで Django 関係のパッケージがインストールされた。
データベースの設定
Django アプリ用のデータベースを作成する。
(ユーザーの作成は省略)
# root で MySQL にログイン
mysql -u root -p
# example データベースを作成
create database example;
# ユーザーに権限を付与
grant all on example.* to user@localhost identified by 'password';
Django 起動テスト
とりあえず Django が動くかどうかテストする。
runserver で使用する 8000 番ポートを開ける。
# /etc/sysconfig/iptables
# Django runserver 用
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8000 -j ACCEPT
ちなみに vim の場合は ‘G’ と入力すると一番下まで移動できる。
cd /var/www/example.com/example
python manage.py runserver 0.0.0.0:8000
http://example.com:8000/ にアクセスできたらOK
uWSGI の設定
アプリ用に作った Virtualenv 環境の外でインストールしておく。(複数のアプリで使用するかもしれないので)
# uWSGI をインストール
pip install uwsgi
uWSGI で Python を動かす
the web client <-> uWSGI <-> Python
とりあえず適当に作った test.py を動かす。
# test.py
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"] # python3
#return ["Hello World"] # python2
# uWSGI 起動
uwsgi --socket :9000 --wsgi-file test.py
uWSGI で Django を動かす
the web client <-> uWSGI <-> Django
# uWSGI 起動
uwsgi --http :8000 --module example.wsgi
ここでエラーが出た。
ImportError: No module named MySQLdb
この Django アプリでは pymysql というモジュールを使っているのだが、manage.py でインポートしていたのを init.py でインポートするようにしたら解決した。(かなりハマった)
# __init__.py
import pymysql
pymysql.install_as_MySQLdb()
http://example.com:8000 にアクセスできたらOK
Nginx と uWSGIで Django を動かす
いよいよ本番。
the web client <-> Nginx <-> the socket <-> uWSGI <-> Django
# /etc/nginx/conf.d/example.conf
upstream django {
server unix:///var/www/example.com/example/example.sock;
}
server {
listen 80;
server_name example.com;
location /static {
alias /var/www/example.com/example/static;
}
location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass django;
}
}
# conf の文法チェック
sudo nginx -t
# Nginx 再起動
sudo systemctl restart nginx
# uWSGI 起動
uwsgi --socket example.sock --module example.wsgi --chmod-socket=666
ini ファイルに設定を書く
ini ファイルにまとめて設定を書いておける。
# example_uwsgi.ini
[uwsgi]
# Django-related settings
# the base directory (full path)
chdir = /var/www/example.com/example
# Django's wsgi file
module = example.wsgi
# the virtualenv (full path)
home = /usr/local/pyenv/versions/example
# process-related settings
# master
master = true
# maximum number of worker processes
processes = 10
# the socket (use the full path to be safe)
socket = /var/www/example.com/example/example.sock
# ... with appropriate permissions - may be needed
chmod-socket = 666
# clear environment on exit
vacuum = true
# respawn processes after serving 1000 requests
max-requests = 1000
# respawn processes taking more than 60 seconds
harakiri = 60
# uWSGI 起動
uwsgi --ini example_uwsgi.ini
Emperor mode
設置した ini ファイルを全て読み込んで起動する。
複数のアプリを公開するときに便利なので初めからこちらを使っておく。
# ディレクトリを作成
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
# 作った ini ファイルへのシンボリックリンクを作成
sudo ln -s /var/www/example.com/example/example_uwsgi.ini /etc/uwsgi/vassals/
# uWSGI を Emperor mode で起動
uwsgi --emperor /etc/uwsgi/vassals --uid user --gid user
自動起動設定
サーバー起動後、常に起動させておきたい。
uWSGI を Emperor mode で起動するサービスを作る。
# サービスファイルを作成
sudo vi /etc/systemd/system/uwsgi.service
# uwsgi.service
[Unit]
Description=uWSGI
After=syslog.target
[Service]
ExecStart=/usr/local/pyenv/versions/3.5.1/bin/uwsgi --emperor /etc/uwsgi/vassals --uid user --gid user
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
# uWSGI を起動
sudo systemctl start uwsgi
# uWSGI を停止
sudo systemctl stop uwsgi
# 正常に動作することを確認したら自動起動の設定を行う
sudo systemctl enable uwsgi
Django の公開設定
ここまでできたらあとは Django の設定。
static ファイルを一箇所に集める
おそらく今の状態で admin ページにアクセスすると css が読み込まれない。
settings.py に STATIC_ROOT を追記する。
# settings.py
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
# static ファイルを一箇所に集める
python manage.py collectstatic
DEBUG モードを解除
# settings.py
# DEBUG = True
DEBUG = False
# ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
ALLOWED_HOSTS = ['example.com']
設定を変更したら uWSGI を再起動する。
# uWSGI を再起動
sudo systemctl restart uwsgi
http://example.com にアクセスして正常に動作していれば成功!
おわりに
以上で設定完了です。お疲れ様でした!
これで新しく作った Django アプリを公開するときは、新たに ini ファイルを作ってそれをシンボリックリンクしてあげるだけで良くなったわけですね。
それにしても、サーバー関連でハマらなかったことがない。。。
参考文献
[1] CentOS7 pyenvを利用したpython環境構築 – from umentu import stupid[2] Setting up Django and your web server with uWSGI and nginx – uWSGI 2.0 documentation
[3] ちゃんと運用するときのuWSGI設定メモ – Qiita
[4] CentOS7 + nginx + uWSGI + Flask – Qiita