Ubuntu18.04 搭建 PHP 环境

2019-12-26

本博客所有文章采用的授权方式为 自由转载-非商用-非衍生-保持署名 ,转载请务必注明出处,谢谢。

声明:
本博客欢迎转发,但请保留原作者信息!
博客地址:任志帆的博客;
内容系本人学习、研究和总结,如有雷同,实属荣幸!

Ubuntu18.04 搭建 PHP 环境


1.初始化系统

实验环境

我们基于一台全新的 Ubuntu 18.04 LTS 服务器

更新软件源

登录到服务器,我们首先要做的就是更新软件源:

$ apt update

注意:这里所说的「更新软件源」并非升级软件,在中文内更加准确的描述应当是 刷新软件源。在这个过程中,包管理器(也就是 APT,可以理解为「软件管家」之类)将会从 软件源 服务器上获取一份最新的包列表并建立本地缓存,包括软件名称、描述、最新版本、下载地址等等。

你将会看到类似这样的输出:

root@JD:~# apt update
Hit:1 http://mirrors.jdcloudcs.com/ubuntu bionic InRelease
Hit:2 http://mirrors.jdcloudcs.com/ubuntu bionic-updates InRelease
Hit:3 http://mirrors.jdcloudcs.com/ubuntu bionic-backports InRelease
Hit:4 http://mirrors.jdcloudcs.com/ubuntu bionic-security InRelease
Reading package lists... Done
Building dependency tree       
Reading state information... Done
112 packages can be upgraded. Run 'apt list --upgradable' to see them.

最后一行有这样的提示:

112 packages can be upgraded. Run 'apt list --upgradable' to see them.

意为有 112 个软件包可升级,执行 apt list --upgradable 命令来查看它们。

我们暂且忽略,直接升级:

$ apt upgrade

注意:生产环境下,更新任何软件包前都需要仔细检查,确保更新日志内没有影响现有环境的改动。另外,你也可以先不升级,对后续部署基本没有影响。

你将会看到一大坨(是的,一坨)输出,它们是将被升级的软件列表;注意关注最后几行:

112 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 196 MB of archives.
After this operation, 348 MB of additional disk space will be used.
Do you want to continue? [Y/n] 

意为此操作将占用 348 MB 磁盘空间。此时输入 Y(注意关闭中文输入法),或直接回车即可开始升级。主流云服务厂商均有缓存软件源,数据流量是通过内网传输,所以该过程不会太慢。

本地化配置

所谓「本地化配置」,可理解为系统时区、单位、地址、语言等配置的统称。使其能够符合某一地区的习惯。虽然我们的母语是中文,但还是建议将服务器配置为英语,尽可能避免奇葩乱码等问题带来的影响。

首先,执行以下命令生成美国本地化数据:

$ locale-gen en_US.UTF-8

随后将本地化配置修改为 en_US.UTF-8 即可:

$ update-locale LC_ALL=en_US.UTF-8

如果服务器在国外,则服务商可能不会将其配置为东八区;我们还需手动修改时区为 Asia/Shanghai

timedatectl set-timezone Asia/Shanghai

若你是在国内云服务商租用的服务器,那么极有可能时区已经配置好了。

至此,系统初始化阶段完成。

2.安装 Nginx

上节我们刚刚完成一些基础的初始化工作;接下来,可以开始安装软件包了。在本课程内,我将使用大名鼎鼎的 Nginx 作为 Web 服务。

通过apt安装 Nginx

由于我们执行 apt update 更新软件源不久,所以直接安装 Nginx 即可:

$ apt install nginx

再次收到确认提示:

0 upgraded, 18 newly installed, 0 to remove and 0 not upgraded.
Need to get 2,461 kB of archives.
After this operation, 8,210 kB of additional disk space will be used.
Do you want to continue? [Y/n] 

上节为大家介绍过输入 Y 或直接回车均可继续,也就是说此处的询问默认结果为 Y。有个普遍共识是,在提供选项供用户选择时,以大写项为默认值。例如此处的 [Y/n] 那么 Y 即为默认值;同理,若是 [a/b/c/D/e],那么 D 即为默认值。

另外,上节介绍了更新软件源即为包管理器从软件源服务器拉取软件包列表并建立本地缓存。其实,当我们执行 apt install 操作时,包管理器便会从本地缓存中找到该软件包的指定版本,并进行下载、安装。

稍等几秒钟即可安装成功:

管理 Nginx 服务

我们可使用 service 命令管理服务状态,常用操作如下:

$ service nginx start # 启动 Nginx
$ service nginx stop # 停止 Nginx
$ service nginx restart # 重启 Nginx

同时,可使用 systemctl 命令开关服务的开机自启:

$ systemctl enable nginx # 启用 Nginx 开机启动
$ systemctl disable nginx # 禁用 Nginx 开机启动

注意:通常情况下,在 APT 安装后已默认启用 Nginx 开机启动。

确认 Nginx 正常运行

在浏览器内输入服务器公网 IP(或域名)并打开,出现默认欢迎页面说明 Nginx 已经正常运行:

恭喜,Nginx 安装成功。

3.安装 PHP-FPM

安装 PHP 7.3。

配置第三方软件源

由于 Ubuntu 的官方软件源通常不包含最新版本的 PHP,因此需要添加一个包含最新 PHP 的第三方软件源。

在添加之前,我们首先安装名为 software-properties-common 的软件包,它提供了快速管理软件源的实用脚本:

$ apt install -y software-properties-common

相比之前执行的 apt install 命令,这次我添加了 -y 选项,表示当 APT 遇到询问时默认确认,避免再次输入 Y 并回车。

随后,执行以下脚本添加第三方 PHP 软件源:

$ add-apt-repository -y ppa:ondrej/php

成功后别忘记刷新:

$ apt-get update

安装 PHP

PHP 的安装实际上分为三个软件包:

  • PHP - PHP 自身。
  • PHP-CLI - PHP 的命令行接口,通俗地说,在命令行内执行 php 便依赖于此包。
  • PHP-FPM - 全称为 PHP FastCGI Process Manager,用于管理 PHP 进程,并提供 FastCGI 接口与 Nginx 交互;浏览网页时的请求便是由 Nginx 交由 PHP-FPM 处理的。

apt install 支持多参数,所以我们不必执行多次安装,只需在单条命令内写明多个软件包即可:

$ apt install -y php7.3 php7.3-cli php7.3-fpm php7.3-dev

按照 Laravel安装文档 的说明,接着安装几个必备的 PHP 扩展:

$ apt install -y php7.3-mbstring php7.3-xml php7.3-bcmath

注意:由于 PDO 等扩展已经内置在 PHP 中,故无需额外安装。

对于不同项目的不同依赖,可能有必要安装以下扩展,根据实际情况选择即可:

$ apt install php7.3-curl php7.3-gd php7.3-mysql php7.3-opcache php7.3-zip php7.3-sqlite3

有个小技巧是,你可以通过 apt-cache 命令来搜索当前软件源内的包:

$ apt-cache search php7.3

例如以上命令,将会得到所有名称、描述等信息内包含 php7.3 字样的软件包:

php-amqp - AMQP extension for PHP
php-apcu - APC User Cache for PHP
php-geoip - GeoIP module for PHP
...

管理 PHP-FPM 服务

与管理 Nginx 服务类似,你同样可以通过 servicesystemctl 命令管理 PHP-FPM 服务:

$ service php7.3-fpm restart # 重启 PHP-FPM
$ service php7.3-fpm start # 启动 PHP-FPM
$ service php7.3-fpm stop # 停止 PHP-FPM
$ systemctl enable php7.3-fpm # 启用 PHP-FPM 开机启动
$ systemctl disable php7.3-fpm # 禁用 PHP-FPM 开机启动

注意:不同版本的 PHP-FPM 服务名是不一致的。例如 7.2 为 php7.2-fpm,7.3 为 php7.3-fpm,以此类推……

确认 PHP-FPM 正常运行

通过以下命令可确认 PHP-FPM 进程正在运行:

$ ps aux | grep php

其中:

  • ps aux 用于列出系统当前正在运行的所有进程的所有信息。
  • | 名为管道操作符,将前一条命令的标准输出连接到下一条命令的标准输入。
  • grep 是一款文本搜索工具,常用来过滤命令行输出;php 是搜索的关键词。

ps 将进程信息输出到 grep 进行过滤,后者筛选出包含 php 字样的行,再将它们输出。于是,它们相结合,产生的效果便是这样:

root@JD:~# ps aux | grep php
root     24292  0.0  0.2 314952 20508 ?        Ss   11:35   0:00 php-fpm: master process (/etc/php/7.3/fpm/php-fpm.conf)
www-data 24318  0.0  0.1 317252  8652 ?        S    11:35   0:00 php-fpm: pool www
www-data 24319  0.0  0.1 317252  8652 ?        S    11:35   0:00 php-fpm: pool www
root     24391  0.0  0.0  13136  1048 pts/0    S+   11:36   0:00 grep --color=auto php

忽略最后一行(这是我们正在执行的 grep 命令),可观察到有 php-fpm 进程正在运行中。

若 PHP-FPM 进程不存在,那么输出将只有孤零零的 grep

root     24391  0.0  0.0  13136  1048 pts/0    S+   11:36   0:00 grep --color=auto php

提示:你可以结合上文提到的 service 命令,将服务进程手动停止试试看;测试完毕不要忘记再次启动。

4.Composer

Composer 是部署 PHP 项目时必不可少的工具

安装 Composer

Composer 比较特殊,不能通过 APT 安装。虽然网络上流传着一大堆从第三方服务器直接下载 composer.phar 文件的安装方式,但根据 Composer 的官方文档,正确的安装姿势应当为:

第一种方式

参考链接

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'baf1608c33254d00611ac1705c1d9958c817a1a33bce370c0595974b342601bd80b92a3f46067da89e3b06bff421f182') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

第二种方式

参考链接

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

第三种方式

参考链接

$ wget https://raw.githubusercontent.com/composer/getcomposer.org/master/web/installer -O - -q | php -- --filename=composer --install-dir=/usr/local/bin

注意:通过第三方服务器、直接下载 composer.phar 不进行任何检查,均无法保证 Composer 正常运行,且存在安全风险!请务必遵循官方文档内的说明。

稍等片刻,将会出现以下输出:

All settings correct for using Composer
Downloading...

这里最好按照第二种方式 执行 mv composer.phar /usr/local/bin/composer 然后可以在任何地方执行composer了

提示当前环境检查通过,可正常使用 Composer;随后开始下载。

鉴于众所周知的原因,大陆访问国际网络速度奇慢无比,请耐心等待。当出现以下提示时,表示已经安装成功:

Composer (version 1.9.1) successfully installed to: /root/composer.phar
Use it: php composer.phar

按照提示,我们可以使用 /usr/local/bin/composer 运行 Composer,当然,还有个更简单的方法:

$ mv composer.phar /usr/local/bin/composer
$ composer

你可能会收到这样一条警告:

Do not run Composer as root/super user! See https://getcomposer.org/root for details

意为请勿使用根用户运行 Composer;暂时不必关心它,我将在后续课程中详细说明。

配置 Packagist 中国镜像

这一步是可选的。如果你的服务器位于大陆,强烈建议使用可信赖的代理,或是国内 Packagist 镜像。

推荐使用阿里云提供的 Packagist 中国镜像,执行以下命令即可切换服务器内 Composer 的默认 Packagist 源:

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

5.部署应用代码

这里以laravel项目为例

创建一个新项目

laravel官网

cd /var/www/
composer create-project --prefer-dist laravel/laravel blog

若提示是没有zip扩展 那么请首先安装扩展

apt-get install php7.3-zip -y

配置文件所有者

最后,别忘记修改文件所有者:

$ chown -R www-data:www-data .

由于目前所在的工作目录为 /var/www/blog,所以可用表示当前工作目录的 . 代替之前的 /var/www/blog,它们是等效的。

至此,本小节目标完成。你可以通过 ll 命令来列出当前目录:

root@JD:/var/www/blog# ll
total 300
drwxr-xr-x 12 www-data www-data   4096 Dec 26 12:03 ./
drwxr-xr-x  4 root     root       4096 Dec 26 12:02 ../
...

6.配置 Nginx 站点

Nginx 站点配置

根据 Laravel部署文档 的说明,我们可直接拿到一份现成的 Nginx 配置文件,稍作调整即可:

我这里做了下解释说明 参考文章

server {
    #监听 HTTP 协议默认的 [80] 端口。
    listen 80;
    #绑定主机名 [example.com]。
    server_name example.com;
    #服务器站点根目录 [/example.com/public]。
    root /example.com/public;

    # 添加几条有关安全的响应头
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    # 站点默认页面;可指定多个,将顺序查找。
    # 例如,访问 http://example.com/ Nginx 将首先尝试「站点根目录/index.html」是否存在,不存在则继续尝试「站点根目录/index.htm」,以此类推...
    index index.html index.htm index.php;

    # 指定字符集为 UTF-8
    charset utf-8;

    # Laravel 默认重写规则;删除将导致 Laravel 路由失效且 Nginx 响应 404。
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    # 关闭 [/favicon.ico] 和 [/robots.txt] 的访问日志。
    # 并且即使它们不存在,也不写入错误日志。
    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }
    
    # 将 [404] 错误交给 [/index.php] 处理,表示由 Laravel 渲染美观的错误页面。
    error_page 404 /index.php;

    # URI 符合正则表达式 [\.php$] 的请求将进入此段配置
    location ~ \.php$ {
        # 配置 FastCGI 服务地址,可以为 IP:端口,也可以为 Unix socket。
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        # 配置 FastCGI 的主页为 index.php。
        fastcgi_index index.php;
        # 配置 FastCGI 参数 SCRIPT_FILENAME 为 $realpath_root$fastcgi_script_name。
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        # 引用更多默认的 FastCGI 参数。
        include fastcgi_params;
    }
    # 通俗地说,以上配置将所有 URI 以 .php 结尾的请求,全部交给 PHP-FPM 处理。
    
    # 除符合正则表达式 [/\.(?!well-known).*] 之外的 URI,全部拒绝访问
    # 也就是说,拒绝公开以 [.] 开头的目录,[.well-known] 除外
    location ~ /\.(?!well-known).* {
        deny all;
    }
}

通常我们仅需修改 server_namerootfastcgi_pass;请注意阅读 # 后的注释。

cd /etc/nginx/sites-available

vi  blog.cn #填入你对应的配置信息

#建立软连接
sudo ln -s /etc/nginx/sites-available/acme.cn /etc/nginx/sites-enabled/

#检测nginx配置是否正确
nginx -t
#配置正常返回如下结果
#nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
#nginx: configuration file /etc/nginx/nginx.conf test is successful

#重启nginx
service nginx restart

#重启fpm 这里一定要重启
service php7.3-fpm restart

FastCGI 服务地址为 IP:端口时的配置

首先修改php的配置文件

 vim /etc/php/7.3/fpm/pool.d/www.conf

在37行加入如下代码

 listen = 127.0.0.1:9000

另外需要注意下如果配置文件内有 listen =/run/php/php7.3-fpm.sock 最好注释 以免冲突

配置一

若fpm配置文件中配置如下:

 listen = 127.0.0.1:9000

则对应的nginx.conf中的配置应为:

 fastcgi_pass   127.0.0.1:9000;

此时开启9000端口监听,不会生成sock文件

配置二

若fpm中的配置为使用Unix套接字,如下:

 listen = /run/php/php7.3-fpm.sock

则对应nginx.conf中的配置应为:

 fastcgi_pass   unix:/run/php/php7.3-fpm.sock;

此时9000端口未开启,在/run/php/下生成php7.2-fpm.sock文件:

注意

若两者不匹配则nginx启动失败。

若fpm为sock,nginx为127.0.0.1:9000,则会出现以下错误:

connect() failed (111: Connection refused) while connecting to upstream

若fpm未127.0.0.1:9000,nginx为sock,则会出现以下错误:

connect() to unix:/run/php/php7.2-fpm.sock failed (2: No such file or directory) while connecting to upstream

重载 Nginx

配置完成后,请务必重启(Restart)或重载(Reload)Nginx。

什么是 重载?实际上,直接重启 Nginx 是不安全的。原因有二:

  • 在 Nginx 进程结束再重新运行的过程中,将造成极短时间的闪断。虽然这一时间通常很短(一般来说在秒级别),但倘若面对大量并发,还是极易造成一部分请求无法访问,即服务中断。
  • 在重启的过程中,若此时 Nginx 恰好正在处理请求,与客户端的 TCP 连接将会断开,客户端无法收到正确响应,造成前后端信息不一致。

在之前的小节中,已经提到重启 Nginx 的方法;

$ service nginx restart

同样地,亦可使用 service 命令重载 Nginx:

$ service nginx reload

另一种等效的方法是:

$ nginx -s reload

最终效果

在浏览器内输入服务器公网 IP 或域名并访问,你将会看到 Laravel 应用的默认主页:

页面效果

恭喜你,部署成功。

7.安装MYSQL

通过apt安装mysql

apt-get install mysql-server mysql-client -y

管理 Mysql 服务

我们可使用 service 命令管理服务状态,常用操作如下:

$ service mysql start # 启动 Mysql
$ service mysql stop # 停止 Mysql
$ service mysql restart # 重启 Mysql

同时,可使用 systemctl 命令开关服务的开机自启:

$ systemctl enable mysql # 启用 Mysql 开机启动
$ systemctl disable mysql # 禁用 Mysql 开机启动

通过以上配置,可使 Nginx 匹配请求 URI,若以 jscss 结尾,则将响应头 Expires 的值设置为 24h 返回。客户端浏览器将根据该值建立资源缓存,并在指定时间后过期,因此可节省部分服务器静态资源流量。24h 可根据需要调整,若使用 CDN 服务分发静态资源,则不必配置此项。

测试

root@JD:/var/run/php# mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.28-0ubuntu0.18.04.4 (Ubuntu)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

出现以上结果说明mysql安装成功

进入数据库后输入命令 设置新的密码

use mysql;
update mysql.user set authentication_string=PASSWORD('新密码'), plugin='mysql_native_password' where user='root';
#执行成功显示如下
#Query OK, 1 row affected, 1 warning (0.00 sec)
#Rows matched: 1  Changed: 1  Warnings: 1

#刷新权限
flush privileges;
#Query OK, 0 rows affected (0.00 sec)

exit;

重启MySQL服务,再次进入数据库吗,输入新设置的密码 重启mysql服务

service mysql restart

mysql -u root -p

mysql 创建新用户

创建一个所有权用户

mysql -u root -p
mysql>create user db_user@'%' identified by 'db_password'; #创建用户
mysql> grant all privileges on *.* to db_user@'%' with grant option; #授权
flush privileges;
mysql> exit;

创建一个条件限制用户

添加一个用户名为db_user,密码为db_pass,授权为% (%表示所有IP能连接)对db_name数据库所有权限,命令如下:

#MySQL8.0版本
mysql -u root -p
mysql>create user db_user@'%' identified by 'db_pass';#创建用户
mysql> grant all privileges on db_name.* to db_user@'%' with grant option; #授权
flush privileges;
mysql> exit;

#其余MySQL版本
mysql> grant all privileges on db_name.* to db_user@'%' identified by 'db_pass'; #授权语句,特别注意有分号
flush privileges;
mysql> exit;

注意

最后记得重启 service mysql restart 还有 如果是云服务器 记得设置安全组允许端口访问

设置允许外网访问

vi /etc/mysql/mysql.conf.d/mysqld.cnf
#注释掉 #bind-address = 127.0.0.1

#再重启启动mysql 生效
service mysql restart

测试

效果如图

8.生产环境的必要优化

本篇内容部分摘选自 Laravel部署文档,你可以阅读该文档获取更多信息。

Nginx 配置

对于 Laravel 应用来说,优化 Nginx 配置所带来的性能提升可谓微不足道。因此不建议在中小型项目中花费较多精力调优 Nginx。

不过,有一点值得注意:

server {
    # ...
    location ~* \.(js|css)$ {
        expires 24h;
    }
    #...
}

通过以上配置,可使 Nginx 匹配请求 URI,若以 jscss 结尾,则将响应头 Expires 的值设置为 24h 返回。客户端浏览器将根据该值建立资源缓存,并在指定时间后过期,因此可节省部分服务器静态资源流量。24h 可根据需要调整,若使用 CDN 服务分发静态资源,则不必配置此项。

Laravel 的配置缓存与路由缓存

开启 配置缓存路由缓存 能够在一定程度上提升 Laravel 的性能。

$ php artisan config:cache # 生成配置缓存

注意:当开启配置缓存后,env() 函数将会失效;它将会永远返回 null;因此务必确保在非配置文件内,未直接调用该函数。

$ php artisan route:cache # 生成路由缓存

注意:路由缓存仅支持控制器风格;若路由注册时存在闭包(Closures),则无法使用该功能。

注意:生成缓存后,对配置和路由的修改将不会生效,需再次执行缓存命令,或使用 php artisan cache:clear 命令清除它们。

Composer

在安装依赖时,建议使用以下命令:

$ composer install --optimize-autoloader --no-dev

其中,--optimize-autoloader 表示生成优化后的自动加载器,虽然生成过程可能较慢,但换来的是提高运行时的效率。--no-dev 表示不安装 composer.json 中 require-dev 声明的扩展包,在生产环境中我们不需要这些开发依赖。

再谈文件权限

文件权限直接关系到服务器安全与否。通常情况下,我们应当遵循「最小权限原则」,即权限越小越好。对于 Laravel 来说,我个人比较倾向的权限配置为:

$ cd /var/www/blog
$ chmod -R 750 .
$ chmod -R 770 storage bootstrap/cache

你可以通过在线工具 Chmod Calculator 来计算八进制权限数字:

上图是 750 所代表的权限,即文件所有者可 读、写、执行(进入),文件所有组可 读、执行(进入),其余用户 均不可

注意:对于文件来说,Execute 权限表示可执行;对于目录来说,表示可进入(即 cd)。为方便描述,以下统称为「执行」权限。

也就是说,运行 Nginx 和 PHP-FPM 的 www-data 用户,可读、写、执行;www-data 用户组内的用户可读、执行。

770 则更加宽松 —— 对于 Laravel 运行时需要写入的目录,赋予文件所有组可 读、写、执行 权限;也就是说 www-data 用户组内的用户可写 storagebootstrap/cache 目录。

杂项

根据应用本身的逻辑不同,涉及的 Laravel 功能也不一样。针对部分项目,你有可能还需要执行以下 Artisan 命令:

$ php artisan storage:link # 软链接 app/storage 到 public 目录,以便公开访问
$ php artisan migrate # 执行迁移
$ php artisan db:seed # 执行数据填充


章节列表