CentOS 8配置Nginx+PHP+MySQL

作为服务器系统再加上一个PHP开发者,使用CentOS8系统运行LNMP技术栈是件很正常的事,再加上作为一个强迫症,有了这种新系统软件新版本,忍不住想要折腾下,这里把我在CentOS8上的配置Nginx+PHP+MySQL过程及遇到的坑记录一下,顺便备份下相关配置文件,方便自己有需要的朋友查找。

开始之前

开始配置之前,说说几个前提条件:

本文是基于CentOS8系统进行配置Nginx+PHP+MySQL,如果是对Linux不熟悉的朋友,建议备份数据重新安装一个纯净版的系统再跟着步骤走,以免遇到一些未预期的问题。
虽然CentOS8支持使用AppStream安装软件,但是因为有些module不能把所有需要的软件组件安装上,所以我这里还是使用的传统的包管理器进行安装。

为PHP-FPM及Nginx创建专门的用户

考虑到安全问题,我建议为PHP-FPM及Nginx专门创建一个只用来跑Web服务、没有home目录也不允许登录的用户,我这里是创建一个www用户组,然后创建一个www用户并分配到www组,命令如下:

groupadd www
useradd -s /sbin/nologin www -g www -M

-s参数是表示不允许登录,-g参数是分配到www组,-M表示不创建用户目录。
后面我们统一用www用户组下面的www用户来运行Nginx及PHP-FPM,这样就能解决文件读写权限问题。

安装PHP

CentOS8自带了PHP7.2版本,相对来说比较新,暂时不需要借助第三方的源来安装,而且CentOS8自带的PHP的模块也相对来说够用,使用下面命令可以看到所有PHP相关的包:

[root@cloudbool-Vultr ~]# yum search php
Last metadata expiration check: 0:01:07 ago on Thu 07 Nov 2019 12:39:59 PM UTC.
============================================================================================ Name & Summary Matched: php =============================================================================================
php.x86_64 : PHP scripting language for creating dynamic web sites
php-common.x86_64 : Common files for PHP
php-common.x86_64 : Common files for PHP
php-fpm.x86_64 : PHP FastCGI Process Manager
php-fpm.x86_64 : PHP FastCGI Process Manager
php-dbg.x86_64 : The interactive PHP debugger
php-cli.x86_64 : Command-line interface for PHP
php-cli.x86_64 : Command-line interface for PHP
php-pgsql.x86_64 : A PostgreSQL database module for PHP
php-devel.x86_64 : Files needed for building PHP extensions
php-xml.x86_64 : A module for PHP applications which use XML
php-xml.x86_64 : A module for PHP applications which use XML
php-ldap.x86_64 : A module for PHP applications that use LDAP
php-json.x86_64 : JavaScript Object Notation extension for PHP
php-json.x86_64 : JavaScript Object Notation extension for PHP
php-embedded.x86_64 : PHP library for embedding in applications
php-enchant.x86_64 : Enchant spelling extension for PHP applications
php-pear.noarch : PHP Extension and Application Repository framework
php-intl.x86_64 : Internationalization extension for PHP applications
php-pear-Cache-Lite.noarch : Fast and Safe little cache system for PHP
php-odbc.x86_64 : A module for PHP applications that use ODBC databases
php-dba.x86_64 : A database abstraction layer module for PHP applications
php-pdo.x86_64 : A database access abstraction module for PHP applications
php-soap.x86_64 : A module for PHP applications that use the SOAP protocol
php-gmp.x86_64 : A module for PHP applications for using the GNU MP library
php-mysqlnd.x86_64 : A module for PHP applications that use MySQL databases
php-process.x86_64 : Modules for PHP script using system process interfaces
php-bcmath.x86_64 : A module for PHP applications for using the bcmath library
php-recode.x86_64 : A module for PHP applications for using the recode library
php-gd.x86_64 : A module for PHP applications for using the gd graphics library
php-snmp.x86_64 : A module for PHP applications that query SNMP-managed devices
php-xmlrpc.x86_64 : A module for PHP applications which use the XML-RPC protocol
php-mbstring.x86_64 : A module for PHP applications which need multi-byte string handling
php-mbstring.x86_64 : A module for PHP applications which need multi-byte string handling
perl-PHP-Serialization.noarch : Converts between PHP's serialize() output and the equivalent Perl structure
================================================================================================= Name Matched: php ==================================================================================================
php-opcache.x86_64 : The Zend OPcache
php-pecl-zip.x86_64 : A ZIP archive management extension
php-pecl-apcu.x86_64 : APC User Cache
php-pear-Date.noarch : Date and Time Zone Classes
php-pear-Mail.noarch : Class that provides multiple interfaces for sending emails
php-pear-Net-URL.noarch : Easy parsing of URLs
php-pear-Net-SMTP.noarch : Provides an implementation of the SMTP protocol
php-pear-Auth-SASL.noarch : Abstraction of various SASL mechanism responses
php-pecl-apcu-devel.x86_64 : APCu developer files (header)
php-pear-Net-Socket.noarch : Network Socket Interface
php-pear-HTTP-Request.noarch : Provides an easy way to perform HTTP requests

其中,php-cli是我们命令运行PHP所需要的,php-fpm是用来配合Nginx使用的,php-mysqlnd是连接MySQL使用的,php-pear在安装一些特定的模块比如说Redis、MongoDB、Swoole等需要用到,php-mbstring包含了一些加密解密函数,php-gd是图形库,生成图形验证码可能需要用到,php-opcache是用来加速PHP运行的,php-process在Swoole相关进行需要用到等等。

安装PHP相关包

PHP的模块我们不需要全部安装,仅需要安装一些必须的,以常用的WordPress及Laravel来说,我们只需要安装如下几个包就行:

yum install php-cli php-fpm php-gd php-mysqlnd php-mbstring php-opcache php-pdo

配置PHP-FPM

安装好了之后,我们还需要稍稍配置一下PHP-FPM,以让其更好的与Nginx进行配合工作。
编辑**/etc/php-fpm.d/www.conf **文件,这个文件有两个需要注意的地方,其中一个就是运行PHP-FPM的用户及对应的用户组:

vim /etc/php-fpm.d/www.conf
:%s/apache/www/g

修改上述文件,将其中的usergroup字段由apache更改成上述我们创建的www
另外一个就是**listen = /run/php-fpm/www.sock **这个配置项,这一行配置了PHP-FPM运行模式及对应的文件目录,我们后面配置Nginx时会用到它。
启动:

systemctl start php-fpm

Nginx安装及配置

安装Nginx很简单,CentOS8系统源自带,只需要一行命令就能安装好:

yum install nginx

启动:

systemctl start nginx

基础配置也很简单,到这一步,我们只需要稍稍改动一下Nginx的配置文件就行,Nginx的配置文件在/etc/nginx/nginx.conf,这个配置文件能配置Nginx所有的功能,包括其他的配置文件也是通过这个文件进行加载。打开其配置文件,修改user字段,并增加几行可能会用上的配置:

vim /etc/nginx/nginx.conf
user = www www;
//开启gzip压缩
gzip  on;
//关闭Nginx版本号显示
server_tokens off;
//增加最大上传文件大小
client_max_body_size 8M;

主要是更改user哪一行,后面几个配置可以选择性增加,如果不知道其什么意思也可以暂时不加。
至于配置文件中默认的default_server那一部分,是自带的默认host,如果不需要的可以删除,或者直接返回404。
到目前为止,Nginx的本身配置已经完成。

MySQL 8安装

其实CentOS8系统自带了MySQL8和MariaDB 10.3.11,如果是从CentOS7升级上来的朋友,可能更习惯MariaDB,虽然说MySQL和MariaDB本身区别不大,但是出于兼容性的考虑,我还是更倾向于选择MySQL,毕竟使用MariaDB数据库有的时候出现一些和MySQL差别问题其实挺烦的,而且很多软件也是安装MySQL本身来适配的,所以我这里使用MySQL 8。
安装MySQL8及对应工具:

yum install mysql mysql-server

启动MySQL服务器:

systemctl start mysqld

然后是初始化MySQL,命令如下:

[root@cloudbool-Vultr ~]# mysql_secure_installation
Securing the MySQL server deployment.
Connecting to MySQL using a blank password.
VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?
Press y|Y for Yes, any other key for No:  //是否设置密码
Please set the password for root here.
New password:  //设置新密码
Re-enter new password:  //重复密码
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y //是否移出匿名用户
Success.
Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y //是否禁止root远程登录
Success.
By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y //是否删除测试数据库
 - Dropping test database...
Success.
 - Removing privileges on test database...
Success.
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y //是否立即重新加载权限表
Success.
All done!

我也不知道从哪个版本开始,MySQL提供了一个程序mysql_secure_installation用来初始化MySQL信息,通过这个程序,我们可以进行如下操作:

  • 设置root密码
  • 更换root密码
  • 移除匿名用户
  • 禁用root用户远程登录
  • 删除测试数据库
  • 重新加载权限表

根本不用自己写SQL语句去更改MySQL的root密码,通过这个小程序就能直接设置/更改root密码,非常方便。
需要注意的是,从某个版本开始,MySQL默认加载了VALIDATE PASSWORD插件,但是CentOS8自带的MySQL并没有默认启用,如果想要启用可以在执行上一个命令的时候开启。这个插件设置/更改密码分为低中高三个策略,简单的说就是包含大小写字母及数字和标点符号等,详细资料可以参考这里: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html
其实到这一步,LNMP整体就配置好了,下面的步骤就是为添加网站而做的,比如说添加Nginx的配置文件以增加网站,为每个网站创建单独的数据库等。

为网站添加单独的Nginx配置文件

其实放置网站的Nginx配置文件各个发行版都有自己的做法,有些是放在/etc/nginx/conf.d/,有些是放在/etc/nginx/site-avaliable,但是我为了统一,一般都是放在前者,这样就不用管什么发行版,更加方便去查找。
以域名cloudbool.com为例,假如网站文件放在/var/www/cloudbool,相关配置文件举例如下:

vim /etc/nginx/conf.d/cloudbool.conf
server {
    listen       80;
    listen       [::]:80;
    server_name  cloudbool.com;
    root         /var/www/cloudbool;
    include /etc/nginx/default.d/*.conf;
    location / {
                try_files $uri $uri/ /index.php?$args;
    }
    error_page 404 /404.html;
        location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
    access_log /var/log/nginx/cloudbool.log;
    error_log /var/log/nginx/cloudbool-error.log;
}

CentOS8系统Nginx配置HTTPS

当然,上面只是最简单的一个实例文件,如果我们只是本地开发或者不需要考虑HTTPS的情况下可以这么使用,如果是正式环境或者需要HTTPS的情况下,还需要加上HTTPS相关配置,下面是包含HTTPS的配置文件:

vim /etc/nginx/conf.d/cloudbool-ssl.conf
server{
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name  cloudbool.com;
        index index.html index.php;
        root  /var/www/cloudbool/public;
        ssl_certificate /var/www/ssl/cloudbool.crt;
        ssl_certificate_key /var/www/ssl/cloudbool.key;
        ssl_session_cache        shared:SSL:10m;
        ssl_session_timeout      10m;
        ssl_session_tickets      on;
        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_dhparam /var/www/ssl/dhparam.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
                include /etc/nginx/default.d/*.conf;
        location / {
                try_files $uri $uri/ /index.php?$args;
        }
        access_log /var/log/nginx/cloudbool.log;
        error_log /var/log/nginx/cloudbool-error.log;
        error_page 404 /404.html;
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
                root /usr/share/nginx/html;
        }
}
server
{
        listen          80;
        server_name cloudbool.com;
        location / {
                rewrite ^/(.*)$ https://cloudbool.com/archive/$1 permanent;
        }
}

是的,上面没有包含location ~ .php$ {} 块,因为CentOS8源仓库里的Nginx默认提供了PHP部分相关配置。PHP相关部分配置文件位于/etc/nginx/default.d/php.conf,文件内容如下:

index index.php index.html index.htm;
location ~ \.(php|phar)(/.*)?$ {
    fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;
    fastcgi_intercept_errors on;
    fastcgi_index  index.php;
    include        fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO $fastcgi_path_info;
    fastcgi_pass   php-fpm;
}

上面部分的Server块是用来配置对应网站的HTTPS部分功能,下面Server块是用来强制将HTTP请求原封不动的重定向到对应的HTTPS链接地址,比如说将http://cloudbool.com/about 重定向到 https://cloudbool.com/archive/about

网站文件目录赋予可读写权限

除了在Nginx配置文件中指定网站文件目录,还需要在赋予对应的用户可读写权限,上面是指定使用www用户组的www用户,指定的网站文件目录为/var/www/cloudbool/,对应的命令如下:

chown -R www.www /var/www/cloudbool

为网站创建单独的MySQL数据库

出于安全考虑,不建议使用root用户来运行网站使用的MySQL数据库,我更建议创建单独的数据库及对应的用户来运行对应的数据库,对应的命令如下:

mysql -p
//root密码
create database if not exists cloudbool default character set utf8mb4 collate utf8mb4_unicode_ci;
create user cloudbool_user@'localhost' IDENTIFIED BY 'cloudbool_password';
grant all privileges on cloudbool.* to cloudbool_user@localhost identified by 'cloudbool_password';
flush privileges;

其中,上面cloudbool就是数据库名称,cloudbool_user为创建的用户名,cloudbool_password是对应的密码,实际创建的时候根据情况更改就好。

常见问题

网站/服务器不能访问

刚安装的Nginx默认是不启动的,如果遇到浏览器出现ERR_CONNECTION_REFUSED或者无法访问此网站xxxxxx 拒绝了我们的连接请求。,可能是Nginx还没有启动,需要手动启动,命令为systemctl start nginx
如果Nginx启动之后还是无法访问,则可能是防火墙或者安全组没有放行,如果是海外的服务器,还可能是因为某些原因可能在国内无法访问,详细的解决思路及办法可以移步这里:服务器端口或服务无法访问解决办法

网站打开页面空白

一般来说,网站页面空白是Nginx没有配置正确,如果后端是PHP相关程序,请依照上述配置过程检查是否有遗漏的步骤。

访问PHP文件弹出下载窗口或者直接下载了文件

这种情况是因为Nginx与PHP-FPM程序没有配合好,具体就是location ~ .php$ {}这一个配置块。如果是CentOS8系统,且使用的是源自带的Nginx,直接在Nginx的网站配置文件中添加下述一行就行:

include /etc/nginx/default.d/*.conf;

或者也可以直接添加这一部分代码块:

index index.php index.html index.htm;
location ~ \.(php|phar)(/.*)?$ {
    fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;
    fastcgi_intercept_errors on;
    fastcgi_index  index.php;
    include        fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO $fastcgi_path_info;
    fastcgi_pass   php-fpm;
}

添加之后重启Nginx就好了。

网站程序提示没有写入权限

网站程序没有写入权限,一般有两个问题,一个是Nginx和PHP-FPM使用的运行用户不一样,这种情况只需要将两个程序的运行用户设置成一样就好了,比如设置成上面专门添加的www用户组的www用户。
如果设置成了相同用户,还是提示没有写入权限,那可能是没有更改网站文件所在目录的权限,命令格式如下:

chown -R www.www /var/www/cloudbool

其中两个www是运行Nginx和PHP-FPM的用户组和用户名,后面的路径是网站文件所在目录。