Nginx 和 PHP-FPM 在 Debian 的官方源中都有,但都不是最新版本。截止本文更新(2021.2.17),Debian 10 官方源中的 Nginx 版本号为 1.14.2(Debian 9 官方源为 1.10.3),PHP 版本号为 7.3。

使用旧的版本当然是不会有问题的,但是在一些情况下就必须使用新版本了:例如想要支持 TLS 1.3 就需要 Nginx 1.13 及以上版本,WordPress 也要求 PHP 7.3 或更高,所以安装新版本还是很有必要的。

安装 Nginx

这里直接使用 Ondřej Surý 大神的 Nginx 源。

先安装一些软件包用于支持 HTTPS 的软件源:

sudo apt update
sudo apt install apt-transport-https lsb-release ca-certificates

增加 Nginx 源:

wget -O /etc/apt/trusted.gpg.d/nginx-mainline.gpg https://packages.sury.org/nginx-mainline/apt.gpg
echo "deb https://packages.sury.org/nginx-mainline/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/nginx.list
sudo apt update
sudo apt install nginx

国内的机器可以使用上交的 Sury 源:

wget -O /etc/apt/trusted.gpg.d/nginx-mainline.gpg https://packages.sury.org/nginx-mainline/apt.gpg
echo "deb https://mirror.sjtu.edu.cn/sury/nginx-mainline/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/nginx.list
sudo apt update
sudo apt install nginx

安装 PHP-FPM

PHP 的话就更要使用 Sury 大神的源了,人家的网站上清清楚楚地写着:“Debian/Ubuntu 上的 PHP 软件包要么是我做的,要么是基于我的工作所做的”,简直比官方源还官方源233。

增加 PHP 源:

wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
sudo apt update

国内的机器依然可以使用上交的 Sury 源:

wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://mirror.sjtu.edu.cn/sury/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
sudo apt update

这里安装最新的 PHP7.4-FPM 和一些常用模块,如果需要低版本修改版本号即可:

sudo apt install php7.4-fpm php7.4-mysql php7.4-curl php7.4-gd php7.4-json php7.4-mbstring php7.4-xml php7.4-xmlrpc php7.4-zip php7.4-bz2 php7.4-opcache php7.4-bcmath php7.4-iconv

配置

修改 Nginx 配置文件

将 sites-available 目录下的 default 文件中的下面这一段取消注释再删除多余的行就可以正常使用 PHP 了。要注意 fastcgi_pass 后面的路径默认是 unix:/run/php/php7.3-fpm.sock,记得修改成自己的版本号,例如 unix:/run/php/php7.4-fpm.sock:

location ~ \.php$ {
  include snippets/fastcgi-php.conf;

  # With php-fpm (or other unix sockets):
  fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}

以及在配置完 HTTPS 之后(假设配置文件是 default-ssl),记得启用它:

ln -s /etc/nginx/sites-available/default-ssl /etc/nginx/sites-enabled/

修改 PHP-FPM 配置文件

PHP-FPM 一共有三个配置文件,以 PHP7.4-FPM 为例,分别是 /etc/php/7.4/fpm/ 目录下的 php-fpm.conf,php.ini 和 /etc/php/7.4/fpm/pool.d/ 目录下的 www.conf。一般来说 php-fpm.conf 没有需要修改的地方。

php.ini

php.ini 需要注意以下几个地方:

  • 第 388 行的 max_execution_time 和第 398 行的 max_input_time,规定了 PHP 的执行时间。默认 30 和 60,0 表示无限制。如果需要使用 PHP 执行大文件的上传任务的话,应该设为一个较大的值,例如 3600,或者直接设置为 0。
  • 第 409 行的 memory_limit,规定了 PHP 最大占用内存。默认 128M,考虑到 Web 服务器和 MySQL 的占用,一般设为内存的一半。
  • 第 694 行的 post_max_size 和第 846 行的 upload_max_filesize,规定了上传文件大小的最大值。默认为 8M 和 2M,根据需要修改。

以下是一个参考:

max_execution_time = 300
max_input_time = 300
memory_limit = 512M
post_max_size = 32M
upload_max_filesize = 32M

www.conf

www.conf 中,在第 102 行的 pm 设置为 dynamic 即动态的前提下,主要关注第 113 行到第 128 行的 4 个设置:

  • pm.max_children,规定了 PHP-FPM 的最大进程数 。这个值需要根据内存大小来决定:考虑到 Web 服务器和 MySQL 的占用,假设 PHP 最多使用一半内存,正常情况下每个 PHP-FPM 进程所占用的内存在 20M 左右,那么对一台 1G 内存的机器来说,就应该设置为 25,即最多使用 500M 左右的内存。
  • pm.start_servers,规定了 PHP-FPM 的起始进程数量。这个数量必须介于 pm.min_spare_servers 和 pm.max_spare_servers 之间,一般设置为和 pm.min_spare_servers 一样的值即可。
  • pm.min_spare_servers,规定了空闲状态下 PHP-FPM 的最小进程数量。
  • pm.max_spare_servers,规定了空闲状态下 PHP-FPM 的最大进程数量,即如果空闲进程数大于 pm.max_spare_servers 的话,多出的空闲进程就会被杀掉,使得 PHP 的内存占用保持在一个较低水平。所以这个值可以设置为 pm.max_children 的一半甚至更低。

以下是一个参考,以 1G 内存的机器为例:

pm.max_children = 25
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 15

Done!

修改完配置文件记得重启服务:

systemctl restart nginx
systemctl restart php7.4-fpm

之后再用 phpinfo() 测试一下就可以正常使用了!

常见问题

重启 Nginx 时报错

如果在重启 Nginx 时看到这条错误:

nginx.service: Failed to read PID from file /run/nginx.pid: Invalid argument

不用紧张,这是因为 Nginx 启动需要一点点时间,而 Systemd 在 Nginx 完成启动前就去读取 PID 文件导致出错。

解决起来也很简单,让 Systemd 在 Nginx 启动后等一下就可以了:

mkdir /etc/systemd/system/nginx.service.d
printf "[Service]\nExecStartPost=/bin/sleep 0.1\n" > /etc/systemd/system/nginx.service.d/override.conf
systemctl daemon-reload
systemctl restart nginx

作为 LEMP 必不可少的一员,MySQL 的安装配置要稍微复杂一些,可以参考 Debian 下安装和配置 MySQL 8.0