LEMP/LNMP 环境搭建(Nginx1.10 + PHP7)

更多文档请浏览官方文档和Wiki,这个很重要,其实文档里已经说的很清楚了,会遇到的Bug往往在回复里也有。


## 1. 更换国内更新源

Ubuntu 14.04 更新源: https://m.oschina.net/blog/224661

2. 安装Nginx

想要安装最新版本,或添加模块,请参考这里:http://nginx.org/en/linux_packages.html

  1. 下载 nginx_signing.key: wget http://nginx.org/keys/nginx_signing.key
  2. 添加下面代码到 /etc/apt/sources.list 的末尾:

    deb http://nginx.org/packages/ubuntu/ trusty nginx
    deb-src http://nginx.org/packages/ubuntu/ trusty nginx

最后:

sudo apt-get update
sudo apt-get install nginx

安装成功后,应该可以在命令行这样:

  • sudo nginx -s stop — fast shutdown
  • sudo nginx -s quit — graceful shutdown
  • sudo nginx -s reload — reloading the configuration file
  • sudo nginx -s reopen — reopening the log files

3. 安装PHP 7.0.6

可以参考:http://php.net/manual/zh/install.unix.nginx.php

先下载需要的版本的 php 包,然后解压等等:

tar zxf php-7.0.6.tar.gz
cd php-7.0.6
./configure --enable-fpm --with-mysql
make
make test
sudo make install

 在运行 ./configure 的过程中我遇到了若干错误信息:

  • Error:configure: error: xml2-config not found. Please check your libxml2 installation. 我开始安装了下 libxml2 ,发现问题还是没解决,在 stackoverflow 找到了答案:链接

    • Solution:安装 libxml2 和 libxml2-dev 即可:sudo apt-get install libxml2 libxml2-dev
  • Error:configure: WARNING: unrecognized options: --with-mysql

    • Solution1: --with-pdo-mysql instead of --with-mysql
    • Solution2: --with-mysqli instead of --with-mysql

make install log:

Wrote PEAR system config file at: /usr/local/etc/pear.conf
You may want to add: /usr/local/lib/php to your php.ini include_path
/home/vagrant/php-7.0.6/build/shtool install -c ext/phar/phar.phar /usr/local/bin
ln -s -f phar.phar /usr/local/bin/phar
Installing PDO headers:           /usr/local/include/php/ext/pdo/

运行:

sudo /home/vagrant/php-7.0.6/build/shtool install -c ext/phar/phar.phar /usr/local/bin
sudo ln -s -f phar.phar /usr/local/bin/phar

创建配置文件,并将其复制到正确的位置:

cp php.ini-development /usr/local/php/php.ini
cp /usr/local/etc/php-fpm.conf.default /usr/local/etc/php-fpm.conf
cp sapi/fpm/php-fpm /usr/local/bin

需要着重提醒的是,如果文件不存在,则阻止 Nginx 将请求发送到后端的 PHP-FPM 模块, 以避免遭受恶意脚本注入的攻击。

/usr/local/php/php.ini 文件中的配置项 cgi.fix_pathinfo 设置为 0

在启动服务之前,需要修改 php-fpm.conf 配置文件,确保 php-fpm 模块使用 www-data 用户和 www-data 用户组的身份运行。

vim /usr/local/etc/php-fpm.conf

修改:

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
user = www-data
group = www-data

需要注意的是:我在这个文件里没找到 user的设置,莫非官方文档还没有针对PHP7?,我在 /usr/local/etc/php-fpm.d/www.conf.default 里找到了 user 的选项,默认是 nobody,你可以参照这里:http://php.net/manual/zh/install.fpm.install.php :
编译 PHP 时需要 --enable-fpm 配置选项来激活 FPM 支持。

以下为 FPM 编译的具体配置参数(全部为可选参数):

  • --with-fpm-user - 设置 FPM 运行的用户身份(默认 - nobody)
  • --with-fpm-group - 设置 FPM 运行时的用户组(默认 - nobody)
  • --with-fpm-systemd - 启用 systemd 集成 (默认 - no)
  • --with-fpm-acl - 使用POSIX 访问控制列表 (默认 - no) 5.6.5版本起有效

PHP核心配置列表

其实可以把之前的配置命令改为

./configure --enable-fpm --with-mysqli --with-fpm-user=www-data --with-fpm-group=www-data

来运行就不用在修改配置文件那么麻烦了。

然后启动 php-fpm 服务:

/usr/local/bin/php-fpm

这里会遇到坑:

$ sudo /usr/local/bin/php-fpm
[12-May-2016 04:39:05] ERROR: Unable to globalize '/usr/local/NONE/etc/php-fpm.d/*.conf' (ret=2) from /usr/local/etc/php-fpm.conf at line 125.
[12-May-2016 04:39:05] ERROR: failed to load configuration file '/usr/local/etc/php-fpm.conf'
[12-May-2016 04:39:05] ERROR: FPM initialization failed

修改 /usr/local/etc/php-fpm.conf 最后一行:

/NONE/etc/php-fpm.d/*.conf

 为
etc/php-fpm.d/*.conf

然后拷贝默认文件为 *.conf 文件:

cp /usr/local/etc/php-fpm.d/www.conf.default /usr/local/etc/php-fpm.d/www.conf

并修改里面的 user 和 group:

user = www-data
group = www-data

现在应该好了,启动 php-fpm 服务:

/usr/local/bin/php-fpm

参考文献:
http://php.net/manual/zh/install.unix.nginx.php
http://nginx.org/en/docs/beginners_guide.html
http://nginx.org/en/linux_packages.html
https://github.com/owncloud/documentation/wiki/NGINX-Configuration

推荐工具 ee(如果你不能翻墙就算了,去用oneinstack吧,也是很好的工具):https://github.com/EasyEngine/easyengine

4. 配置 Nginx 使其支持 PHP 应用:

我的本地测试域名用 yum.app ,代码放在虚拟机的 /var/www/owncloud 。成功搞定应该是可以通过浏览器访问 http://yum.app 直接访问到我们的OwnCloud 的。

sudo vim /etc/nginx/conf.d/default.conf

修改默认的 location 块,使其支持 .php 文件:

location / {
    root   html;
    index  index.php index.html index.htm;
}

下一步配置来保证对于 .php 文件的请求将被传送到后端的 PHP-FPM 模块, 取消默认的 PHP 配置块的注释,并修改为下面的内容:

location ~* \.php$ {
    fastcgi_index   index.php;
    fastcgi_pass    127.0.0.1:9000;
    fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;
    include         fastcgi_params;
}

写下测试文件:

sudo touch /usr/share/nginx/html/index.php
sudo vim /usr/share/nginx/html/index.php

index.php:

<?php
phpinfo();

然后访问 http://yum.app ,报错:File Not Found. 这里可以初步判断也许是php解析有问题,在相同位置建一个html文件,访问,发现正常。确诊是php解析问题。

File Not Found 解决和分析

打开刚才的配置文件:

sudo vim /etc/nginx/conf.d/default.conf

将原有配置修改为:

location ~ \.php$ {
    root           html;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /usr/share/nginx/html/$fastcgi_script_name;
    include        fastcgi_params;
}

没错,是这一行:

fastcgi_param  SCRIPT_FILENAME  /usr/share/nginx/html/$fastcgi_script_name;

我们把 $document_root 修改为 /usr/share/nginx/html/,然后重启nginx,会发现问题解决了。

但是这样并不算很科学,我认为放弃对 $document_root 的使用不科学,所以,这样,其实,如果我们把 root  html; 写到解析 / 或 php 里并不科学,更好的做法是把这些基本不变的参数写到 /etc/nginx/conf.d/default.conf 顶上去:

server {
    listen       80;
    server_name  localhost;
    root        /var/www;
    index       index.html index.htm index.php;
......

然后,修改 php 的解析为:

location ~ \.php$ {
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
}

重启nginx,一些都好了,至此,File Not Found 问题分析解决完毕。

5. Nginx的”虚拟目录”

参考:https://www.nginx.com/resources/wiki/start/topics/examples/server_blocks/
按照官方的说法,Nginx是没有虚拟目录的概念的,它有的是 Server Blocks。

其实我没必要做这一部分,毕竟我没打算让服务器上运行多个网站,它只运行 owncloud, 但是既然都走到这步了,那就实现了吧。

打开 /etc/nginx/nginx.conf 配置文件可以看到这样一段:

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

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

而这一行 include /etc/nginx/conf.d/*.conf; 就是插入了所有 conf.d 目录下的配置文件,这个做法好——解耦很重要。

根据官方给的样例:

server {
  # Replace this port with the right one for your requirements
  listen 80 default_server;  #could also be 1.2.3.4:80

  # Multiple hostnames separated by spaces.  Replace these as well.
  server_name star.yourdomain.com *.yourdomain.com; # Alternately: _

  root /PATH/TO/WEBROOT;

  error_page 404 errors/404.html;
  access_log logs/star.yourdomain.com.access.log;

  index index.php index.html index.htm;

  # static file 404's aren't logged and expires header is set to maximum age
  location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
    access_log off;
    expires max;
  }

  location ~ \.php$ {
    include fastcgi_params;
    fastcgi_intercept_errors on;
    # By all means use a different server for the fcgi processes if you need to
    fastcgi_pass   127.0.0.1:YOURFCGIPORTHERE;
  }

  location ~ /\.ht {
    deny  all;
  }
}

我们把这个样例稍作修改,放到 conf.d 目录下即可,例如下面的 /etc/nginx/conf.d/demo.conf

server {
  # Replace this port with the right one for your requirements
  listen 80 default_server;  #could also be 1.2.3.4:80

  # Multiple hostnames separated by spaces.  Replace these as well.
  server_name star.demo.com *.demo.com; # Alternately: _

  root /var/www/demo;

  error_page 404 errors/404.html;
  # access_log logs/star.yourdomain.com.access.log;

  index index.php index.html index.htm;

  # static file 404's aren't logged and expires header is set to maximum age
  location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
    access_log off;
    expires max;
  }

  location ~ \.php$ {
    include fastcgi_params;
    fastcgi_intercept_errors on;
    # By all means use a different server for the fcgi processes if you need to
    fastcgi_pass   127.0.0.1:9000;
  }

  location ~ /\.ht {
    deny  all;
  }
}

然后重启Nginx即可. Over!