Ubuntu18.04 搭建 PHP 环境
本博客所有文章采用的授权方式为 自由转载-非商用-非衍生-保持署名 ,转载请务必注明出处,谢谢。
声明:
本博客欢迎转发,但请保留原作者信息!
博客地址:任志帆的博客;
内容系本人学习、研究和总结,如有雷同,实属荣幸!
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 服务类似,你同样可以通过 service
和 systemctl
命令管理 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项目为例
创建一个新项目
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_name
、root
和 fastcgi_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,若以 js
或 css
结尾,则将响应头 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,若以 js
或 css
结尾,则将响应头 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
用户组内的用户可写 storage
、bootstrap/cache
目录。
杂项
根据应用本身的逻辑不同,涉及的 Laravel 功能也不一样。针对部分项目,你有可能还需要执行以下 Artisan 命令:
$ php artisan storage:link # 软链接 app/storage 到 public 目录,以便公开访问
$ php artisan migrate # 执行迁移
$ php artisan db:seed # 执行数据填充