uWSGI
uWSGI 是一个快速、自愈且对开发者/系统管理员友好的应用程序容器服务器,使用纯 C 语言编写。
有一些用 Python 编写的替代品,例如 gunicorn。
安装
安装 uwsgi 软件包。插件需要单独安装(它们的软件包名称以 uwsgi-plugin-
开头)。
配置
由 uWSGI 服务的 Web 应用程序 在 /etc/uwsgi/
中配置,其中每个应用程序都需要自己的配置文件(ini 风格)。详细信息可以在 uWSGI 文档中找到。
或者,你可以在 Emperor 模式(在 /etc/uwsgi/emperor.ini
中配置)下运行 uWSGI。它使单个 uWSGI 实例能够使用单个主主管(称为 emperor)运行一组不同的应用程序(称为 vassals)。
--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 用户身份运行此命令。
PHP
以下是基于 PHP 的网站的简单示例。
/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 服务器的后端。以下是配置示例。
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; } # ...
uwsgi_modifier1
参数列表。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
由于我们正在 chroot 到 /srv/http
,因此上述配置将导致创建以下 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 [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
/run
而不是 /srv/http/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; } } ...
现在请确保 重启 nginx.service
,以便在 127.0.0.1
上提供你的 application1
。
运行 uWSGI
/etc/uwsgi/
中配置。为简单起见,配置文件名应仅包含字母数字字符和 _
,以避免转义问题,请参阅 systemd.unit(5) § STRING ESCAPING FOR INCLUSION IN UNIT NAMES。如果你计划一直使用 Web 应用程序(而不是按需激活),你可以简单地 启动 和 启用 uwsgi@example
。
如果你计划让你的 Web 应用程序按需启动,你可以 启动 和 启用 uwsgi@example.socket
。
要使用 Emperor 模式,启动 和 启用 emperor.uwsgi.service
。
要使用此模式的套接字激活,启动 和 启用 emperor.uwsgi.socket
。
提示和技巧
uWSGI 提供的一些功能无法通过使用 systemd 服务文件在 官方仓库 中提供。对它们的更改将在以下部分中解释。有关更多信息,请参阅 [2]。
套接字激活
使用套接字激活,你想要
- 将你的 Web 服务器定向到 unix 套接字,从而启动你的 uWSGI 实例运行应用程序
- 你很可能希望在一定空闲时间后让 uWSGI 关闭应用程序
- 你希望你的 Web 服务器能够在应用程序被访问后再次启动它
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 在自行关闭应用程序后可能提供的退出代码添加到列表中,systemd 将使用 SuccessExitStatus
指令将这些代码视为成功(有关更多信息,请参阅 [3])。
/etc/systemd/system/uwsgi-socket@.service
[Unit] Description=uWSGI service unit [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-after-idle 功能进行正确的套接字激活。
强化 uWSGI 服务
Web 应用程序暴露于野外,并且根据其质量和底层语言的安全性,某些应用程序比其他应用程序更危险。处理可能不安全的 Web 应用程序的一个好方法是将它们隔离起来。systemd 具有一些可以使用的功能。请看以下示例(有关更多信息,请参阅 systemd.exec(5) 和 [4])
/etc/systemd/system/uwsgi-secure@.service
[Unit] Description=uWSGI service unit [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=yes
不适用于 Mailman 的 cgi 前端!如果你想将其与它结合使用,请删除此设置。 - 如果你想要进一步强化,建议使用命名空间。你可以在 uWSGI 命名空间文档中初步了解该主题。
uWSGI 套接字的可访问性
默认的(每个应用程序)套接字单元 (uwsgi@.socket
) 在 uwsgi 中允许系统上的任何用户进行读取和写入访问。但是,systemd 允许更精细的访问管理(参见 systemd.socket(5)),通过它可以更严格地限制对 unix 套接字的访问。
通过在 /run
下的 webapp 特定目录(需要预先使用 tmpfiles 创建 - 有关参考,请参阅 Web application package guidelines)下创建它,并修改其 组 和文件 权限,该套接字仅对 root 和 web 服务器 可访问,并允许 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: 尝试连接到 127.0.0.1:0 (*) 失败
默认的 uWSGI 端口 (3031) 目前(?)不适用于 Apache httpd 服务器。有关详细信息,请参阅 [5]。