Ubuntu 16.04でuWSGIとNginxを使用してDjangoアプリケーションを提供する方法
紹介
Djangoは、Pythonアプリケーションやウェブサイトを立ち上げるのに役立つ強力なウェブフレームワークです。Djangoには、ローカルでコードをテストするための簡素化された開発用サーバーが含まれていますが、少しでも本番関連のことを行うには、より安全で強力なウェブサーバーが必要です。
このガイドでは、Django アプリケーションをサポートし提供するために、Ubuntu 16.04 にいくつかのコンポーネントをインストールおよび構成する方法を示します。アプリケーションとインターフェースするために、uWSGI アプリケーションコンテナサーバーを構成します。その後、uWSGI へのリバースプロキシとして Nginx を設定し、アプリケーションを提供するためのセキュリティとパフォーマンス機能にアクセスできるようにします。
前提条件と目標
このガイドを完了するためには、非ルートユーザーにsudo権限が設定された新しいUbuntu 16.04サーバーインスタンスが必要です。この設定方法については、初期サーバー設定ガイドを参照してください。
私たちは2つの異なる仮想環境内にDjangoをインストールします。これにより、プロジェクトやその要件を別々に管理することができます。私たちは、マルチプロジェクト環境での手順を実行できるように、2つのサンプルプロジェクトを作成します。
アプリケーションが整ったら、uWSGIアプリケーションサーバーをインストールして設定します。これは、クライアントからのHTTPリクエストを私たちのアプリケーションが処理できるPythonの呼び出しに変換するインターフェースとして機能します。その後、uWSGIの前にNginxを設定し、高性能の接続処理メカニズムと簡単に実装できるセキュリティ機能を活用します。
さあ、始めましょう。
VirtualEnv と VirtualEnvWrapper をインストールして設定する
私たちは、各Djangoプロジェクトの要件を隔離するために、それぞれ独自の仮想環境にプロジェクトをインストールします。そのために、Pythonの仮想環境を作成できるvirtualenvと、virtualenvのワークフローにいくつかの使いやすさの改善を追加するvirtualenvwrapperをインストールします。
これらのコンポーネントの両方を、Pythonのパッケージマネージャーであるpipを使ってインストールします。このユーティリティは、Ubuntuのリポジトリからインストールできます。
もしあなたがPython 2を使ってDjangoプロジェクトを構築しているなら、次のように入力してください。
- sudo apt-get update
- sudo apt-get install python-pip
Python 3を使用している場合、次のように入力します:
- sudo apt-get update
- sudo apt-get install python3-pip
これで pip がインストールされたので、virtualenv と virtualenvwrapper をグローバルにインストールできます。また、pip 自体を使用して pip を最新バージョンにアップグレードします。
Python 2を使用している場合は、次のように入力します:
- sudo -H pip install --upgrade pip
- sudo -H pip install virtualenv virtualenvwrapper
Python 3を使用している場合、入力してください:
- sudo -H pip3 install --upgrade pip
- sudo -H pip3 install virtualenv virtualenvwrapper
これらのコンポーネントがインストールされたので、私たちは今、シェルをvirtualenvwrapperスクリプトと連携するために必要な情報で構成することができます。私たちの仮想環境は、アクセスしやすいように、ホームフォルダ内のEnvというディレクトリにすべて配置されます。これはWORKON_HOMEという環境変数を通じて設定されます。これをシェル初期化スクリプトに追加し、仮想環境ラッパースクリプトをソースすることができます。
Python 3 を使用していて、pip3 コマンドを使用している場合、シェル初期化スクリプトに追加の行を加える必要があります:
- echo "export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3" >> ~/.bashrc
使用しているPythonのバージョンに関係なく、次のコマンドを実行する必要があります:
- echo "export WORKON_HOME=~/Env" >> ~/.bashrc
- echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc
さて、シェル初期化スクリプトをソースして、この機能を現在のセッションで使用できるようにします:
- source ~/.bashrc
あなたのホームフォルダには、仮想環境の情報を保持する Env という名前のディレクトリが今あるはずです。
Djangoプロジェクトを作成する
仮想環境ツールが揃ったので、2つの仮想環境を作成し、それぞれにDjangoをインストールして、2つのプロジェクトを開始します。
最初のプロジェクトを作成する
私たちは、virtualenvwrapper スクリプトが提供するいくつかのコマンドを使用することで、簡単に仮想環境を作成できます。
最初のサイトまたはプロジェクトの名前で最初の仮想環境を作成するには、次のように入力してください:
- mkvirtualenv firstsite
これにより、仮想環境が作成され、その中にPythonとpipがインストールされ、環境が有効化されます。プロンプトが変更され、新しい仮想環境内で作業していることを示します。これは次のようになります:(firstsite)user@hostname:~$。括弧内の値があなたの仮想環境の名前です。pipを通じてインストールされたソフトウェアは、グローバルシステムではなく、仮想環境にインストールされます。これにより、プロジェクトごとにパッケージを隔離することができます。
最初のステップは、Django自体をインストールすることです。私たちは、仮想環境内にローカルでインストールするので、sudoを使わずにpipを使用できます:
- pip install django
Djangoがインストールされたので、次のように入力して最初のサンプルプロジェクトを作成できます:
- cd ~
- django-admin.py startproject firstsite
これにより、あなたのホームディレクトリ内にfirstsiteという名前のディレクトリが作成されます。その中には、プロジェクトのさまざまな側面を管理するためのスクリプトと、実際のプロジェクトコードを格納するための同名の別のディレクトリがあります。
サンプルプロジェクトの最低限の要件を設定するために、最初のレベルのディレクトリに移動します。
- cd ~/firstsite
まず、プロジェクトで使用するSQLiteデータベースを初期化するためにデータベースを移行します。必要であれば、アプリケーションのために別のデータベースを設定することもできますが、これはこのガイドの範囲外です。
- ~/firstsite/manage.py migrate
プロジェクトディレクトリに db.sqlite3 というデータベースファイルが作成されているはずです。 さあ、次に、次のコマンドを入力して管理者ユーザーを作成できます:
- ~/firstsite/manage.py createsuperuser
この時点で、あなたのプロジェクトディレクトリ(この場合は~/firstsite)には以下の内容があるはずです:
~/firstsite/manage.py: Djangoプロジェクト管理スクリプト.~/firstsite/firstsite/: Djangoプロジェクトパッケージ。これには__init__.py、settings.py、urls.py、およびwsgi.pyファイルが含まれている必要があります。~/firstsite/db.sqlite3: サイト情報を保存するために使用されるSQLiteデータベースファイル。
次に、テキストエディタでプロジェクトの設定ファイルを開いてください:
- nano ~/firstsite/firstsite/settings.py
ALLOWED_HOSTS ディレクティブを探すことから始めます。これは、Django インスタンスに接続するために使用できるサーバーのアドレスまたはドメイン名のリストを定義します。このリストに含まれていないHost ヘッダーを持つすべての受信リクエストは、例外を発生させます。Django は、特定の種類のセキュリティ脆弱性を防ぐためにこれを設定することを要求します。
角括弧内に、あなたのDjangoサーバーに関連付けられているIPアドレスまたはドメイン名をリストしてください。各項目は引用符で囲み、項目同士はカンマで区切ってください。ドメイン全体とそのサブドメインに対するリクエストを希望する場合は、エントリの先頭にドットを付けてください。以下のスニペットには、デモのために使用されるいくつかのコメントアウトされた例があります。
. . .
The simplest case: just add the domain name(s) and IP addresses of your Django server
ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']
To respond to 'example.com' and any subdomains, start the domain with a dot
ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .]
当サイトを提供するためにNginxを設定するので、サイトの静的アセットを保管するディレクトリを構成する必要があります。これにより、Nginxがこれらを直接提供できるようになり、パフォーマンスに良い影響を与えます。Djangoにプロジェクトのベースディレクトリにあるstaticというディレクトリに配置するように指示します。この動作を構成するために、ファイルの底にこの行を追加してください:
. . .
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
作業が完了したら、ファイルを保存して閉じてください。次に、当サイトの静的要素を収集し、それらをそのディレクトリ内に配置するために、次のように入力してください:
- ~/firstsite/manage.py collectstatic
アクションを確認し、静的コンテンツを収集するために「はい」と入力するように求められることがあります。プロジェクトディレクトリに「static」と呼ばれる新しいディレクトリが作成されます。
次に、Django開発サーバーにアクセスできるようにポートを開放します。初期サーバー設定ガイドに従った場合、UFWファイアウォールが有効になっているはずです。ポート8080への接続を許可するには、次のコマンドを入力します:
- sudo ufw allow 8080
すべてが終わったので、開発サーバーを一時的に起動してプロジェクトをテストできます。タイプ:
- ~/firstsite/manage.py runserver 0.0.0.0:8080
これにより、ポート8080で開発サーバーが起動します。ブラウザでサーバーのドメイン名またはIPアドレスの後に8080を入力してアクセスしてください:
http://server_domain_or_IP:8080
このようなページが表示されるはずです:
/admin をブラウザのアドレスバーのURLの最後に追加すると、管理者ログインページに移動します:
選択した管理者ログイン資格情報を使用して、createsuperuserコマンドでサーバーにログインしてください。これにより、管理インターフェイスにアクセスできるようになります:
この機能をテストした後、ターミナルでCTRL-Cを押して開発サーバーを停止します。これで、私たちの2つ目のプロジェクトに進むことができます。
第二のプロジェクトを作成する
二つ目のプロジェクトは、一つ目と全く同じ方法で作成されます。このセクションの説明は省略します、なぜならあなたはこれをすでに一度完了しているからです。
自分のホームディレクトリに戻り、新しいプロジェクトのための2番目の仮想環境を作成します。この新しい環境がアクティブになったら、Djangoをインストールしてください。
- cd ~
- mkvirtualenv secondsite
- pip install django
新しい環境が作成され、以前の仮想環境はそのまま残ります。このDjangoインスタンスは、あなたが設定した別のインスタンスとは完全に独立しています。これにより、それぞれを独立して管理し、必要に応じてカスタマイズすることができます。
2つ目のプロジェクトを作成し、そのプロジェクトディレクトリに移動してください:
- cd ~
- django-admin.py startproject secondsite
- cd ~/secondsite
データベースを初期化し、管理ユーザーを作成します:
- ~/secondsite/manage.py migrate
- ~/secondsite/manage.py createsuperuser
設定ファイルを開いてください:
- nano ~/secondsite/secondsite/settings.py
ALLOWED_HOSTSをあなたの2番目のプロジェクトのドメイン、サーバーのIPアドレス、またはその両方に設定してください。最初のプロジェクトと同様に:
ALLOWED_HOSTS = ['second_project_domain_or_IP', 'another_domain_or_IP', . . .]
前のプロジェクトで行ったように、静的ファイルの場所を追加してください。
. . .
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
ファイルを保存して閉じます。次に、次のコマンドを入力して静的要素をそのディレクトリに集めます:
- ~/secondsite/manage.py collectstatic
最後に、サイトをテストするために開発サーバーを起動します:
- ~/secondsite/manage.py runserver 0.0.0.0:8080
定期的なサイトを確認するべきです:
http://server_domain_or_IP:8080
管理サイトにもログインしてください:
http://server_domain_or_IP:8080/admin
すべてが期待通りに動作していることを確認したら、開発サーバーを停止するためにターミナルでCTRL-Cと入力してください。
仮想環境から出る
ガイドのDjango部分が終わったので、私たちは2つ目の仮想環境を無効にすることができます:
- deactivate
もしあなたが再びどちらかのDjangoサイトで作業する必要がある場合は、それぞれの環境を再活性化する必要があります。これは、workonコマンドを使用することでできます:
- workon firstsite
または :
- workon secondsite
もう一度、サイトでの作業が終わったら無効にしてください:
- deactivate
アプリケーションサーバーの設定に進むことができます。
uWSGIアプリケーションサーバーの設定
今、2つのDjangoプロジェクトが設定され、準備が整ったので、uWSGIを設定できます。uWSGIは、WSGIと呼ばれる標準インターフェースを介してアプリケーションと通信できるアプリケーションサーバーです。これについて詳しく知りたい場合は、Ubuntu 14.04でのuWSGIとNginxの設定に関するガイドのこのセクションをお読みください。
uWSGIのインストール
上記のガイドとは異なり、このチュートリアルではuWSGIをグローバルにインストールします。これにより、複数のDjangoプロジェクトを扱う際の摩擦が少なくなります。uWSGIをインストールする前に、ソフトウェアが依存しているPythonの開発ファイルが必要です。これをUbuntuのリポジトリから直接インストールすることができます。
もしあなたが Python 2 と一緒に Django を使用している場合は、次のように入力します:
- sudo apt-get install python-dev
Python 3を使用している場合は、次のように入力します:
- sudo apt-get install python3-dev
開発ファイルが利用可能になったので、pipを通じてuWSGIをグローバルにインストールできます。
Python 2を使用している場合は、次のように入力します:
- sudo -H pip install uwsgi
Python 3を使用している場合、次のように入力します:
- sudo -H pip3 install uwsgi
このアプリケーションサーバーを、私たちのサイトの情報を渡すことで迅速にテストすることができます。例えば、最初のプロジェクトを提供するように指示するには、以下のように入力します:
- uwsgi --http :8080 --home /home/sammy/Env/firstsite --chdir /home/sammy/firstsite -w firstsite.wsgi
ここでは、uWSGIに私たちの~/Envディレクトリにある仮想環境を使用し、プロジェクトのディレクトリに移動し、内部のfirstsiteディレクトリ内に保存されているwsgi.pyファイルを提供するように指示しました(firstsite.wsgi Pythonモジュール構文を使用)。デモのために、HTTPをポート8080で提供するように指示しました。
ブラウザでサーバーのドメイン名またはIPアドレスの後に:8080を入力すると、再びサイトが表示されます(/adminインターフェース内のCSSのような静的要素はまだ機能しません)。この機能のテストが終了したら、ターミナルでCTRL-Cを入力してください。
設定ファイルの作成
コマンドラインからuWSGIを実行することはテストには便利ですが、実際のデプロイにはあまり役立ちません。代わりに、設定ファイルのセットを指定することで、マスタープロセスが別々のアプリケーションを自動的に管理できる「エンペラーモード」でuWSGIを実行します。
設定ファイルを保存するディレクトリを作成します。このプロセスはグローバルなものなので、設定ファイルを保存するためのディレクトリとして/etc/uwsgi/sitesという名前のディレクトリを作成します:
- sudo mkdir -p /etc/uwsgi/sites
このディレクトリには、私たちの設定ファイルを置きます。私たちがサーブしている各プロジェクトのために設定ファイルが必要です。uWSGIプロセスはさまざまな形式の設定ファイルを受け入れますが、そのシンプルさから.iniファイルを使用します。
最初のプロジェクトのためのファイルを作成し、テキストエディタで開いてください:
- sudo nano /etc/uwsgi/sites/firstsite.ini
内部では、まず[uwsgi]のセクションヘッダーから始めます。すべての情報はこのヘッダーの下に配置します。また、設定ファイルをより再利用可能にするために変数を使用します。ヘッダーの後に、最初のプロジェクトの名前でprojectという変数を設定します。sudoのユーザー名を保持するuidという変数を追加します。
ユーザーのホームディレクトリへのパスを持つ変数baseも追加します。これは、%(variable_name)構文を使用して設定したユーザー名から構成されます。設定が読み込まれたときに、この変数の値で置き換えられます:
[uwsgi]
project = firstsite
uid = sammy
base = /home/%(uid)
次に、uWSGIを設定して、プロジェクトを正しく処理できるようにする必要があります。chdirオプションを設定して、ルートプロジェクトディレクトリに移動する必要があります。同じ変数構文を使用して、ホームディレクトリとプロジェクト名を組み合わせることができます。
同様に、プロジェクトのための仮想環境を示します。モジュールを設定することで、私たちのプロジェクトとのインターフェースを正確に示すことができます(内部プロジェクトディレクトリ内のwsgi.pyファイルから「application」をインポートすることによって)。これらの項目の構成は次のようになります:
[uwsgi]
project = firstsite
uid = sammy
base = /home/%(uid)
chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application
私たちは5つのワーカーを持つマスタープロセスを作成したいと考えています。これを追加することで実現できます:
[uwsgi]
project = firstsite
uid = sammy
base = /home/%(uid)
chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application
master = true
processes = 5
次に、uWSGIが接続をリッスンする方法を指定する必要があります。私たちのuWSGIのテストでは、HTTPとネットワークポートを使用しました。しかし、Nginxをリバースプロキシとして使用するので、より良い選択肢があります。
ネットワークポートを使う代わりに、すべてのコンポーネントが単一のサーバーで動作しているため、Unixソケットを使用することができます。これはより安全で、パフォーマンスも向上します。このソケットはHTTPを使用せず、代わりにuWSGIのuwsgiプロトコルを実装します。これは他のサーバーとの通信のために設計された高速バイナリプロトコルです。Nginxはuwsgiプロトコルをネイティブにプロキシすることができるため、これは私たちの最良の選択です。
私たちは、ウェブサーバーに書き込みアクセスを付与するため、ソケットの所有権と権限も変更します。サービスが停止したときにソケットファイルが自動的にクリーンアップされるように、vacuumオプションを設定します。
[uwsgi]
project = firstsite
uid = sammy
base = /home/%(uid)
chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application
master = true
processes = 5
socket = /run/uwsgi/%(project).sock
chown-socket = %(uid):www-data
chmod-socket = 660
vacuum = true
これで、私たちの最初のプロジェクトのuWSGI設定が完了しました。ファイルを保存して閉じてください。
変数を使用してファイルを設定する利点は、それが再利用を非常に簡単にすることです。最初のプロジェクトの構成ファイルをコピーして、2番目の構成ファイルのベースとして使用します:
- sudo cp /etc/uwsgi/sites/firstsite.ini /etc/uwsgi/sites/secondsite.ini
テキストエディタで2番目の設定ファイルを開いてください:
- sudo nano /etc/uwsgi/sites/secondsite.ini
このファイルの単一の値を変更する必要があるだけで、私たちの第二のプロジェクトに対応させることができます。project変数を、あなたの第二のプロジェクトで使用した名前に変更してください:
[uwsgi]
project = secondsite
uid = sammy
base = /home/%(uid)
chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application
master = true
processes = 5
socket = /run/uwsgi/%(project).sock
chown-socket = %(uid):www-data
chmod-socket = 660
vacuum = true
作業が終わったら、ファイルを保存して閉じてください。あなたの2つ目のプロジェクトは今すぐにでも始められるはずです。
uWSGIのためのsystemdユニットファイルを作成する
私たちは現在、Djangoプロジェクトを提供するために必要な設定ファイルを持っていますが、まだプロセスを自動化していません。次に、uWSGIエンペラー プロセスを管理し、ブート時にuWSGIを自動的に起動するためのsystemdユニットファイルを作成します。
私たちは、管理者が作成したユニットファイルが保存されている/etc/systemd/systemディレクトリにユニットファイルを作成します。私たちのファイルはuwsgi.serviceと呼ぶことにします:
- sudo nano /etc/systemd/system/uwsgi.service
まず [Unit] セクションから始めます。これはメタデータと順序情報を指定するために使用されます。ここに私たちのサービスの説明を入れましょう:
[Unit]
Description=uWSGI Emperor service
次に、[Service] セクションを開きます。ExecStartPre ディレクティブを使用して、サーバーを実行するために必要な部分を設定します。これにより、/run/uwsgi ディレクトリが作成され、通常のユーザーがその所有者となり、グループ所有者として www-data グループが設定されます。-p フラグ付きの mkdir と chown コマンドは、操作が必要でなくても成功を返します。これが私たちが望んでいることです。
実際の起動コマンドについて、ExecStart ディレクティブで指定されたものとして、uwsgi 実行可能ファイルを指します。複数のアプリケーションを管理できる「エンペラーモード」で実行するように指示します。これは /etc/uwsgi/sites で見つけたファイルを使用します。また、systemd がプロセスを正しく管理するために必要な部分も追加します。これらは uWSGI ドキュメントから取られています。
[Unit]
Description=uWSGI Emperor service
[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown sammy:www-data /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
さて、私たちが行う必要があるのは、[Install]セクションを追加することだけです。これにより、サービスが自動的に開始されるべき時期を指定できます。私たちはサービスをマルチユーザーシステムの状態に結びつけます。システムが複数のユーザー向けに設定されている(通常の操作条件)場合、私たちのサービスがアクティベートされます。
[Unit]
Description=uWSGI Emperor service
[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown sammy:www-data /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
[Install]
WantedBy=multi-user.target
終わったら、ファイルを保存して閉じてください。
この時点では、www-dataユーザーが利用可能であることに依存しているため、サービスを正常に開始することができません。NginxがインストールされるまでuWSGIサービスを開始するのを待たなければなりません。
Nginxをリバースプロキシとしてインストールして構成する
uWSGIが設定され、準備が整ったので、次にNginxをリバースプロキシとしてインストールおよび設定することができます。これはUbuntuのデフォルトリポジトリからダウンロードできます:
- sudo apt-get install nginx
Nginxがインストールされると、各プロジェクトのためにサーバーブロックの構成ファイルを作成することができます。 最初のプロジェクトから始めて、サーバーブロックの構成ファイルを作成します:
- sudo nano /etc/nginx/sites-available/firstsite
内部では、最初のプロジェクトにアクセスできるポート番号とドメイン名を示すことによってサーバーブロックを開始できます。server_nameブロックは、サーバーのドメイン名のいずれかまたはそのIPアドレスと一致する必要があります。さもなければ、デフォルトのNginxページが代わりに使用される可能性があります。それぞれにドメイン名があると仮定します:
server {
listen 80;
server_name firstsite.com www.firstsite.com;
}
次に、Nginxにファビコンが見つからない場合は心配しないように指示できます。また、サイトの静的要素を格納した静的ファイルディレクトリの場所を指示します:
server {
listen 80;
server_name firstsite.com www.firstsite.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/sammy/firstsite;
}
}
次に、追加のクエリをすべて私たちのアプリケーションに直接渡すキャッチオールのロケーションブロックを作成できます。uwsgiパラメーターは/etc/nginx/uwsgi_paramsに含まれており、uWSGIサーバーが設定したソケットにトラフィックを渡します:
server {
listen 80;
server_name firstsite.com www.firstsite.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/sammy/firstsite;
}
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/firstsite.sock;
}
}
これで、最初のサーバーブロックは完成です。
これを私たちの2番目のプロジェクトのNginx設定ファイルの基礎として使用します。 今すぐコピーしてください:
- sudo cp /etc/nginx/sites-available/firstsite /etc/nginx/sites-available/secondsite
テキストエディタで新しいファイルを開いてください:
- sudo nano /etc/nginx/sites-available/secondsite
ここでは、firstsiteへのすべての参照をsecondsiteへの参照に変更する必要があります。また、server_nameを修正して、あなたの二番目のプロジェクトが異なるドメイン名に応答するようにするか、複数のドメイン名またはIPアドレスがない場合はポートを変更する必要があります。終了すると、こんな感じになります:
server {
listen 80;
server_name secondsite.com www.secondsite.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/sammy/secondsite;
}
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/secondsite.sock;
}
}
作業が完了したら、ファイルを保存して閉じてください。
次に、新しい構成ファイルを両方ともNginxのsites-enabledディレクトリにリンクして有効にします:
- sudo ln -s /etc/nginx/sites-available/firstsite /etc/nginx/sites-enabled
- sudo ln -s /etc/nginx/sites-available/secondsite /etc/nginx/sites-enabled
次のように入力して構成構文を確認してください:
- sudo nginx -t
構文エラーが検出されない場合は、新しい設定を読み込むためにNginxサービスを再起動できます。
- sudo systemctl restart nginx
前に言ったように、私たちは実際にuWSGIサーバーを始めていませんでした。今、これを入力して開始してください:
- sudo systemctl start uwsgi
ポート8080へのUFWルールを削除し、代わりに私たちのNginxサーバーへのアクセスを許可しましょう:
- sudo ufw delete allow 8080
- sudo ufw allow 'Nginx Full'
あなたは今、各プロジェクトのドメイン名にアクセスすることで、2つのプロジェクトに到達できるようになっているはずです。公開インターフェースと管理インターフェースの両方が期待通りに機能するはずです。
これがうまくいけば、次のコマンドを入力することで、両方のサービスを自動的に起動時に開始できるように設定できます。
- sudo systemctl enable nginx
- sudo systemctl enable uwsgi
ノート
Nginxを設定した後の次のステップは、SSL/TLSを使用してサーバーへのトラフィックを保護することです。これは、これがないと、パスワードを含むすべての情報がプレーンテキストでネットワーク上に送信されるため、重要です。
ドメイン名を持っている場合、トラフィックを保護するためのSSL証明書を取得する最も簡単な方法は、Let’s Encryptを使用することです。このガイドに従って、Ubuntu 16.04上でNginxとLet’s Encryptを設定してください。
ドメイン名がない場合でも、自己署名のSSL証明書を使用して、テストや学習のためにサイトを保護することができます。
NginxとuWSGIのトラブルシューティング
アプリケーションにアクセスできない場合は、インストールのトラブルシューティングを行う必要があります。
NginxがDjangoアプリケーションの代わりにデフォルトページを表示しています
Nginxがデフォルトページを表示し、アプリケーションへのプロキシを行わない場合、通常は/etc/nginx/sites-available/firstsiteファイル内のserver_nameをサーバーのIPアドレスまたはドメイン名に指すように調整する必要があることを意味します。
Nginxはserver_nameを使用して、リクエストに応答するためにどのサーバーブロックを使用するかを決定します。デフォルトのNginxページが表示されている場合、これはNginxがリクエストを明示的にサーバーブロックに一致させることができなかったことを示しており、/etc/nginx/sites-available/defaultに定義されたデフォルトブロックにフォールバックしています。
プロジェクトのサーバーブロック内のserver_nameは、デフォルトのサーバーブロック内のものよりも具体的でなければ選択されません。
NginxがDjangoアプリケーションの代わりに502 Bad Gatewayエラーを表示しています
502エラーは、Nginxがリクエストを正常にプロキシできないことを示します。502エラーはさまざまな構成の問題を示しているため、適切にトラブルシューティングするにはより多くの情報が必要です。
詳細情報を探す主な場所はNginxのエラーログです。一般的に、これによりプロキシングイベント中に問題を引き起こした条件がわかります。Nginxのエラーログを確認するには、次のように入力します:
- sudo tail -F /var/log/nginx/error.log
さて、ブラウザで別のリクエストをして新しいエラーを生成してください(ページを更新してみてください)。ログに新しいエラーメッセージが記録されるはずです。メッセージを見れば、問題を特定する手助けになるでしょう。
次のメッセージのいくつかを見ることができるかもしれません:
connect() が unix:/run/uwsgi/firstsite.sock に失敗しました (2: 該当するファイルやディレクトリがありません)
これは、Nginx が指定された場所にソケットファイルを見つけられなかったことを示しています。/etc/nginx/sites-available フォルダ内の firstsite および secondsite ファイルで定義された uwsgi_pass の場所を、/run/uwsgi ディレクトリ内の実際の firstsite.sock および secondsite.sock ソケットファイルの場所と比較する必要があります。
/run/uwsgi ディレクトリ内にソケットファイルが存在するか確認するには、次のコマンドを入力してください:
- sudo ls /run/uwsgi
/run/uwsgiにソケットファイルがない場合、一般的にuwsgiプロセスがそれを作成できなかったことを意味します。uwsgiプロセスの状態を確認して、それが起動できたかどうかを調べてください:
- sudo systemctl status uwsgi
もしsystemctl statusコマンドがエラーが発生したことを示したり、ディレクトリ内にソケットファイルが見つからない場合、それはuWSGIが正しく起動できなかったことを示しています。次のコマンドを入力してuWSGIプロセスのログを確認してください:
- sudo journalctl -u uwsgi
ログにあるメッセージを見て、uWSGIが問題に直面した場所を特定してください。問題が発生した理由はいくつかありますが、しばしばuWSGIがソケットファイルを作成できない場合、それは次の理由のいずれかによるものです:
- プロジェクトファイルは、
sudoユーザーではなく、rootユーザーが所有しています。 /etc/systemd/system/uwsgi.serviceファイル内のExecStartPre行には、ディレクトリを作成し所有権を割り当てるための正しいコマンドが含まれていません。- サイト設定ファイルの
/etc/nginx/sites-availableディレクトリにあるuwsgi_passパスは、正しいソケットの場所を指していません。 「/etc/uwsgi/sites」ディレクトリ内の
.iniファイルに定義されているuWSGIの設定が不正です。次の項目を確認してください:chdirディレクティブは、一度補間されると、メインプロジェクトディレクトリを指します。
homeディレクティブは、一度補間されると、仮想環境ディレクトリを指します。- この
moduleディレクティブは、内側のプロジェクトディレクトリからwsgi.pyファイルをロードするために、Python モジュールのインポート構文を使用します。 socketディレクティブは、/run/uwsgiファイル内のファイルを指します(これは、上記のサービスファイルのExecStartPre行によって作成される必要があります)。
/etc/systemd/system/uwsgi.serviceファイルに変更を加えた場合は、デーモンを再読み込みしてサービス定義を再読み込みし、以下のコマンドを入力してuWSGIプロセスを再起動してください:
- sudo systemctl daemon-reload
- sudo systemctl restart uwsgi
これらの問題を修正することで、Nginxがソケットファイルを正しく見つけられるようになるはずです。
unix:/run/uwsgi/firstsite.sock への接続に失敗しました (13: 権限が拒否されました)
これは、Nginxが権限の問題によりuWSGIソケットに接続できなかったことを示しています。通常、これはソケットが制限された環境で作成されるか、または権限が誤っている場合に発生します。uWSGIプロセスはソケットファイルを作成することができますが、Nginxはそれにアクセスできません。
これは、ソケットファイルとの間のルートディレクトリ(/)のいずれかのポイントで権限が制限されている場合に発生する可能性があります。ソケットファイルとその親ディレクトリの権限と所有権の値は、ソケットファイルの絶対パスをnameiコマンドに渡すことで確認できます。
- namei -nom /run/uwsgi/firstsite.sock
f: /run/uwsgi/firstsite.sock
drwxr-xr-x root root /
drwxr-xr-x root root run
drwxr-xr-x sammy www-data uwsgi
srw-rw---- sammy www-data firstsite.sock
出力は各ディレクトリコンポーネントの権限を表示します。権限(最初の列)、所有者(2番目の列)、およびグループ所有者(3番目の列)を見れば、ソケットファイルに許可されているアクセスの種類を理解できます。
上記の例では、ソケットファイルに至る各ディレクトリには、全ユーザーが読み取りおよび実行できる権限があります(ディレクトリの権限列はr-xで終わります)。www-dataグループはソケット自体のグループ所有権を持っています。これらの設定のもとでは、Nginxプロセスはソケットに正常にアクセスできるはずです。
ソケットに至るディレクトリのいずれかが www-data グループに属していないか、世界読み取りおよび実行権限を持っていない場合、Nginx はソケットにアクセスできません。通常、これは設定ファイルに誤りがあることを意味します。
ディレクトリパスに権限や所有権が過度に制限されている場合は、/etc/systemd/system/uwsgi.serviceファイルを確認してください。ExecStartPreディレクティブは、/run/uwsgiディレクトリを作成し、www-dataグループにグループ所有権を割り当てる役割を担っています。ここでのコマンドが正しくない場合、ディレクトリパスが過度に制限されている可能性があります。
ソケットファイル自体がNginxプロセスにアクセスできない場合、/etc/uwsgi/sites内の.iniファイルで定義された設定が誤っている可能性があります。webプロセスがファイルにアクセスできる権限が与えられていることを確認するために、chown-socketおよびchmod-socketの値を確認してください。
さらなるトラブルシューティング
追加のトラブルシューティングのために、ログは根本原因を特定するのに役立ちます。それぞれを順に確認し、問題のある領域を示すメッセージを探してください。
次のログが役立つかもしれません:
- 次のコマンドを入力してNginxプロセスのログを確認してください:
sudo journalctl -u nginx - Nginxのアクセスログを確認するには、以下のコマンドを入力します:
sudo less /var/log/nginx/access.log - Nginxのエラーログを確認するには、次のコマンドを入力します:
sudo less /var/log/nginx/error.log - uWSGIアプリケーションのログを確認するには、次のように入力します:
sudo journalctl -u uwsgi
設定やアプリケーションを更新する際には、変更に対応するためにプロセスを再起動する必要があるでしょう。
Djangoアプリケーションを更新した場合は、以下のように入力してuWSGIプロセスを再起動し、変更を反映させることができます:
- sudo systemctl restart uwsgi
uwsgi システムdサービスファイルを変更した場合は、デーモンを再読み込みし、次のように入力してプロセスを再起動します:
- sudo systemctl daemon-reload
- sudo systemctl restart uwsgi
Nginxのサーバーブロック設定を変更した場合は、設定をテストしてから次のようにNginxを実行してください:
- sudo nginx -t && sudo systemctl restart nginx
これらのコマンドは、設定を調整する際に変更を把握するのに役立ちます。
結論
このガイドでは、各プロジェクトをそれぞれの仮想環境内で設定した二つのDjangoプロジェクトを用意しました。各プロジェクト用に設定された仮想環境を使用して、uWSGIを独立して各プロジェクトを提供するように構成しました。その後、クライアントの接続を処理し、クライアントのリクエストに応じた正しいプロジェクトを提供するために、Nginxをリバースプロキシとして設定しました。
Djangoは、一般的な部分を多く提供することにより、プロジェクトやアプリケーションの作成を簡単にし、ユニークな要素に集中できるようにします。この文章で説明されている一般的なツールチェーンを活用することで、作成したアプリケーションを単一のサーバーから簡単に提供できます。


