ウェブサイト検索

Ubuntu 22.04でuWSGIとNginxを使用してFlaskアプリケーションを提供する方法


Ubuntu 22.04を使用していませんか?別のバージョンまたはディストリビューションを選択してください。

紹介

このガイドでは、Ubuntu 22.04上でFlaskマイクロフレームワークを使用してPythonアプリケーションを構築します。この記事の大部分は、uWSGIアプリケーションサーバーのセットアップ方法、アプリケーションの起動方法、Nginxをフロントエンドリバースプロキシとして構成する方法について説明します。

前提条件

このガイドを始める前に、あなたは以下のものを持っているべきです:

  • Ubuntu 22.04がインストールされたサーバーと、sudo権限を持つ非ルートユーザーが必要です。初期サーバー設定ガイドを参考にしてください。

  • Nginxがインストールされました。Ubuntu 22.04にNginxをインストールする方法のステップ1から3に従ってください。

  • あなたのサーバーに向けて設定されたドメイン名。Namecheapで購入するか、Freenomで無料で取得できます。ドメインをDigitalOceanに向ける方法については、ドメインとDNSに関する関連ドキュメントを参考にしてください。このチュートリアルでは、次のDNSレコードを作成したと仮定しています:

    • your_domain がサーバーのパブリックIPアドレスを指すAレコード。
    • www.your_domainがあなたのサーバーのパブリックIPアドレスを指しているAレコード。

さらに、このガイドで設定するアプリケーションサーバーであるuWSGIやWSGI仕様についての基本的な理解があると役立つかもしれません。この定義と概念の説明では、両方を詳細に説明します。

ステップ 1 — Ubuntu リポジトリからコンポーネントをインストールする

最初のステップは、Ubuntuのリポジトリから必要なすべてのパッケージをインストールすることです。 インストールする必要があるパッケージには、Pythonコンポーネントを管理するためのPythonパッケージマネージャーであるpipが含まれています。また、uWSGIをビルドするために必要なPython開発ファイルも取得します。

まず、ローカルパッケージインデックスを更新します:

  1. sudo apt update

次に、Python環境を構築するためのパッケージをインストールします。これには、python3-pipを含む、堅牢なプログラミング環境に必要な他のいくつかのパッケージや開発ツールが含まれます。

  1. sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

これらのパッケージが整ったら、プロジェクトのための仮想環境を作成する準備が整いました。

ステップ2 — Python仮想環境の作成

Pythonの仮想環境は、特定のプロジェクトに必要なPythonおよびPythonモジュールの特定のバージョンを含む自己完結型のプロジェクトディレクトリです。これは、同じシステム上の他のアプリケーションから1つのアプリケーションを隔離し、それぞれの依存関係を別々に管理するのに役立ちます。このステップでは、Flaskアプリケーションを実行するためのPython仮想環境を設定します。

venvモジュールをインストールするために、python3-venvパッケージのインストールを開始してください:

  1. sudo apt install python3-venv

次に、Flaskプロジェクトの親ディレクトリを作成します:

  1. mkdir ~/myproject

作成した後、そのディレクトリに移動します:

  1. cd ~/myproject

FlaskプロジェクトのPython要件を格納するために仮想環境を作成するには、次のように入力します:

  1. python3.10 -m venv myprojectenv

これにより、プロジェクトディレクトリ内の myprojectenv というディレクトリに、Pythonとpipのローカルコピーがインストールされます。

仮想環境内にアプリケーションをインストールする前に、それをアクティブにする必要があります。以下のように入力してください:

  1. source myprojectenv/bin/activate

あなたのプロンプトは、現在仮想環境内で動作していることを示すように変わります。それは次のようになります:(myprojectenv)user@host:~/myproject$.

ステップ3 — Flaskアプリケーションのセットアップ

仮想環境にいるので、FlaskとuWSGIをインストールし、アプリケーションの設計を始めることができます。

最初に、ローカルの pip インスタンスを使用して wheel をインストールし、ホイールアーカイブが欠落していてもパッケージがインストールされることを確認します:

  1. pip install wheel

注: 使用しているPythonのバージョンに関係なく、仮想環境がアクティブな場合は、pipコマンドを使用する必要があります(pip3ではなく)。

次に、FlaskとuWSGIをインストールします:

  1. pip install uwsgi flask

サンプルアプリの作成

Flaskが利用できるようになったので、サンプルアプリケーションを作成できます。Flaskはマイクロフレームワークです。より多機能なフレームワークが持つかもしれない多くのツールは含まれておらず、主にウェブアプリケーションを初期化するのを手助けするためにプロジェクトにインポートできるモジュールとして存在します。

あなたのアプリケーションはもっと複雑かもしれませんが、この例では、単一のファイルであるmyproject.pyにFlaskアプリを作成します。nanoまたはお気に入りのテキストエディタを使ってmyproject.pyを開いてください:

  1. 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へのアクセスを許可する必要があります。

  1. sudo ufw allow 5000

さて、次のコマンドを入力してFlaskアプリをテストできます:

  1. python myproject.py

以下のような出力が表示され、プロダクション環境でこのサーバー設定を使用しないように注意を促す警告が含まれています:

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Serving Flask app 'myproject'
 * Debug mode: off
 * Running on all addresses (0.0.0.0)
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://127.0.0.1:5000
 * Running on http://your_server:5000 (Press CTRL+C to quit)

ウェブブラウザでサーバーのIPアドレスに:5000を続けて入力してください:

http://your_server_ip:5000

あなたはこのようなものを見るでしょう:

作業が完了したら、ターミナルウィンドウで CTRL + C を押してFlask開発サーバーを停止してください。

WSGIエントリーポイントの作成

次に、アプリケーションのエントリーポイントとして機能するファイルを作成します。これにより、uWSGIサーバーがどのようにそれと対話するかが指定されます。

wsgi.pyというファイルを呼び出します:

  1. nano ~/myproject/wsgi.py

このファイルでは、アプリケーションからFlaskインスタンスをインポートして、それを実行します:

from myproject import app

if __name__ == "__main__":
    app.run()

作業が完了したら、ファイルを保存して閉じてください。

ステップ4 — uWSGIの設定

あなたのアプリケーションは、エントリーポイントが確立されて書かれました。次にuWSGIの設定に進むことができます。

uWSGIがアプリケーションを提供できるかのテスト

最初のステップとして、uWSGIがアプリケーションを正しく提供できるかテストするために、エントリーポイントの名前を渡します。これは、モジュールの名前(.py拡張子を除く)とアプリケーション内の呼び出し可能な名前を組み合わせたものです。このチュートリアルの文脈では、エントリーポイントの名前はwsgi:appです。

さらに、ソケットを指定して、公開されているインターフェースで起動されるようにし、プロトコルも指定して、uwsgiバイナリプロトコルの代わりにHTTPを使用するようにします。以前に開いたポート番号5000を使用してください:

  1. uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

ウェブブラウザでサーバーのIPアドレスに:5000を付け加えて再度訪問してください:

http://your_server_ip:5000

アプリケーションの出力が再度表示されます。

正常に機能していることを確認したら、ターミナルウィンドウでCTRL + Cを押してください。

仮想環境はもう終了したので、非アクティブ化することができます。

  1. deactivate

今後、すべてのPythonコマンドはシステムのPython環境を再び使用します。

uWSGI設定ファイルの作成

uWSGIがあなたのアプリケーションを提供できることをテストしましたが、長期的な使用のためにはもっと堅牢なものを望むでしょう。このための関連オプションを持つuWSGIの設定ファイルを作成できます。

そのファイルをプロジェクトディレクトリに置き、それをmyproject.iniと呼びます:

  1. nano ~/myproject/myproject.ini

内部では、uWSGIが設定を適用できるように、ファイルの最初に[uwsgi]ヘッダーを付けます。その下に、モジュール自体を指定します。これは拡張子を除いたwsgi.pyファイルを参照し、ファイル内の呼び出し可能なオブジェクトであるappを示します。

[uwsgi]
module = wsgi:app

次に、uWSGIにマスターモードで起動し、実際のリクエストを処理するために5つのワーカープロセスを生成するように指示します:

[uwsgi]
module = wsgi:app

master = true
processes = 5

テストしているときに、uWSGIをネットワークポートに公開しました。しかし、実際のクライアント接続を処理するためにNginxを使用し、リクエストをuWSGIに渡します。これらのコンポーネントは同じコンピュータ上で動作しているため、Unixソケットが望ましいです。なぜなら、それはより速く、より安全だからです。ソケットをmyproject.sockと呼び、このディレクトリに配置してください。

次に、ソケットの権限を変更します。後でuWSGIプロセスの所有権をNginxグループに与えるため、ソケットのグループ所有者が情報を読み書きできることを確認する必要があります。また、vacuumオプションを追加し、trueに設定します。これにより、プロセスが停止したときにソケットがクリーンアップされます:

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

最後に行うべきことは、die-on-termオプションを設定することです。これにより、initシステムとuWSGIが各プロセスのシグナルが意味することについて同じ前提を持つことが確保できます。これを設定することで、二つのシステムコンポーネントが整合し、期待される動作を実現します:

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

die-on-term = true

これらの行が、あなたがコマンドラインから行ったようにプロトコルを指定していないことに気付いたかもしれません。それは、デフォルトでuWSGIが他のサーバーと通信するために設計された高速バイナリプロトコルであるuwsgiプロトコルを使用しているからです。Nginxはこのプロトコルをネイティブにサポートしているため、HTTPで通信を強制するよりも、これを使用する方が良いです。

終わったら、ファイルを保存して閉じてください。

これにより、uWSGI はあなたのシステムに設定されました。Flask アプリケーションの管理方法にもっと柔軟性を持たせるために、これからはそれを systemd サービスとして実行するように設定できます。

ステップ5 — systemdユニットファイルの作成

Systemdは、システムサービスを管理するための迅速で柔軟なinitモデルを提供するツールのスイートです。systemdユニットファイルを作成することで、Ubuntuのinitシステムがサーバーの起動時にuWSGIを自動的に起動し、Flaskアプリケーションを提供することができます。

/etc/systemd/systemディレクトリ内に.serviceで終わるユニットファイルを作成して始めます:

  1. sudo nano /etc/systemd/system/myproject.service

内部では、まず[Unit]セクションから始めます。これはメタデータや依存関係を指定するために使用されます。それから、ここでサービスの説明を記述し、初期化システムにネットワーキングターゲットが達成された後のみこれを起動するように指示します。

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

次に、[Service] セクションを作成します。これにより、プロセスを実行するユーザーとグループを指定します。関連するすべてのファイルの所有権を持つため、通常のユーザーアカウントにプロセスの所有権を与えます。そして、NginxがuWSGIプロセスと通信できるように、グループ所有権をwww-data グループに与えます(これは、UbuntuでNginxがデフォルトで実行されるグループです)。ここでユーザー名を自分のユーザー名に置き換えることを忘れないでください:

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data

次に、作業ディレクトリをマップし、PATH 環境変数を設定して、初期化システムがプロセスの実行可能ファイルが仮想環境内にあることを知ることができるようにします。また、サービスを開始するためのコマンドを指定します。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サービスを開始する前に、権限変更を行う必要があります。なぜなら、Nginxのwww-dataユーザーはデフォルトでUbuntu 22.04以降のバージョンでホームディレクトリ内のファイルを読み取ることができないためです。これにより、ホームディレクトリからウェブアプリケーションを提供することができなくなる可能性があります。すぐに解決する方法は、chgrpを使用してホームディレクトリに関連付けられたグループを変更することです。

  1. sudo chgrp www-data /home/sammy

これにより、Nginxはソケットファイルにアクセスするために必要なあなたのホームディレクトリの内容を見ることができるようになります。ただし、あなたのホームディレクトリ内のファイルがWebに公開されることはありません。

作成したuWSGIサービスを今すぐ開始できます:

  1. sudo systemctl start myproject

次に、ブート時に開始されるようにそれを有効にします:

  1. sudo systemctl enable myproject

ステータスを確認してください:

  1. sudo systemctl status myproject

このような出力が表示されます:

● myproject.service - uWSGI instance to serve myproject
     Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: ena>
     Active: active (running) since Fri 2022-08-05 17:22:05 UTC; 6s ago
   Main PID: 4953 (uwsgi)
      Tasks: 6 (limit: 2327)
     Memory: 20.9M
        CPU: 241ms
     CGroup: /system.slice/myproject.service
             ├─4953 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             ├─4954 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             ├─4955 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             ├─4956 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             ├─4957 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             └─4958 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

エラーが見つかった場合は、チュートリアルを続ける前にそれらを解決してください。そうでなければ、Nginx インストールの設定を進めて、リクエストをmyproject.sockソケットに渡すことができます。

ステップ6 — Nginxを設定してリクエストをプロキシする

あなたのuWSGIアプリケーションサーバーは現在稼働中で、プロジェクトディレクトリ内のソケットファイルでリクエストを待っています。このステップでは、Nginxを設定して、そのソケットにウェブリクエストを渡すためにuwsgiプロトコルを使用します。

まず、Nginxのsites-availableディレクトリに新しいサーバーブロック設定ファイルを作成します。このガイドの他の部分に合わせて、以下の例ではこれをmyprojectと呼びます:

  1. sudo nano /etc/nginx/sites-available/myproject

サーバーブロックを開いて、Nginxにデフォルトポート80でリッスンするように指示します。さらに、このブロックをサーバーのドメイン名へのリクエストに使用するよう指示します:

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ディレクトリにリンクしてください:

  1. sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Nginxをインストールすると、プロセスは自動的にsites-availableディレクトリにdefaultという名前のサーバーブロック構成ファイルを設定し、そのファイルとsites-enabledディレクトリとの間にシンボリックリンクを作成しました。このシンボリックリンクをそのままにしておくと、default構成がサイトの読み込みを妨げます。次のコマンドでリンクを削除できます:

  1. sudo unlink /etc/nginx/sites-enabled/default

次に、以下のように入力して構文エラーをテストできます:

  1. sudo nginx -t

これが問題を示すことなく戻った場合は、新しい設定を読み込むためにNginxプロセスを再起動してください:

  1. sudo systemctl restart nginx

最後に、ファイアウォールを再度調整します。ポート5000を通じてのアクセスはもう必要ないので、そのルールを削除できます。次に、Nginxサーバへのアクセスを許可します:

  1. sudo ufw delete allow 5000
  2. sudo ufw allow 'Nginx Full'

これで、ウェブブラウザでサーバーのドメイン名にアクセスできるようになります:

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からの無料証明書を取得する、自分で署名した証明書を生成する、商業プロバイダーから購入するなど、いくつかの方法があります。迅速さを重視して、このチュートリアルではLet’s Encryptから無料証明書を取得する方法を説明します。

まず、aptを使ってCertbotとそのNginxプラグインをインストールします。

  1. sudo apt install certbot python3-certbot-nginx

Certbotは、プラグインを通じてSSL証明書を取得するためのさまざまな方法を提供しています。Nginxプラグインは、必要に応じてNginxの再構成と設定の再読み込みを行います。このプラグインを使用するには、次のように入力します:

  1. sudo certbot --nginx -d your_domain -d www.your_domain

これは、--nginx プラグインを使用して certbot を実行し、-d を使用して証明書を有効にしたい名前を指定するものです。

このサーバーで初めてcertbotを実行する場合、メールアドレスの入力と利用規約への同意を求められます。その後、certbotはLet’s Encryptサーバーと通信し、証明書を要求しているドメインを管理していることを確認するためのチャレンジを実行します。

設定が更新され、Nginxが新しい設定を適用するために再読み込みされます。certbotは、プロセスが成功し、証明書がどこに保存されているかを知らせるメッセージで終了します:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/your_domain/privkey.pem
This certificate expires on 2022-11-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 for your_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://www.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プロファイルの許可はもはや必要ありません。

  1. sudo ufw delete allow 'Nginx HTTP'

設定を確認するには、再度自分のドメインに移動し、https://を使用してください:

https://your_domain

もう一度アプリケーションの出力を見ることができ、ブラウザのセキュリティインジケーターも表示されるはずで、そのサイトが安全であることを示すべきです。

結論

このガイドでは、Python仮想環境内にFlaskアプリケーションを作成し、それを保護しました。その後、WSGIに対応するアプリケーションサーバーがそれとインターフェースできるようにWSGIエントリポイントを作成し、uWSGIアプリサーバーを構成してこの機能を提供しました。その後、ブート時にアプリケーションサーバーを自動的に起動するsystemdサービスファイルを作成しました。また、Webクライアントのトラフィックをアプリケーションサーバーに渡すNginxサーバーブロックを作成し、外部からのリクエストを中継し、Let’s Encryptを使用してサーバーへのトラフィックを保護しました。

Flaskは、アプリケーションに機能を提供しながら、構造やデザインに対してあまり制約を設けない柔軟なフレームワークです。このガイドで説明される一般的なスタックを使用して、あなたがデザインするFlaskアプリケーションを提供することができます。

関連記事: