浅析 Laravel 官方文档推荐的 Nginx 配置
以 Laravel 5.8 文档 为准,浅析 Nginx 配置。可作为 轻松部署 Laravel 应用 的拓展阅读。
方便起见,我在注释中使用 [] 包裹引用配置中的值。
server {
# 监听 HTTP 协议默认的 [80] 端口。
listen 80;
# 绑定主机名 [example.com]。
server_name example.com;
# 服务器站点根目录 [/example.com/public]。
root /example.com/public;
# 添加几条有关安全的响应头;与 Google+ 的配置类似,详情参见文末。
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;
}
}
关于 X-Frame-Options、X-XSS-Protection 和 X-Content-Type-Options 可参考 这篇文章,自认为作者讲得还不错,通俗易懂并且是中文。
关于 .well-known 目录的详细解释,可参考 这篇问答(英文)。
本作品采用《CC 协议》,转载必须注明作者和本文链接
感谢 @soli,请大家注意这条留言:博客:浅析 Laravel 官方文档推荐的 Nginx 配置。
本帖由系统于 6年前 自动加精
关于 LearnKu
高认可度评论:
非常不错的文章。我也从中选了几条我没有但非常有用的配置添加到我的配置中了。
值得注意的是,文中给的关于
X-Frame-Options的那篇文章中,第一条Strict-Transport-Security,使用的时候要谨慎一些。即使用,也不要把max-age设置的太大。否则,万一配置有误或者需要修改配置,那你将无法让那些已经保存过HSTS的用户使用新的配置。举个例子,比如你把
max-age设置成一年。但半年的时候你的 HTTPS 证书到期了。由于某种原因你不想续费 HTTPS 证书了。所以,你修改配置文件,删除Strict-Transport-Security等配置,重新启用 HTTP 。但那些已经保存了
HSTS的用户在接下来的半年内,还是会直接访问你的https站点,并得到证书过期的红色警告,浏览器拒绝打开你的网站。即使用户手动输入http都不行。@overfalse
try_files指令可让 Nginx 按照特定的顺序查找文件。按照以下配置为例:假设你正在访问
/api/status?query=example:$uri是否存在(这是个 Nginx 内置变量,表示请求 URI),也就是/网站根目录/api/status。$uri不存在,则尝试$uri/,也就是/网站根目录/api/status/。$uri/也不存在,则最终尝试/index.php?$query_string($query_string也是 Nginx 的内置变量,表示 URI 内的查询字符串),也就是/网站根目录/index.php?query=example。/网站根目录/index.php是必定存在的,但如果该文件确实不存在,Nginx 将会返回 404。需要注意的是,严格地说,
/api/status与/api/status/这两个 URI 并不指向同一个资源。同理,https://www.google.com与https://www.google.com/也不等效。有兴趣可 Googletrailing slash in uri之类的关键词获取更多细节。@晨读秀 正如 @molaifeng 所说,后者相比前者无需经过 TCP/IP。理想状态下,只有应用层的内存数据拷贝,所以相对来说资源占用小,但速度提升基本可以忽略(太小)。你可以 Google
tcp/ip socket vs unix socket来找到更多信息。另外,Unix Socket 由于并不属于「网络通信协议」,而是一种「进程通讯机制」,因此有个不太常见的局限:无法跨机器使用。即使通过 NFS 等协议共享 Unix Socket 文件也无效。
虽然这是一篇讲解
Nginx配置的文章,但是却让我突然弄清楚了正则表达式中的 零宽断言,,,以前一直都看的云里雾里,就没管了,反正也很少用,,,@largezhou 哈哈,是的,最后的
/\.(?!well-known).*便是断言,即仅匹配但不捕获,可以理解为一个判断条件。断言有很多种,这一种称作否定前瞻断言(这是个不标准、不统一的称呼),也叫Negative Lookahead(比较通用的叫法)。@Wi1dcard 向大佬学习
您好,请教一下
这里讲到的 IP:端口 和 Unix socket 的使用有什么区别吗? 或者是利弊
@晨读秀 前者走的是 TCP/IP 协议栈,后者走的是 IPC,前者稳定些,具体可参考 PHP-FPM 与 Nginx 的通信机制总结
@晨读秀 正如 @molaifeng 所说,后者相比前者无需经过 TCP/IP。理想状态下,只有应用层的内存数据拷贝,所以相对来说资源占用小,但速度提升基本可以忽略(太小)。你可以 Google
tcp/ip socket vs unix socket来找到更多信息。另外,Unix Socket 由于并不属于「网络通信协议」,而是一种「进程通讯机制」,因此有个不太常见的局限:无法跨机器使用。即使通过 NFS 等协议共享 Unix Socket 文件也无效。
@Wi1dcard @molaifeng
多谢解惑! :pray:
您好,希望您有时间可以添加上 HTTPS 的配置。 :pray: @Wi1dcard
@晨读秀 好的,没问题;已经列入计划中。
@Wi1dcard 多谢。 :pray:
学习
零宽断言,.well-known关于
tcp/ip socket vs unix socket的比较,大多数都提的是unix socket性能好,但高并发有瓶颈,为什么那?@lmaster 关于 Unix Socket 的性能瓶颈还真没有听说过,给个链接?
@Wi1dcard PHP-FPM 与 Nginx 的通信机制总结 ,百度上类似
PHP-FPM 与 Nginx 的通信标题的博文里面多多少少都说unix socket高并发有瓶颈、不稳定,我也是对这个感觉很奇怪@lmaster 并不是 Unix Socket 不稳定,我猜是没有做好内核参数调优;可供参考的配置很多,例如:https://gist.github.com/voluntas/bc54c60aa...
百度的文章太浅显,容易误人子弟;搜娱乐还行,技术向还是用谷歌吧。
try_files $uri $uri/ /index.php?$query_string;这段啥意思呢?@overfalse
try_files指令可让 Nginx 按照特定的顺序查找文件。按照以下配置为例:假设你正在访问
/api/status?query=example:$uri是否存在(这是个 Nginx 内置变量,表示请求 URI),也就是/网站根目录/api/status。$uri不存在,则尝试$uri/,也就是/网站根目录/api/status/。$uri/也不存在,则最终尝试/index.php?$query_string($query_string也是 Nginx 的内置变量,表示 URI 内的查询字符串),也就是/网站根目录/index.php?query=example。/网站根目录/index.php是必定存在的,但如果该文件确实不存在,Nginx 将会返回 404。需要注意的是,严格地说,
/api/status与/api/status/这两个 URI 并不指向同一个资源。同理,https://www.google.com与https://www.google.com/也不等效。有兴趣可 Googletrailing slash in uri之类的关键词获取更多细节。@Wi1dcard 谢谢解答哇
@晨读秀 https://www.mantis.vip/posts/2018-03-24-Ng... 这个文章看了你就明白了
讲的非常好,特别是 Wi1dcard 回答问题真的是我见过最仔细的! 感谢
@MarksGui 感谢支持。
非常不错的文章。我也从中选了几条我没有但非常有用的配置添加到我的配置中了。
值得注意的是,文中给的关于
X-Frame-Options的那篇文章中,第一条Strict-Transport-Security,使用的时候要谨慎一些。即使用,也不要把max-age设置的太大。否则,万一配置有误或者需要修改配置,那你将无法让那些已经保存过HSTS的用户使用新的配置。举个例子,比如你把
max-age设置成一年。但半年的时候你的 HTTPS 证书到期了。由于某种原因你不想续费 HTTPS 证书了。所以,你修改配置文件,删除Strict-Transport-Security等配置,重新启用 HTTP 。但那些已经保存了
HSTS的用户在接下来的半年内,还是会直接访问你的https站点,并得到证书过期的红色警告,浏览器拒绝打开你的网站。即使用户手动输入http都不行。配置信息不错,但是现在基本上都是https了,可以借鉴其中几条
@聪聆 HTTPS 和官方推荐的配置项不冲突。
@晨读秀 两种配置分别对应着nginx和php-fpm之间的两种通信方式。
1.unix socket通信
2. tcp socket通信
3.区别
由于 Unix socket 不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。所以其效率比 tcp socket 的方式要高,可减少不必要的 tcp 开销。不过,unix socket 高并发时不稳定,连接数爆发时,会产生大量的长时缓存,在没有面向连接协议的支撑下,大数据包可能会直接出错不返回异常。而 tcp 这样的面向连接的协议,可以更好的保证通信的正确性和完整性。
支持支持
你好,读了你的文章,受益匪浅。 当前遇到了一个php-fpm的问题。php 版本 7.3.9 php-fpm版本 7.1.26,请求域名502。希望给写指导
@Benny 502 Bad Gateway 一般是 Nginx 无法与上游通讯,在 Nginx 和 PHP-FPM 的场景下,上游就是 FPM 进程。所以建议你:
/usr/local/etc/php/7.3/php-fpm.conf)看看监听的端口或 Unix Socket 路径是否正确。ps aux | grep fpm),且已经监听对应端口(ls <UNIX_SOCKET_PATH>/telnet localhost <PORT>)。现在遇到的问题是,访问域名502。不知道是不是FPM哪里配置出错了 。
@Benny 如果你在用 Valet 的话,建议你直接全部卸载重装。另外,
ping并不能说明问题。执行这个命令 tail -n 10 /usr/local/var/log/php-fpm.log发现 log文件一直在写入日志

@Benny

看起来有可能你安装了多个 PHP-FPM。
偶然发现 当我关了v-p-n , 就能够访问了 。不清楚为什么 ; 开着v-p-n ,执行valet share 可以访问
很可以,支持!
很好的文章,之前还点赞过,就近收藏夹吃灰了。 最近又想着看下源码,看源码之前想说在了解下laravel的nginx配置,gogo一搜索,就看到这个文章。 内容真的不错,评论下讨论也行。