Nginx Unit 作为 PHP 和 Laravel 服务器
Nginx Unit 是一个 Nginx 带来的 “通用 Web 应用服务器”。它是一个可以和你的代码库“直接”通信的 web 服务器,帮你以代码能够理解的方式将 HTTP 请求传递给代码。
对于 PHP 支持,它有一个创建 PHP 进程的 PHP 模块,类似于 PHP-FPM,但不需要 PHP-FPM。摆脱 PHP-FPM 对我来说真的很好,所以我决定看看它是如何工作的。
安装 PHP
我们将在 Ubuntu 服务器上以通常的方式安装 PHP——使用 ppa:ondrej/php
存储库。这基本上是在 Ubuntu 服务器上使用 PHP 的实际方式。它可以让我们获得最新的 PHP,并在同一台服务器上安装多个版本的 PHP(如果需要的话)。
Unit 的一个问题是:它希望使用系统设置的默认 PHP 版本。幸运的是,我们可以自己重新编译它的 PHP 模块(请参阅此处),以使用我们的ppa:ondrej/php
安装的PHP。
首先,我们如常安装 PHP。
sudo add-apt-repository -y ppa:ondrej/php
sudo apt-get install -y php8.2-dev php8.2-embed \
php8.2-bcmath php8.2-cli php8.2-common php8.2-curl \
php8.2-gd php8.2-intl php8.2-mbstring php8.2-mysql php8.2-pgsql \
php8.2-redis php8.2-soap php8.2-sqlite3 php8.2-xml php8.2-zip
curl -sLS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/bin/ --filename=composer
3 件需要注意的事:
- 我们需要
php8.2-dev
(-dev
版本) 以获取特定的 PHP "header" 文件,允许我们稍后编译 Unit 的 PHP 模块 - 我们需要
php8.2-embed
,因为这是 Unit 使用的用于启用 PHP 进程的 SAPI。 - 我们不需要
php-fpm
,因此不必安装
其他的如正常安装 PHP 那样。
安装 Nginx Unit
我们可以根据 Nginx Unit 的文档进行安装 - 没有需要特别注意的!
我使用的是 Ubuntu 22.04,按照该系统的说明:
sudo curl --output /usr/share/keyrings/nginx-keyring.gpg \
https://unit.nginx.org/keys/nginx-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-keyring.gpg] https://packages.nginx.org/unit/ubuntu/ jammy unit
deb-src [signed-by=/usr/share/keyrings/nginx-keyring.gpg] https://packages.nginx.org/unit/ubuntu/ jammy unit
" | sudo tee /etc/apt/sources.list.d/unit.list
sudo apt-get update
sudo apt-get install -y unit
我只安装了 unit
, 既没安装 unit-dev
也还没安装 unit-php
,因为我们需要自己编译 PHP 模块。
手动编译 Unit 的 PHP 模块
接下来,我们手动重新编译 Unit 的 PHP 模块, 以使用 ppa:ondre/php
。这是从前面提到的 GitHub issue 中获得的,该 issue 有助于指出我们如何使之生效。
以用户 root
运行:
cd /opt
# Latest version of Unit as of this release
VERSION="1.31.0"
curl -O https://unit.nginx.org/download/unit-$VERSION.tar.gz
tar xzf unit-$VERSION.tar.gz
cd unit-$VERSION
./configure --prefix=/usr --state=/var/lib/unit --control=unix:/var/run/control.unit.sock \
--pid=/var/run/unit.pid --log=/var/log/unit.log --tmp=/var/tmp --user=unit --group=unit \
--tests --openssl --modules=/usr/lib/unit/modules --libdir=/usr/lib/x86_64-linux-gnu
./configure php --module=php82 --config=php-config8.2
make php82
make install php82-install
# Restart
systemctl unit restart
# Check logs to ensure PHP module is loaded
cat /var/log/unit.log
我们自己编译了 PHP 模块,它使用了当前安装的 PHP 版本(从 ppa:ondrej/php
库中获取)。
成功!
创建 Laravel 应用
本例中,我们直接在服务器上创建一个新的 Laravel 应用:
mkdir -p /var/www
cd /var/www
composer create-project laravel/laravel html
# Ensure files are owned by "unit", the user created
# by unit, so PHP can write to log files, etc
chown -R unit:unit /var/www/html
再简单不过!
配置 Unit
现在配置 Unit,以运行应用。
新建 /var/www/unit.json
:
{
"listeners": {
"*:80": {
"pass": "routes"
}
},
"routes": [
{
"match": {
"uri": "!/index.php"
},
"action": {
"share": "/var/www/html/public$uri",
"fallback": {
"pass": "applications/laravel"
}
}
}
],
"applications": {
"laravel": {
"type": "php",
"root": "/var/www/html/public/",
"script": "index.php",
"processes": {}
}
}
}
然后让 Unit 使用该配置来运行应用:
sudo curl -X PUT --data-binary @unit.json --unix-socket \
/var/run/control.unit.sock http://localhost/config/
前往应用(当前监听 80 端口)!使用 curl localhost
测试。
Control API
你可以使用 Control API 检索和更新配置。
我们来 GET 获取配置:
curl -X GET \
--unix-socket /var/run/control.unit.sock \
http://localhost/config/
Unit 的优点
我们可以移除掉 PHP-FPM
!很好,因为它使我们的应用放入容器变得简单多了。
Unit 似乎也更高效——我使用 ab
一次发送 100 个请求,总共10000个请求,并不会让其宕机。
Unit 的缺点
有一些取舍!
首先,如果不重新编译 Unit PHP 模块,我们就无法切换 PHP 版本。这意味着在使用 Unit 时很难(不可能?)同时运行多个版本的 PHP。
您可能在 Unit 前面还需要另一个 HTTP 层(Nginx、Cloudflare、Cloudfront、fly.io 的 HTTP 层等)。事实证明,Unit 要么让一些标准的配置变得困难,要么根本做不到。一些示例:
- (还)不支持 Gzip 压缩
- 它使得保护点文件和其他路由变得困难
- 不容易为静态资源设置缓存 header