Fedora 35 では uWSGI が retire しました。メンテナーがいなくなったからです。Fedora 35 では PHP 7.4 のサポートなんてありませんが、libphp7-7.4.so がない、というエラーメッセージが物悲しく感じます。ともあれ、標準のレポジトリで提供されないので、何らかの対策が必要になりました。NGINX Unit などの別のアプリケーションサーバに移行するというのもよいと思いますが、ここでは、引き続き uWSGI を使う方法について書きます。

まず、uWSGI ですが、2021-11-24 時点の最新バージョンは 2.0.20 です。2021-10-06 リリースですので、プロジェクトはまだ生きています。一方、Fedora 34 の uWSGI は 2.0.18 で、以後のアップデートがありません。2.0.19 のビルドに失敗して以降、放置されています。Fedora では、upstream に追随できていないパッケージを使い続けるのは問題があります。

pip からのインストール

ほとんどの方は、uWSGI をレポジトリからインストールしていると思うので、ネットを探しても pip からインストールする方法は情報が限られています。

レポジトリから uWSGI をインストール済みの場合は、一旦 uWSGI をアンインストールします。設定ファイルの待避が必要な場合は、事前に行ってください。

# dnf remove uwsgi
削除しました:
  uwsgi-2.0.18-16.fc34.x86_64                                                   
  uwsgi-plugin-common-2.0.18-16.fc34.x86_64                                     
  uwsgi-plugin-python3-2.0.18-16.fc34.x86_64                                    

完了しました!
# 

Fedora のパッケージでは、uWSGI 本体と、プラグインが別ファイルになっていますので、これに近づけることを目標にします。

uWSGI を pip でインストールするには、gccpython3-devel が必要になりますので、インストールします。もちろん、pip も必要です。

# dnf install -y gcc python3-devel pip
...
# 

uWSGI をインストールします。基本は以下の通りです。root で入れんなとか言われますが、無視でいいです。

# pip install uwsgi
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip install --user` instead.
Collecting uwsgi
  Downloading uwsgi-2.0.20.tar.gz (804 kB)
     |████████████████████████████████| 804 kB 2.9 MB/s 
Using legacy 'setup.py install' for uwsgi, since package 'wheel' is not installed.
Installing collected packages: uwsgi
    Running setup.py install for uwsgi ... done
Successfully installed uwsgi-2.0.20
# 

この方法でインストールすると、プラグイン全部入りのバイナリができあがります。emperor プロセスにも全てのプラグインが組み込まれて、メモリの消費が増えてしまいます。組み込むプラグインを指定するには、次のようにインストールします。pyonly はプラグイン python のみを有効にする場合の設定です。

# UWSGI_PROFILE=pyonly pip install uwsgi
...
# 

pyonly を指定してインストールした uWSGI のプラグインの一覧は、次のようにして確認できます。全部入りの場合と結果を比較してみてください。

# uwsgi --plugin-list

*** uWSGI loaded generic plugins ***

*** uWSGI loaded request plugins ***
0: python
--- end of plugins list ---

# 

UWSGI_PROFILE に指定できる値は、ソースをダウンロードして、buildconf/ の中を見ると確認できます。この中のファイル名を指定します。

# ls ./uwsgi-2.0.20/buildconf/
all.ini       erlang.ini     modular.ini  pyonly.ini        ruby2.ini
asyncio.ini   gccgo.ini      mono.ini     pypy.ini          servlet.ini
base.ini      gevent.ini     nolang.ini   pypyonly.ini      travis.ini
cgi.ini       glusterfs.ini  package.ini  pyring.ini        unbit.ini
core.ini      gridfs.ini     php.ini      pyuwsgi.ini       unbitstaff.ini
coroae.ini    jwsgi.ini      plonly.ini   pyuwsginossl.ini  uwsgi.it.ini
coverity.ini  lib.ini        ppa.ini      rack.ini          v8.ini
default.ini   lua.ini        psgi.ini     rados.ini
django.ini    luap.ini       pyerl.ini    rbonly.ini
embedded.ini  minimal.ini    pylua.ini    ring.ini
#

この中に所望のものがない場合は、自前で書いて、フルパスで指定します。基本は、base.iniminimal.ini を継承して、組み込みたいプラグインを指定します。また modular.ini には、プラグインを別ファイルに分離したい場合の設定が書かれています。以下の例では、Fedora 34 のパッケージの uWSGI に準拠して、corerouterpingecho プラグインを uWSGI 本体に組み込みとします。python プラグインは、別ファイルとして /usr/local/lib64/uwsgi へインストールします。以下のように書きます。

[uwsgi]
inherit = base
plugins = python
plugin_dir = /usr/local/lib64/uwsgi
embedded_plugins = corerouter, ping, echo

これを適当なファイル名(ここでは my.ini )で保存して、フルパスで指定してインストールします。/usr/local/lib64/uwsgi がない場合は、あらかじめ作成しておく必要があります。

# mkdir -p /usr/local/lib64/uwsgi
# UWSGI_PROFILE=~/my.ini pip install uwsgi
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip install --user` instead.
Collecting uwsgi
  Downloading uwsgi-2.0.20.tar.gz (804 kB)
     |████████████████████████████████| 804 kB 2.9 MB/s 
Using legacy 'setup.py install' for uwsgi, since package 'wheel' is not installed.
Installing collected packages: uwsgi
    Running setup.py install for uwsgi ... done
Successfully installed uwsgi-2.0.20
# 

これでインストール完了です。

設定

systemd から uWSGI を起動するために、Fedora のパッケージから丸パクリで、/usr/local/lib/systemd/system/uwsgi.service を作成します。

[Unit]
Description=uWSGI Emperor Service
After=syslog.target

[Service]
EnvironmentFile=-/etc/sysconfig/uwsgi
ExecStart=/usr/local/bin/uwsgi --ini /etc/uwsgi.ini --pidfile /run/uwsgi/uwsgi.pid --stats /run/uwsgi/stats.sock
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT
Restart=always
Type=notify
StandardError=journal
NotifyAccess=all

[Install]
WantedBy=multi-user.target

ユーザ uwsgi とグループ uwsgi を作ります。こちらもパッケージから丸パクリです。

# groupadd -r uwsgi
# useradd -r -g uwsgi -d /run/uwsgi -s /sbin/nologin -c "uWSGI daemon user" uwsgi
#

.pid ファイルなどの置き場所として /run/uwsgi/ ディレクトリを作成します。

# install -d -m 775 -o uwsgi -g uwsgi /run/uwsgi
#

OS を再起動すると /run/uwsgi/ ディレクトリが消えてしまうので、次回起動時に自動作成するために、/etc/tmpfiles.d/uwsgi.conf を作成します。

d /run/uwsgi 0775 uwsgi uwsgi

/etc/uwsgi.ini はこんな感じでいいと思います。

[uwsgi]
uid = uwsgi
gid = uwsgi
emperor = /etc/uwsgi.d
chmod-socket = 660
emperor-tyrant = false
cap = setgid,setuid

emperor-tyrant の設定値は emperor を root で動かす場合と、そうでない場合で違います。truefalse か、動く方を指定してください。公式ドキュメントが文学的でどちらが正しいのか、ちょっとよく分からないです。emperor は root でも OK ですが、vassal は特権プロセスにしないのが原則です。

後は、各自 uWSGI で動かすアプリケーションを設定後、いつも通り以下のように起動します。念のため、事前に daemon-reload(設定ファイル再読み込み)もしておきましょう。

# systemctl daemon-reload
# systemctl start uwsgi
# systemctl enable uwsgi
#

以上で、これまで通り uWSGI が使えます。uWSGI のアップデートは手動になりますが、やむを得ません。

おわりに

pip で uWSGI をインストールする場合でも、ビルド設定は柔軟に指定できますので、レポジトリからインストールした場合と同等に運用可能です。とりあえず、しばらくはこれで凌げるでしょう。メンテナーが復活してくれるといいのですが。