1. 环境介绍

CentOS、Nginx、MySQL、PHP,由 LNMP 一键脚本安装,具体参见 lnmp.org

2. 问题说明

ThinkPHP5 在经过重构之后,入口文件改为了 /public/index.php。在添加站点后(lnmp vhost add),访问站点就需要加个二级目录,如 https://example.com/public

如何在将 ThinkPHP5 部署在 LNMP 环境中时,去掉 public 及 index.php ,让 url 变得更加友好。下面是解决方案。

3. 解决办法

3.1 准备工作

由于 LNMP 是用于生产环境的,默认关闭了 PHP 的错误提示,这就导致如果页面出错会直接返回服务器 500 错误,而不会显示具体错误信息。所以我们需要修改下,打开 /usr/local/php/conf 下的 php.ini 文件,搜索 display_errors ,把 Off 修改为 On ,这样出错时,页面会提示具体错误信息。

3.2 修改站点目录

打开 /usr/local/nginx/conf/vhost/example.com.conf 文件,

vim /usr/local/nginx/conf/vhost/example.com.conf

将内容

root /home/wwwroot/example.com;

修改为:

root /home/wwwroot/example.com/public;

修改之后问题来了,由于 lnmp 环境考虑到虚拟站点各自的访问目录权限问题,在 /usr/local/nginx/conf/fastcgi.conf 里面有如下配置:

fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/";

每个站点的访问权限就限制在了 $document_root 里了,上面我们修改了 example.com.conf 文件,将 root 的路径加了 /public,所以限制了只能访问 public 目录下的文件,而 ThinkPHP 需要加载 public 同级目录下的 application 等目录下的文件,这样就有问题了。

现在要做的是:

既需要 root /home/wwwroot/example.com/public; 这个配置,又要让虚拟站点有 /home/wwwroot/example.com 目录的访问权限。

那么可以修改 /usr/local/nginx/conf/fastcig.conf 配置文件:

在内容

fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/";

后面添加一行:

fastcgi_param PHP_ADMIN_VALUE $basedir if_not_empty;

$basedir 变量可以在 /usr/local/nginx/conf/vhost/example.com.conf 配置文件里面的 include enable-php.conf 前赋值就行了:

set $basedir "open_basedir=/home/wwwroot/example.com/:/tmp/:/proc/";

这样,既满足了部署要求,又不影响其他一般站点的使用,因为 $basedir 可以根据站点需要自行设定。

3.3 伪静态规则

可以在 set $basedir 后面添加或者引入 ThinkPHP5 的伪静态规则。

set $basedir "open_basedir=/home/wwwroot/example.com/:/tmp/:/proc/";
include thinkphp.conf

伪静态规则如下:

location / {
    if (!-e $request_filename) {
        rewrite ^/(.*)$ /index.php?s=/$1 last;
        break;
    }
}

最后,别忘了把 php.ini 文件里的 display_errors 的值由 On 改回 Off

4. HTTP 重定向到 HTTPS

添加 301 将HTTP 重定向到 HTTPS。

server
    {
        listen 80;
        #listen [::]:80;
        server_name www.example.com;
        return 301 https://$server_name$request_uri;
    }

最后要注意一点,LNMP 采用自动化颁发和续期 HTTPS 证书策略,在颁发证书之前会验证服务器的有效性,通过 HTTP 访问网站根目录下的 .well-known 目录下的验证文件,请求地址形如 https://domain.com/.well-known/xxx。所以如果是像 ThinkPHP、Laravel 这样 web 目录不是根目录的,需要修改域名对应的配置文件,确保网站根目录对应到域名,不然可能由于无法获取到验证文件的内容,而导致证书生成失败。另外域名对应的 SSL 证书配置文件里的根目录也要和实际目录一致,以确保证书续期成功。