Ubuntu18.04でuWSGIとNginxを使用してFlaskアプリケーションを提供する方法
序章
このガイドでは、Ubuntu18.04でFlaskマイクロフレームワークを使用してPythonアプリケーションを構築します。 この記事の大部分は、 uWSGIアプリケーションサーバーをセットアップする方法と、アプリケーションを起動し、フロントエンドリバースプロキシとして機能するようにNginxを構成する方法について説明します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
-
Ubuntu 18.04がインストールされ、sudo権限とファイアウォールが有効になっているroot以外のユーザーがいるサーバー。 ガイダンスについては、初期サーバーセットアップガイドに従ってください。
-
Ubuntu 18.04にNginxをインストールする方法のステップ1と2に従って、Nginxをインストールしました。
-
サーバーを指すように構成されたドメイン名。 Namecheap で購入するか、Freenomで無料で入手できます。 ドメインとDNSに関する関連するドキュメントに従うことで、ドメインをDigitalOceanにポイントする方法を学ぶことができます。 必ず次のDNSレコードを作成してください。
- サーバーのパブリックIPアドレスを指す
your_domain
のAレコード。 - サーバーのパブリックIPアドレスを指す
www.your_domain
のAレコード。
- サーバーのパブリックIPアドレスを指す
-
uWSGI、アプリケーションサーバー、およびWSGI仕様に精通していること。 定義と概念に関するこのディスカッションでは、両方について詳しく説明します。
ステップ1—Ubuntuリポジトリからコンポーネントをインストールする
最初のステップは、Ubuntuリポジトリから必要なすべての部分をインストールすることです。 Pythonコンポーネントを管理するために、Pythonパッケージマネージャーであるpip
をインストールします。 また、uWSGIのビルドに必要なPython開発ファイルも入手できます。
まず、ローカルパッケージインデックスを更新します。
- sudo apt update
次に、Python環境を構築できるようにするパッケージをインストールします。 これらには、python3-pip
に加えて、堅牢なプログラミング環境に必要ないくつかのパッケージと開発ツールが含まれます。
- sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
これらのパッケージを配置したら、プロジェクトの仮想環境の作成に進むことができます。
ステップ2—Python仮想環境を作成する
次に、Flaskアプリケーションをシステム上の他のPythonファイルから分離するために、仮想環境をセットアップします。
python3-venv
パッケージをインストールすることから始めます。これにより、venv
モジュールがインストールされます。
- sudo apt install python3-venv
次に、Flaskプロジェクトの親ディレクトリを作成します。
- mkdir ~/myproject
次に、ディレクトリを作成した後、ディレクトリに移動します。
- cd ~/myproject
次のコマンドを実行して、FlaskプロジェクトのPython要件を保存する仮想環境を作成します。
- python3.6 -m venv myprojectenv
これにより、Pythonとpip
のローカルコピーが、プロジェクトディレクトリ内のmyprojectenv
というディレクトリにインストールされます。
仮想環境内にアプリケーションをインストールする前に、それをアクティブ化する必要があります。
- source myprojectenv/bin/activate
プロンプトが変わり、仮想環境内で操作していることを示します。 (myprojectenv) user@host:~/myproject$
のように表示されます。
ステップ3—Flaskアプリケーションのセットアップ
これで仮想環境ができたので、FlaskとuWSGIをインストールして、アプリケーションの設計を開始できます。
まず、pip
のローカルインスタンスを使用してwheel
をインストールし、ホイールアーカイブがない場合でもパッケージがインストールされるようにします。
- pip install wheel
注:使用しているPythonのバージョンに関係なく、仮想環境をアクティブ化するときは、pip
コマンドを使用する必要があります(pip3
ではありません)。
次に、FlaskとuWSGIをインストールします。
- pip install uwsgi flask
インストールが完了したら、Flaskの使用を開始できます。
サンプルアプリの作成
Flaskを利用できるようになったので、簡単なアプリケーションを作成できます。 ご存知かもしれませんが、Flaskはマイクロフレームワークであり、よりフル機能のフレームワークにあるようなツールの多くは含まれていません。 Flaskは主に、Webアプリケーションの初期化を支援するためにプロジェクトにインポートできるモジュールとして存在します。
アプリケーションはもっと複雑かもしれませんが、Flaskアプリを1つのファイルで作成します。 お気に入りのテキストエディタを使用してファイルを作成できます。 この例では、nano
を使用し、myproject.py
という名前を付けます。
- nano ~/myproject/myproject.py
アプリケーションコードはこのファイルに存在します。 Flaskをインポートし、Flaskオブジェクトをインスタンス化します。 これを使用して、特定のルートが要求されたときに実行する必要がある関数を定義できます。
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "<h1 style='color:blue'>Hello There!</h1>"
if __name__ == "__main__":
app.run(host='0.0.0.0')
これは、ルートドメインにアクセスしたときに表示するコンテンツを定義します。 終了したら、ファイルを保存して閉じます。 nano
を使用している場合は、CTRL + X
、Y
、ENTER
の順に押すとこれを行うことができます。
サーバーの初期設定ガイドに従っている場合は、UFWファイアウォールを有効にする必要があります。 アプリケーションをテストするには、ポート5000
へのアクセスを許可する必要があります。
- sudo ufw allow 5000
次に、Flaskアプリをテストします。
- python myproject.py
このサーバーセットアップを本番環境で使用しないように通知する役立つ警告を含む、次のような出力が表示されます。
Output* Serving Flask app "myproject" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
WebブラウザでサーバーのIPアドレスにアクセスし、続いて:5000
にアクセスします。
http://your_server_ip:5000
次のようなものが表示されます。
終了したら、ターミナルウィンドウでCTRL + C
を押して、Flask開発サーバーを停止します。
WSGIエントリポイントの作成
次に、アプリケーションのエントリポイントとして機能するファイルを作成します。 これにより、uWSGIサーバーとの対話方法がわかります。
まず、ファイルを作成してwsgi.py
という名前を付けます。
- nano ~/myproject/wsgi.py
このファイルで、アプリケーションからFlaskインスタンスをインポートして、実行します。
from myproject import app
if __name__ == "__main__":
app.run()
終了したら、ファイルを保存して閉じます。
ステップ4—uWSGIを構成する
これで、アプリケーションはエントリポイントが確立された状態で作成されました。 これで、uWSGIの構成に進むことができます。
uWSGIサービングのテスト
さらに変更を加える前に、uWSGIがアプリケーションに対応できることをテストすると役立つ場合があります。
これを行うには、エントリポイントの名前をuWSGIに渡します。 これは、モジュールの名前(.py
拡張子を除く)とアプリケーション内の呼び出し可能オブジェクトの名前で構成されます。 この場合、エントリポイントの名前はwsgi:app
です。
また、ソケットを指定して、公開されているインターフェイスとプロトコルで開始されるようにし、uwsgi
バイナリプロトコルの代わりにHTTPを使用するようにします。 以前に開いたのと同じポート番号5000
を使用します。
- uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app
Webブラウザの末尾に:5000
を追加して、サーバーのIPアドレスに再度アクセスします。
http://your_server_ip:5000
アプリケーションの出力を再度受け取る必要があります。
正常に動作していることを確認したら、ターミナルウィンドウでCTRL + C
を押します。
仮想環境の使用が完了したので、仮想環境を非アクティブ化できます。
- deactivate
すべてのPythonコマンドは、システムのPython環境を再び使用するようになります。
uWSGI構成ファイルの作成
uWSGIがアプリケーションに対応できることをテストおよび検証しましたが、最終的には、長期間使用するためにより堅牢なものが必要になります。 これに関連するオプションを使用して、uWSGI構成ファイルを作成できます。
そのファイルをプロジェクトディレクトリに配置し、myproject.ini
と呼びます。
- nano ~/myproject/myproject.ini
内部では、[uwsgi]
ヘッダーから始めて、uWSGIが設定を適用できるようにします。 wsgi.py
ファイルから拡張子を引いたものを参照するモジュール自体と、ファイル内の呼び出し可能ファイルapp
の2つを指定します。
[uwsgi]
module = wsgi:app
次に、uWSGIにマスターモードで起動し、実際のリクエストを処理するために5つのワーカープロセスを生成するように指示します。
[uwsgi]
module = wsgi:app
master = true
processes = 5
テストしているときに、ネットワークポートでuWSGIを公開しました。 ただし、実際のクライアント接続を処理するためにNginxを使用することになります。これにより、リクエストがuWSGIに渡されます。 これらのコンポーネントは同じコンピューター上で動作するため、Unixソケットの方が高速で安全です。 ソケットmyproject.sock
を呼び出して、このディレクトリに配置します。
また、ソケットのアクセス許可を変更します。 これにより、後でuWSGIプロセスのNginxグループ所有権が付与されるため、ソケットのグループ所有者がソケットから情報を読み取ったり、書き込みたりできることを確認してください。 さらに、vacuum
オプションを追加して、プロセスが停止したときにソケットをクリーンアップします。
[uwsgi]
module = wsgi:app
master = true
processes = 5
socket = myproject.sock
chmod-socket = 660
vacuum = true
最後に行うことは、die-on-term
オプションを設定することです。 これは、initシステムとuWSGIが各プロセス信号の意味について同じ仮定を持つことを保証するのに役立ちます。 これを設定すると、2つのシステムコンポーネントが調整され、期待される動作が実装されます。
[uwsgi]
module = wsgi:app
master = true
processes = 5
socket = myproject.sock
chmod-socket = 660
vacuum = true
die-on-term = true
コマンドラインから指定したようにプロトコルを指定しなかったことにお気づきかもしれません。 これは、デフォルトでは、uWSGIがuwsgi
プロトコルを使用して通信するためです。これは、他のサーバーと通信するように設計された高速バイナリプロトコルです。 Nginxはこのプロトコルをネイティブに話すことができるため、HTTPによる通信を強制するよりもこれを使用する方が適切です。
終了したら、ファイルを保存して閉じます。
ステップ5—systemdユニットファイルを作成する
次に、systemdサービスユニットファイルを作成します。 systemdユニットファイルを作成すると、Ubuntuのinitシステムが自動的にuWSGIを起動し、サーバーが起動するたびにFlaskアプリケーションを提供できるようになります。
/etc/systemd/system
ディレクトリ内に.service
で終わるユニットファイルを作成して開始します。
- sudo nano /etc/systemd/system/myproject.service
ファイル内で、メタデータと依存関係を指定するために使用される[Unit]
セクションから始めます。 ここにサービスを説明し、ネットワークターゲットに到達した後にのみ開始するようにinitシステムに指示します。
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
次に、[Service]
セクションを開きます。 これにより、プロセスを実行するユーザーとグループが指定されます。 プロセスは関連するすべてのファイルを所有しているため、通常のユーザーアカウントにプロセスの所有権を与えます。 また、www-data
グループにグループの所有権を付与して、NginxがuWSGIプロセスと簡単に通信できるようにします。 ここでのユーザー名を自分のユーザー名に置き換えることを忘れないでください。
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
[Service]
User=sammy
Group=www-data
次に、作業ディレクトリをマップし、PATH
環境変数を設定して、プロセスの実行可能ファイルが仮想環境内にあることをinitシステムが認識できるようにします。 また、サービスを開始するコマンドを指定します。 Systemdでは、仮想環境内にインストールされているuWSGI実行可能ファイルへのフルパスを指定する必要があります。 プロジェクトディレクトリに作成した.ini
構成ファイルの名前を渡します。
ユーザー名とプロジェクトパスを独自の情報に置き換えることを忘れないでください。
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
次に、[Install]
セクションを追加します。 これにより、起動時にサービスを開始できるようにした場合に、このサービスを何にリンクするかがsystemdに通知されます。 通常のマルチユーザーシステムが稼働しているときにこのサービスを開始する必要があります。
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
[Install]
WantedBy=multi-user.target
これで、systemdサービスファイルが完成しました。 今すぐ保存して閉じます。
これで、作成したuWSGIサービスを開始し、起動時に開始するように有効にすることができます。
- sudo systemctl start myproject
- sudo systemctl enable myproject
ステータスを確認します。
- sudo systemctl status myproject
次のような出力を受け取るはずです。
Output● myproject.service - uWSGI instance to serve myproject
Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset
Active: active (running) since Mon 2021-10-25 22:34:52 UTC; 14s ago
Main PID: 9391 (uwsgi)
Tasks: 6 (limit: 1151)
CGroup: /system.slice/myproject.service
├─9391 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i
├─9410 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i
├─9411 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i
├─9412 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i
├─9413 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i
└─9414 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i
エラーが発生した場合は、チュートリアルを続行する前に必ず解決してください。
ステップ6—リクエストをプロキシするためのNginxの設定
これで、uWSGIアプリケーションサーバーが稼働し、プロジェクトディレクトリのソケットファイルに対する要求を待機しているはずです。 これで、uwsgi
プロトコルを使用してそのソケットにWebリクエストを渡すようにNginxを構成できます。
Nginxのsites-available
ディレクトリに新しいサーバーブロック構成ファイルを作成することから始めます。 ガイドの残りの部分との一貫性を保つために、myproject
という名前を付けます。
- sudo nano /etc/nginx/sites-available/myproject
サーバーブロックを開き、デフォルトのポート80
でリッスンするようにNginxに指示します。 また、サーバーのドメイン名のリクエストにこのブロックを使用するように指示します。
server {
listen 80;
server_name your_domain www.your_domain;
}
次に、すべてのリクエストに一致するロケーションブロックを追加します。 このブロック内に、設定が必要ないくつかの一般的なuWSGIパラメーターを指定するuwsgi_params
ファイルを含めます。 次に、uwsgi_pass
ディレクティブを使用して定義したソケットにリクエストを渡します。
server {
listen 80;
server_name your_domain www.your_domain;
location / {
include uwsgi_params;
uwsgi_pass unix:/home/sammy/myproject/myproject.sock;
}
}
終了したら、ファイルを保存して閉じます。
作成したNginxサーバーブロック構成を有効にするには、ファイルをsites-enabled
ディレクトリにリンクします。
- sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
そのディレクトリにあるファイルを使用して、次のコマンドを実行して構文エラーをテストできます。
- sudo nginx -t
これが問題を示さずに戻った場合は、Nginxプロセスを再起動して、新しい構成を読み取ります。
- sudo systemctl restart nginx
次に、ファイアウォールを再度調整します。 ポート5000
を介してアクセスする必要がなくなったため、次のルールを削除できます。
- sudo ufw delete allow 5000
その後、Nginxサーバーへのアクセスを許可します。
- sudo ufw allow 'Nginx Full'
これで、Webブラウザでサーバーのドメイン名に移動できるようになります。
http://your_domain
アプリケーションの出力が表示されます。
エラーが発生した場合は、以下を確認してください。
sudo less /var/log/nginx/error.log
:Nginxエラーログをチェックします。sudo less /var/log/nginx/access.log
:Nginxアクセスログをチェックします。sudo journalctl -u nginx
:Nginxプロセスログをチェックします。sudo journalctl -u myproject
:FlaskアプリのuWSGIログを確認します。
ステップ7—アプリケーションの保護
サーバーへのトラフィックを安全に保つには、ドメインのSSL証明書を取得する必要があります。 これを行うには、 Let’s Encrypt から無料の証明書を取得する、自己署名証明書を生成する、別のプロバイダーから証明書を購入するなど、複数の方法があります。 Nginxは、 Ubuntu18.04でNginxの自己署名SSL証明書を作成する方法のステップ2から6に従って使用します。 便宜上、オプション1でデモンストレーションを行います。 完全なチュートリアルについては、 Ubuntu18.04でLet’sEncryptを使用してNginxを保護する方法を確認してください。
まず、CertbotUbuntuリポジトリを追加します。
- sudo add-apt-repository ppa:certbot/certbot
同意するには、ENTER
を押す必要があります。
次に、apt
を使用してCertbotのNginxパッケージをインストールします。
- sudo apt install python-certbot-nginx
Certbotは、プラグインを介してSSL証明書を取得するためのさまざまな方法を提供します。 Nginxプラグインは、Nginxの再構成と、必要に応じて構成の再読み込みを処理します。 このプラグインを使用するには、次を実行します。
- sudo certbot --nginx -d your_domain -d www.your_domain
これは、--nginx
プラグインでcertbot
を実行し、-d
を使用して、証明書を有効にする名前を指定します。
certbot
を初めて実行する場合は、メールアドレスを入力して利用規約に同意するよう求められます。 その後、certbot
はLet’sEncryptサーバーと通信し、チャレンジを実行して、証明書を要求しているドメインを制御していることを確認します。
それが成功すると、certbot
はHTTPS設定をどのように構成するかを尋ねます。
OutputPlease choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
選択してENTER
を押してください。 構成が更新され、Nginxがリロードして新しい設定を取得します。 certbot
は、プロセスが成功し、証明書が保存されている場所を通知するメッセージで終了します。
OutputIMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/your_domain/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/your_domain/privkey.pem
Your cert will expire on 2022-01-24. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option. To non-interactively renew *all* of
your certificates, run "certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
前提条件のNginxインストール手順に従った場合、冗長HTTPプロファイルの許容量は不要になります。
- sudo ufw delete allow 'Nginx HTTP'
構成を確認するには、https://
を使用して、もう一度ドメインに移動します。
https://your_domain
サイトが保護されていることを示すブラウザのセキュリティインジケータとともに、アプリケーションの出力がもう一度表示されます。
結論
このガイドでは、Python仮想環境内で単純なFlaskアプリケーションを作成して保護しました。 WSGI対応のアプリケーションサーバーがWSGIエントリポイントとインターフェイスできるようにWSGIエントリポイントを作成し、この機能を提供するようにuWSGIアプリサーバーを構成しました。 その後、起動時にアプリケーションサーバーを自動的に起動するsystemdサービスファイルを作成しました。 また、Webクライアントトラフィックをアプリケーションサーバーに渡し、外部要求を中継し、Let’sEncryptを使用してサーバーへのトラフィックを保護するNginxサーバーブロックを作成しました。
Flaskは非常に柔軟なフレームワークであり、構造や設計をあまり制限することなく、アプリケーションに機能を提供することを目的としています。 このガイドで説明されている一般的なスタックを使用して、設計するフラスコアプリケーションを提供できます。