浅析 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-OptionsX-XSS-ProtectionX-Content-Type-Options 可参考 这篇文章,自认为作者讲得还不错,通俗易懂并且是中文。

关于 .well-known 目录的详细解释,可参考 这篇问答(英文)。

我感谢自己平凡,敢爱敢恨没负担。
我感谢自己不凡,可爱可恨都包揽。

附言 1  ·  4周前

感谢 @soli,请大家注意这条留言:博客:浅析 Laravel 官方文档推荐的 Nginx 配置

本帖由系统于 3个月前 自动加精
Wi1dcard
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 25
soli

非常不错的文章。我也从中选了几条我没有但非常有用的配置添加到我的配置中了。

值得注意的是,文中给的关于 X-Frame-Options那篇文章中,第一条 Strict-Transport-Security,使用的时候要谨慎一些。即使用,也不要把 max-age 设置的太大。否则,万一配置有误或者需要修改配置,那你将无法让那些已经保存过 HSTS 的用户使用新的配置。

举个例子,比如你把 max-age 设置成一年。但半年的时候你的 HTTPS 证书到期了。由于某种原因你不想续费 HTTPS 证书了。所以,你修改配置文件,删除 Strict-Transport-Security 等配置,重新启用 HTTP 。
但那些已经保存了 HSTS 的用户在接下来的半年内,还是会直接访问你的 https 站点,并得到证书过期的红色警告,浏览器拒绝打开你的网站。即使用户手动输入 http 都不行。

4周前 评论

@晨读秀 正如 @molaifeng 所说,后者相比前者无需经过 TCP/IP。理想状态下,只有应用层的内存数据拷贝,所以相对来说资源占用小,但速度提升基本可以忽略(太小)。你可以 Google tcp/ip socket vs unix socket 来找到更多信息。

另外,Unix Socket 由于并不属于「网络通信协议」,而是一种「进程通讯机制」,因此有个不太常见的局限:无法跨机器使用。即使通过 NFS 等协议共享 Unix Socket 文件也无效。

3个月前 评论

@overfalse

try_files 指令可让 Nginx 按照特定的顺序查找文件。按照以下配置为例:

try_files $uri $uri/ /index.php?$query_string;

假设你正在访问 /api/status?query=example

  1. Nginx 会首先尝试 $uri 是否存在(这是个 Nginx 内置变量,表示请求 URI),也就是 /网站根目录/api/status
  2. 如果 $uri 不存在,则尝试 $uri/,也就是 /网站根目录/api/status/
  3. 如果 $uri/ 也不存在,则最终尝试 /index.php?$query_string$query_string 也是 Nginx 的内置变量,表示 URI 内的查询字符串),也就是 /网站根目录/index.php?query=example
  4. 按照 Laravel 的目录结构,/网站根目录/index.php 是必定存在的,但如果该文件确实不存在,Nginx 将会返回 404。

需要注意的是,严格地说,/api/status/api/status/ 这两个 URI 并不指向同一个资源。同理,https://www.google.comhttps://www.google.com/ 也不等效。有兴趣可 Google trailing slash in uri 之类的关键词获取更多细节。

PS,ID 很不错😂。下次我改个 overnull

2个月前 评论
largezhou

虽然这是一篇讲解 Nginx 配置的文章,但是却让我突然弄清楚了正则表达式中的 零宽断言,,,以前一直都看的云里雾里,就没管了,反正也很少用,,,

3个月前 评论

@largezhou 哈哈,是的,最后的 /\.(?!well-known).* 便是断言,即仅匹配但不捕获,可以理解为一个判断条件。断言有很多种,这一种称作 否定前瞻断言(这是个不标准、不统一的称呼),也叫 Negative Lookahead(比较通用的叫法)。

3个月前 评论
晨读秀

您好,请教一下

# 配置 FastCGI 服务地址,可以为 IP:端口,也可以为 Unix socket。
  fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;

这里讲到的 IP:端口 和 Unix socket 的使用有什么区别吗? 或者是利弊

3个月前 评论

@晨读秀 前者走的是 TCP/IP 协议栈,后者走的是 IPC,前者稳定些,具体可参考 PHP-FPM 与 Nginx 的通信机制总结

3个月前 评论

@晨读秀 正如 @molaifeng 所说,后者相比前者无需经过 TCP/IP。理想状态下,只有应用层的内存数据拷贝,所以相对来说资源占用小,但速度提升基本可以忽略(太小)。你可以 Google tcp/ip socket vs unix socket 来找到更多信息。

另外,Unix Socket 由于并不属于「网络通信协议」,而是一种「进程通讯机制」,因此有个不太常见的局限:无法跨机器使用。即使通过 NFS 等协议共享 Unix Socket 文件也无效。

3个月前 评论
晨读秀

@Wi1dcard @molaifeng

多谢解惑! :pray:

3个月前 评论
晨读秀

您好,希望您有时间可以添加上 HTTPS 的配置。 :pray: @Wi1dcard

2个月前 评论

@晨读秀 好的,没问题;已经列入计划中。

2个月前 评论
晨读秀

@Wi1dcard 多谢。 :pray:

2个月前 评论
lmaster

学习零宽断言.well-known
关于 tcp/ip socket vs unix socket 的比较,大多数都提的是 unix socket 性能好,但高并发有瓶颈,为什么那?

2个月前 评论

@lmaster 关于 Unix Socket 的性能瓶颈还真没有听说过,给个链接?

2个月前 评论
lmaster

@Wi1dcard PHP-FPM 与 Nginx 的通信机制总结 ,百度上类似PHP-FPM 与 Nginx 的通信标题的博文里面多多少少都说unix socket高并发有瓶颈、不稳定,我也是对这个感觉很奇怪

2个月前 评论

@lmaster 并不是 Unix Socket 不稳定,我猜是没有做好内核参数调优;可供参考的配置很多,例如:https://gist.github.com/voluntas/bc54c60aa...

百度的文章太浅显,容易误人子弟;搜娱乐还行,技术向还是用谷歌吧。

2个月前 评论

try_files $uri $uri/ /index.php?$query_string; 这段啥意思呢?

2个月前 评论

@overfalse

try_files 指令可让 Nginx 按照特定的顺序查找文件。按照以下配置为例:

try_files $uri $uri/ /index.php?$query_string;

假设你正在访问 /api/status?query=example

  1. Nginx 会首先尝试 $uri 是否存在(这是个 Nginx 内置变量,表示请求 URI),也就是 /网站根目录/api/status
  2. 如果 $uri 不存在,则尝试 $uri/,也就是 /网站根目录/api/status/
  3. 如果 $uri/ 也不存在,则最终尝试 /index.php?$query_string$query_string 也是 Nginx 的内置变量,表示 URI 内的查询字符串),也就是 /网站根目录/index.php?query=example
  4. 按照 Laravel 的目录结构,/网站根目录/index.php 是必定存在的,但如果该文件确实不存在,Nginx 将会返回 404。

需要注意的是,严格地说,/api/status/api/status/ 这两个 URI 并不指向同一个资源。同理,https://www.google.comhttps://www.google.com/ 也不等效。有兴趣可 Google trailing slash in uri 之类的关键词获取更多细节。

PS,ID 很不错😂。下次我改个 overnull

2个月前 评论

讲的非常好,特别是 Wi1dcard 回答问题真的是我见过最仔细的! 感谢

1个月前 评论
soli

非常不错的文章。我也从中选了几条我没有但非常有用的配置添加到我的配置中了。

值得注意的是,文中给的关于 X-Frame-Options那篇文章中,第一条 Strict-Transport-Security,使用的时候要谨慎一些。即使用,也不要把 max-age 设置的太大。否则,万一配置有误或者需要修改配置,那你将无法让那些已经保存过 HSTS 的用户使用新的配置。

举个例子,比如你把 max-age 设置成一年。但半年的时候你的 HTTPS 证书到期了。由于某种原因你不想续费 HTTPS 证书了。所以,你修改配置文件,删除 Strict-Transport-Security 等配置,重新启用 HTTP 。
但那些已经保存了 HSTS 的用户在接下来的半年内,还是会直接访问你的 https 站点,并得到证书过期的红色警告,浏览器拒绝打开你的网站。即使用户手动输入 http 都不行。

4周前 评论
聪聆

配置信息不错,但是现在基本上都是https了,可以借鉴其中几条

3周前 评论

@聪聆 HTTPS 和官方推荐的配置项不冲突。

3周前 评论
loveinalife

@晨读秀 两种配置分别对应着nginx和php-fpm之间的两种通信方式。

1.unix socket通信

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

2. tcp socket通信

fastcgi_pass   127.0.0.1:9000;

3.区别

由于 Unix socket 不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。所以其效率比 tcp socket 的方式要高,可减少不必要的 tcp 开销。不过,unix socket 高并发时不稳定,连接数爆发时,会产生大量的长时缓存,在没有面向连接协议的支撑下,大数据包可能会直接出错不返回异常。而 tcp 这样的面向连接的协议,可以更好的保证通信的正确性和完整性。

1周前 评论
GhostCoder

支持支持

1周前 评论

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!
未填写
文章
55
粉丝
340
喜欢
878
收藏
615
排名:38
访问:6.96 万+
私信
所有博文