uWSGI

提供: ArchWiki
2023年10月28日 (土) 14:38時点におけるKgx (トーク | 投稿記録)による版 (→‎設定: 情報を更新)
ナビゲーションに移動 検索に移動

uWSGI は高速で自己回復機能のある、開発者とシステム管理人に優しいアプリケーションコンテナサーバーです。C だけで書かれています。

インストール

公式リポジトリuwsgi パッケージをインストールしてください。パッケージをコンパクトにするために、プラグインは付属していません。外部プラグインは別にインストールする必要があります。C で書かれているためとても効率的なソフトウェアです。gunicorn など Python で書かれた代替も存在しますが、どうしても動作は遅くなってしまいます。

サービスの起動

ノート: アプリケーション (Python アプリケーション) ごとにそれぞれ uwsgi サービスのインスタンスを作成するのが一番シンプルな構成です。uwsgi サービスを有効化・起動する前に、/etc/uwsgi/ の中に同一の名前の設定ファイルを作成してください。以下では /etc/uwsgi/helloworld.ini を使っています。

スタートアップ時にデフォルトで uwsgi サービスを有効にするには、次を実行:

# systemctl enable uwsgi@helloworld

これで /etc/uwsgi/helloworld.ini 設定されたアプリケーションのサービスが有効になります。また、以下のコマンドを使ってソケットインターフェイスで有効にすることも可能です:

# systemctl enable uwsgi@helloworld.socket

もしくは、Emperor モード サービスを実行することができます。このモードを使うと uwsgi インスタンスで (emperor と呼ばれる) メインスーパーバイザーを使って様々なアプリ (vassal と呼ばれます) が動くようになります。有効にするには、次を入力:

# systemctl enable emperor.uwsgi

ソケットを使うこともできます:

# systemctl enable emperor.uwsgi.socket

Emperor の設定は /etc/uwsgi/emperor.ini にあります。

設定

uWSGI によって提供される ウェブアプリケーション は、/etc/uwsgi/ で設定されており、それぞれに独自の構成ファイル (ini 形式) が必要です。詳細については、uWSGI ドキュメント をご覧ください。

あるいは、エンペラーモード (/etc/uwsgi/emperor.ini で設定) して uWSGI を実行することもできます。これにより、単一の uWSGI インスタンスが、単一のメインスーパーバイザー (エンペラーと呼ばれる) を使用して、一連の異なるアプリ (家臣と呼ばれる) を実行できるようになります。

ノート: プラグインは、そのオプションを使用する前に明示的にロードする必要があります。そうしないと、オプションが認識されません。これは、--plugins コマンドラインオプション、または設定ファイル内の plugins 変数を使用して実行できます。

Web アプリケーション

uWSGI はさまざまな言語をサポートしているため、多くの Web アプリケーションもサポートしています。 例として、設定ファイル /etc/uwsgi/example.ini と、Web アプリケーションに必要なプラグインが事前にインストールされていることを前提としています。

Python

以下は、Python アプリケーションの簡単な例です。

/etc/uwsgi/example.ini
[uwsgi]
chdir = /srv/http/example
module = example
plugins = python

たとえば、次の構文を使用して uWSGI を個別に実行することもできます。

$ uwsgi --socket 127.0.0.1:3031 --plugin python2 --wsgi-file ~/foo.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191 --uid --gid

このコマンドを root として実行することは避けてください。

ノート: 使用中の動作モードに注意してください。--lazy-apps を使用せずにプリフォークすると、明らかではない動作が発生する可能性があります。デフォルトでは、Python プラグインは GIL を初期化しません。これは、アプリで生成されたスレッドが実行されないことを意味します。スレッドが必要な場合は、enable-threads を使用してスレッドを有効にしてください。マルチスレッドモード (スレッドオプションを使用) で uWSGI を実行すると、スレッドサポートが自動的に有効になります。この 奇妙な デフォルト動作はパフォーマンス上の理由からで、気にする必要はありません。[1]

PHP

以下は、PHP ベースの Web サイトの簡単な例です。

/etc/uwsgi/example.ini
[uwsgi]
; maximum number of worker processes
processes = 4
; the user and group id of the process once it’s started
uid = http
gid = http
socket = /run/uwsgi/%n.sock
master = true
chdir = /srv/http/%n
; php
plugins = php
; jail our php environment
php-docroot = /srv/http/%n
php-index = index.php
; clear environment on exit
vacuum = true

Web サーバー

uWSGI は、アクセスの転送をサポートする多くの Web サーバーのバックエンドとして使用できます。以下に構成例を示します。

ノート: パフォーマンスとセキュリティの両方の観点から構成を理解するには、uWSGI ドキュメントを一読することをお勧めします。

Nginx

nginx は、Web アプリケーションに応じて、UNIX ソケットまたはポート (ローカルホストまたはリモートマシン上) にアクセスをリダイレクトできます。

/etc/nginx/example.conf
# ...
# forward all access to / towards 
location / {
  root /usr/share/nginx/html;
  index index.html index.htm;
  include uwsgi_params;
  # this is the correct uwsgi_modifier1 parameter for a php based application
  uwsgi_modifier1 14;
  # uncomment the following if you want to use the unix socket instead
  # uwsgi_pass unix:/var/run/uwsgi/example.sock;
  # access is redirected to localhost:3031
  uwsgi_pass 127.0.0.1:3031;
}
# ...
ヒント: Web アプリケーションに適合する uwsgi_modifier1 パラメータのリストについては、ドキュメント を参照してください。

Nginx (chroot 内)

ノート: このセクションは、Nginx#chroot でのインストール の説明に従って Nginx をデプロイしていることを前提としています。Nginx chroot は /srv/http にあると想定されています。

まず、アプリケーションを指す ini ファイルを作成します。

/etc/uwsgi/application1.ini
[uwsgi]
chroot = /srv/http
chdir = /www/application1
wsgi-file = application1.py
plugins = python
socket = /run/application1.sock
uid = http
gid = http
threads = 2
stats = 127.0.0.1:9191
vacuum = true

上記の設定では /srv/http に chroot しているため、次のような UNIX ソケットが作成されます /srv/http/run/application1.sock

ノート:
  • アプリケーションが /srv/http/www/application1 内に配置されている必要があります。

設定によっては、アプリケーションはキャッシュされるかもしれません。

  • python アプリケーションをデプロイしている場合、標準の python ライブラリをコピーする必要があるかもしれません python 3 で開発している場合、/usr/lib/python3.6から/srv/http/lib/python3.6 にコピーできます。

以下を実行してみてください:

# cp -r -p /usr/lib/python3.6 /srv/http/lib
# cp -r -p /usr/lib/*python*so /srv/http/lib

サービスファイル内で通知を無効にする必要があります。

/etc/systemd/system/multi-user.target.wants/uwsgi\@application1.service
[Unit]
Description=uWSGI service unit
After=syslog.target

[Service]
PIDFile=/run/%I.pid
RemainAfterExit=yes
ExecStart=/usr/bin/uwsgi --ini /etc/uwsgi/%I.ini
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -INT $MAINPID
Restart=always
StandardError=syslog
KillSignal=SIGQUIT

[Install]
WantedBy=multi-user.target
ノート: PID ファイルは /srv/http/run ではなく /run 内に作成されます

変更後は必ず 再起動 を行って、新しいユニットまたは変更されたユニットを組み込んでください。

その後、uwsgi@application1.service有効化 および 起動 して下さい。

/srv/http/etc/nginx/nginx.conf を編集し、その中に少なくとも以下を含む新しい server セクションを追加します。

/srv/http/etc/nginx/nginx.conf
...
    server
    {
        listen       80;
        server_name  127.0.0.1;
        location /
        {
            root   /www/application1;
            include uwsgi_params;
            uwsgi_pass unix:/run/application1.sock;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html
        {
            root   /usr/share/nginx/html;
        }
    }
...

application1127.0.0.1 で提供されるように、nginx.service再起動 してください。

uWSGI の実行

ノート: これは、使用される Web アプリケーションが適切に構成されており、Web サーバーによって提供され、使用しているソケットまたはポートにリダイレクトされ、/etc/uwsgi/ で設定されていることが前提となります。わかりやすくするために、設定ファイル名には英数字と _ のみを含めてエスケープの問題を避ける必要があります。systemd.unit(5) § STRING ESCAPING FOR INCLUSION IN UNIT NAMES を参照してください。

Web アプリケーションを (オンデマンドでアクティブ化せずに) 常に使用する予定がある場合は、単に 起動 および 有効化 uwsgi@example を実行できます。

Web アプリケーションをオンデマンドで開始する予定の場合は、起動 および 有効化 uwsgi@example.socket を実行できます。

エンペラーモードを使用するには、emperor.uwsgi.service起動 および 有効化 します。

このモードのソケットアクティベーションを使用するには、emperor.uwsgi.socket起動 および 有効化 します。

ヒントとテクニック

uWSGI が提供する一部の機能は、公式リポジトリ で提供される systemd サービスファイルを使用してアクセスすることはできません。 これらの変更点については、次のセクションで説明します。詳細については、[2] を参照してください。

ソケットのアクティブ化

ソケットアクティベーションを使用して、次のことを行います。

  • Web サーバーを unix ソケットに誘導し、アプリケーションを実行している uWSGI インスタンスを起動します。
  • アイドリング時間が経過すると、uWSGI によってアプリケーションがクローズされます。
  • アプリケーションがアクセスされた後、ウェブサーバが再びアプリケーションを起動できるようにしたい。

uWSGI には、インスタンスにアプリケーションを閉じるための設定が用意されています。

/etc/uwsgi/example.ini
[uwsgi]
# ...

# set idle time in seconds
idle = 600
# kill the application after idle time was reached
die-on-idle = true

# ...

しかし、現在の uwsgi@.service ファイルはこれを許さない。なぜなら、systemd はゼロ以外の終了コードを失敗として扱い、それによってユニットを失敗としてマークするからであり、さらに Restart=always ディレクティブはアイドル時間後に終了することを無意味にしてしまうからです。 これを修正するには、終了コードを追加します。終了コードは、アプリケーションを単独で閉じた後に uWSGI がリストに提供する可能性があり、systemdSuccessExitStatus ディレクティブを使用して成功として処理します (詳細については、[3] を参照)

/etc/systemd/system/uwsgi-socket@.service
[Unit]
Description=uWSGI service unit
After=syslog.target

[Service]
ExecStart=/usr/bin/uwsgi --ini /etc/uwsgi/%I.ini
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -INT $MAINPID
Type=notify
SuccessExitStatus=15 17 29 30
StandardError=syslog
NotifyAccess=all
KillSignal=SIGQUIT

[Install]
WantedBy=multi-user.target

これにより、アイドル後の Kill 機能を使用してソケットを適切にアクティブ化できるようになります。

uWSGI サービスの強化

Web アプリケーションは実際に公開されており、その品質と基礎となる言語のセキュリティに応じて、実行するのが他のアプリケーションよりも危険なものもあります。 安全でない可能性のある Web アプリケーションへの対処を始める良い方法は、それらを刑務所に入れることです。 systemd には、使用できる機能がいくつかあります。 次の例を見てください (詳細については、systemd.exec(5) および [4] を参照してください。)

/etc/systemd/system/uwsgi-secure@.service
[Unit]
Description=uWSGI service unit
After=syslog.target

[Service]
ExecStart=/usr/bin/uwsgi --ini /etc/uwsgi/%I.ini
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -INT $MAINPID
Type=notify
SuccessExitStatus=15 17 29 30
StandardError=syslog
NotifyAccess=all
KillSignal=SIGQUIT
PrivateDevices=yes
PrivateTmp=yes
ProtectSystem=full
ReadWritePaths=/etc/webapps /var/lib/
ProtectHome=yes
NoNewPrivileges=yes

[Install]
WantedBy=multi-user.target
ノート:
  • NoNewPrivileges=yesMailman の cgi フロントエンドでは動作しません!この設定を併用したい場合は削除してください。
  • さらに強固にしたいのであれば、名前空間を使うことをお勧めします。このトピックについては uWSGI namespaces documentation をご覧ください。

uWSGI ソケットのアクセシビリティ

uwsgi のデフォルト (アプリケーションごと) ソケットユニット (uwsgi@.socket) では、システム上のすべてのユーザーに読み取りおよび書き込みアクセスが許可されます。 ただし、systemd では、より細かく粒度の高いアクセス管理が可能です (systemd.socket(5) を参照) これにより、UNIX ソケットへのアクセスをより制限することができます。

(事前に tmpfiles を使って作成する必要があります。参考は ウェブアプリケーションパッケージガイドライン を参照してください)、その グループ とファイルの パーミッション を変更することで、ソケットは rootウェブサーバー だけがアクセスできるようになり、Web アプリケーションを独自のユーザーとして実行できるようになります:

/etc/systemd/system/uwsgi-secure@.socket
[Unit]
Description=Socket for uWSGI %I

[Socket]
ListenStream=/run/%I/%I.sock
SocketGroup=http
SocketMode=0660

[Install]
WantedBy=sockets.target

トラブルシューティング

Apache httpd

AH00957: uwsgi: attempt to connect to 127.0.0.1:0 (*) failed

デフォルトの uWSGI ポート (3031) は、(現時点では?) Apache httpd サーバーでは機能しません。詳細については、[5] を参照してください。

参照