Ubuntu18.04でGunicornとNginxを使用してFlaskアプリケーションを提供する方法
序章
このガイドでは、Ubuntu18.04でFlaskマイクロフレームワークを使用してPythonアプリケーションを構築します。 この記事の大部分は、 Gunicornアプリケーションサーバーをセットアップする方法と、アプリケーションを起動して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アドレスを指す
-
GunicornサーバーがFlaskアプリケーションとの通信に使用するWSGI仕様に精通していること。 このディスカッションでは、WSGIについて詳しく説明します。
ステップ1—Ubuntuリポジトリからコンポーネントをインストールする
最初のステップは、デフォルトのUbuntuリポジトリから必要なすべてのパッケージをインストールすることです。 これには、Pythonコンポーネントを管理するPythonパッケージマネージャーであるpip
が含まれます。 また、Gunicornコンポーネントの一部を構築するために必要な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)\ssammy@host:~/myproject$
ステップ3—Flaskアプリケーションのセットアップ
仮想環境にいるので、FlaskとGunicornをインストールして、アプリケーションの設計を開始できます。
まず、pip
のローカルインスタンスを使用してwheel
をインストールし、ホイールアーカイブがない場合でもパッケージがインストールされるようにします。
- pip install wheel
注:使用しているPythonのバージョンに関係なく、仮想環境をアクティブ化するときは、pip
コマンドを使用する必要があります(pip3
ではありません)。
次に、FlaskとGunicornをインストールします。
- pip install gunicorn flask
Flaskを使用できるようになったので、次のステップで基本的なアプリケーションを作成できます。
サンプルアプリケーションの作成
Flaskはマイクロフレームワークであるため、よりフル機能のフレームワークに含まれる可能性のあるツールの多くは含まれていません。 Flaskは主に、Webアプリケーションの初期化を支援するためにプロジェクトにインポートできるモジュールとして存在します。
アプリケーションはもっと複雑かもしれませんが、myproject.py
という単一のファイルにFlaskアプリケーションを作成します。 お好みのテキストエディタを使用してこのファイルを作成します。 ここではnano
を使用します。
- 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: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on all addresses.
WARNING: This is a development server. Do not use it in a production deployment.
* Running on http://your_server_ip:5000/ (Press CTRL+C to quit)
WebブラウザでサーバーのIPアドレスにアクセスし、続いて:5000
にアクセスします。
http://your_server_ip:5000
次のようなものを受け取るはずです。
終了したら、ターミナルウィンドウでCTRL + C
を押して、Flask開発サーバーを停止します。
WSGIエントリポイントの作成
次に、アプリケーションのエントリポイントとして機能するファイルを作成します。 これにより、Gunicornサーバーにアプリケーションとの対話方法が通知されます。
お好みのテキストエディタを使用して新しいファイルを作成し、名前を付けます。 ここでは、ファイルをwsgi.py
と呼びます。
- nano ~/myproject/wsgi.py
このファイルで、アプリケーションからFlaskインスタンスをインポートして、実行します。
from myproject import app
if __name__ == "__main__":
app.run()
終了したら、ファイルを保存して閉じます。
ステップ4—Gunicornの設定
これで、アプリケーションはエントリポイントが確立された状態で作成され、Gunicornの設定に進むことができます。
ただし、最初に、適切なディレクトリに移動します。
- cd ~/myproject
次に、エントリポイントの名前を渡すことで、Gunicornがアプリケーションを正しく提供できることを確認できます。 これは、モジュールの名前(.py
拡張子を除く)と、アプリケーション内の呼び出し可能オブジェクトの名前として構成されます。 この場合、これはwsgi:app
と表記されます。
また、公開されているインターフェイスでアプリケーションが起動するように、バインドするインターフェイスとポートを指定します。
- gunicorn --bind 0.0.0.0:5000 wsgi:app
次のような出力が表示されます。
Output[2021-11-19 23:07:57 +0000] [8760] [INFO] Starting gunicorn 20.1.0
[2021-11-19 23:07:57 +0000] [8760] [INFO] Listening at: http://0.0.0.0:5000 (8760)
[2021-11-19 23:07:57 +0000] [8760] [INFO] Using worker: sync
[2021-11-19 23:07:57 +0000] [8763] [INFO] Booting worker with pid: 8763
[2021-11-19 23:08:11 +0000] [8760] [INFO] Handling signal: int
[2021-11-19 23:08:11 +0000] [8760] [INFO] Shutting down: Master
Webブラウザの末尾に:5000
を追加して、サーバーのIPアドレスに再度アクセスします。
http://your_server_ip:5000
アプリケーションの出力は、以下を生成します。
正常に動作していることを確認したら、ターミナルウィンドウでCTRL + C
を押します。
これで仮想環境が完成したので、それを非アクティブ化します。
- deactivate
すべてのPythonコマンドは、システムのPython環境を再び使用するようになります。
次に、systemdサービスユニットファイルを作成します。 systemdユニットファイルを作成すると、Ubuntuのinitシステムが自動的にGunicornを起動し、サーバーが起動するたびにFlaskアプリケーションを提供できるようになります。
/etc/systemd/system
ディレクトリ内に.service
で終わるユニットファイルを作成して開始します。
- sudo nano /etc/systemd/system/myproject.service
内部では、メタデータと依存関係を指定するために使用される[Unit]
セクションから始めます。 ここにサービスの説明を追加し、ネットワークターゲットに到達した後にのみこれを開始するようにinitシステムに指示します。
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target
次に、[Service]
セクションを作成します。 これにより、プロセスを実行するユーザーとグループが指定されます。 プロセスは関連するすべてのファイルを所有しているため、プロセスの通常のユーザーアカウントの所有権を提供します。 また、 www-data グループにグループの所有権を付与して、NginxがGunicornプロセスと通信できるようにします。 ここでのユーザー名を自分のユーザー名に置き換えることを忘れないでください。
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target
[Service]
User=sammy
Group=www-data
次に、作業ディレクトリをマップし、PATH
環境変数を設定して、プロセスの実行可能ファイルが仮想環境内にあることをinitシステムが認識できるようにします。 また、サービスを開始するコマンドを指定してください。 このコマンドは次のことを行います。
- 3つのワーカープロセスを開始します(ただし、必要に応じてこれを調整する必要があります)
- プロジェクトディレクトリ内にUnixソケットファイル
myproject.sock
を作成してバインドします。 007
のumask値を設定して、他のアクセスを制限しながら、所有者とグループへのアクセスを許可するソケットファイルが作成されるようにします。- WSGIエントリポイントファイル名と、そのファイル内で呼び出し可能なPythonを指定します(
wsgi:app
)
Systemdでは、仮想環境内にインストールされているGunicorn実行可能ファイルへのフルパスを指定する必要があります。
ユーザー名とプロジェクトパスを独自の情報に置き換えることを忘れないでください。
[Unit]
Description=Gunicorn 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/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
最後に、[Install]
セクションを追加します。 これにより、起動時にサービスを開始できるようにした場合に、このサービスを何にリンクするかがsystemdに通知されます。 通常のマルチユーザーシステムが稼働しているときにこのサービスを開始する必要があります。
[Unit]
Description=Gunicorn 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/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
[Install]
WantedBy=multi-user.target
これで、systemdサービスファイルが完成しました。 今すぐ保存して閉じます。
次に、作成したGunicornサービスを開始します。
- sudo systemctl start myproject
次に、起動時に開始するように有効にします。
- sudo systemctl enable myproject
ステータスを確認します。
- sudo systemctl status myproject
次のような出力を受け取るはずです。
Output● myproject.service - Gunicorn instance to serve myproject
Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset
Active: active (running) since Fri 2021-11-19 23:08:44 UTC; 6s ago
Main PID: 8770 (gunicorn)
Tasks: 4 (limit: 1151)
CGroup: /system.slice/myproject.service
├─9291 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
├─9309 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
├─9310 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
└─9311 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
…
エラーが発生した場合は、チュートリアルを続行する前に必ず解決してください。
ステップ5—リクエストをプロキシするためのNginxの設定
これで、Gunicornアプリケーションサーバーが稼働し、プロジェクトディレクトリのソケットファイルに対するリクエストを待機しているはずです。 次に、構成ファイルにいくつかの小さな追加を行うことにより、そのソケットに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;
}
次に、すべてのリクエストに一致するロケーションブロックを追加します。 このブロック内に、設定する必要のあるいくつかの一般的なプロキシパラメータを指定するproxy_params
ファイルを含めます。 次に、proxy_pass
ディレクティブを使用して定義したソケットにリクエストを渡します。
server {
listen 80;
server_name your_domain www.your_domain;
location / {
include proxy_params;
proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
}
}
終了したら、ファイルを保存して閉じます。
作成したNginxサーバーブロック構成を有効にするには、ファイルをsites-enabled
ディレクトリにリンクします。 これを行うには、ln
コマンドと-s
フラグを実行して、ハードリンクではなく、シンボリックリンクまたはソフトリンクを作成します。
- 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アプリのGunicornログを確認します。
ステップ6—アプリケーションの保護
サーバーへのトラフィックを安全に保つには、ドメインのSSL証明書を取得する必要があります。 これを行うには、 Let’s Encrypt から無料の証明書を取得する、自己署名証明書を生成する、別のプロバイダーから証明書を購入するなど、複数の方法があります。 Nginxは、 Ubuntu18.04でNginxの自己署名SSL証明書を作成する方法のステップ2から6に従って使用します。 便宜上、オプション1を使用します。
まず、snap
を使用してCertbotをインストールします。
- sudo snap install --classic certbot
出力には、Certbotの現在のバージョンが表示され、インストールが成功したことが示されます。
Outputcertbot 1.21.0 from Certbot Project (certbot-eff✓) installed
次に、/usr/bin/
ディレクトリから新しくインストールされた/snap/bin/certbot
実行可能ファイルへのシンボリックリンクを作成します。 これにより、certbot
コマンドをサーバーで正しく実行できるようになります。
- sudo ln -s /snap/bin/certbot /usr/bin/certbot
Certbotは、プラグインを介してSSL証明書を取得するためのさまざまな方法を提供します。 Nginxプラグインは、Nginxの再構成と、必要に応じて構成の再読み込みを処理します。 このプラグインを使用するには、次のように入力します。
- sudo certbot --nginx -d your_domain -d www.your_domain
これは、--nginx
プラグインでcertbot
を実行し、-d
を使用して、証明書を有効にする名前を指定します。
certbot
を初めて実行する場合は、メールアドレスを入力して利用規約に同意するよう求められます。 その後、certbot
はLet’sEncryptサーバーと通信して、ドメインの証明書を要求します。 成功すると、次の出力が表示されます。
OutputSuccessfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/jeanellehorcasitasphd.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/jeanellehorcasitasphd.com/privkey.pem
This certificate expires on 2022-03-03.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate foryour_domain to /etc/nginx/sites-enabled/myproject
Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/myproject
Congratulations! You have successfully enabled HTTPS on https://your_domain and https://your_domain
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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エントリポイントを作成し、この機能を提供するようにGunicornアプリケーションサーバーを構成しました。 その後、起動時にアプリケーションサーバーを自動的に起動するsystemdサービスファイルを作成しました。 また、Let’s Encryptを使用して、外部リクエストを中継するためにWebクライアントトラフィックをアプリケーションサーバーに渡し、サーバーへのトラフィックを保護するNginxサーバーブロックを作成しました。
Flaskは非常に柔軟なフレームワークであり、構造や設計をあまり制限することなく、アプリケーションに機能を提供することを目的としています。 このガイドで説明されている一般的なスタックを使用して、設計したフラスコアプリケーションにサービスを提供できます。