nginx配置的常见陷阱及错误

不管是新老用户都可能掉进同样的陷阱里。下面我们列举了觉的问题同时也给出了解决办法。在Freenode的IRC频道#nginx里,我们经常遇到这类问题。

导言

这些常见问题,一般是因某人试图从别人的配置里直接拷贝后拿来用,并不是所有拷贝的都有问题,可惜的是,大部分都有问题。即使是Linode文档库里也存在因社区成员不去维护导致质量差的信息。

这个文档由大量NGINX社区成员创建和审查,这个特殊文档的存在也是因为这些太过来常见了并经常发生。

如果你的问题并未列明

你可能并没有找你跟你直接有关的特殊问题,也许我们确实是没有指出你经常的特殊问题。但,不要以为你来到这个页面是没有原因的,你被带到这个页面至少表示你在下面的问题里遇到过问题:)

Chmod 777

永远不要使用777。不要以为这只是一个漂亮的数字,即使在测试环境也表明你会没有线索查你正在做的事。你可以对整个路径的权限进行检查,可以考虑你正在做的事实。

要检查路径的权限,你可以:

namei -om /path/to/check
Location 里的 root 配置

劣:

server {
    server_name www.example.com;
    location / {
        root /var/www/nginx-default/;
        # [...]
      }
    location /foo {
        root /var/www/nginx-default/;
        # [...]
    }
    location /bar {
        root /var/www/nginx-default/;
        # [...]
    }
}

可以工作。每个location块里都加上root指令没有错,也能很好的工作。那会有什么问题呢?如果某一个location块你路径写错了,将导致没有根目录。来看下什么是优的配置。

优:

server {
    server_name www.example.com;
    root /var/www/nginx-default/;
    location / {
        # [...]
    }
    location /foo {
        # [...]
    }
    location /bar {
        # [...]
    }
}
多个Index指令

劣:

http {
    index index.php index.htm index.html;
    server {
        server_name www.example.com;
        location / {
            index index.php index.htm index.html;
            # [...]
        }
    }
    server {
        server_name example.com;
        location / {
            index index.php index.htm index.html;
            # [...]
        }
        location /foo {
            index index.php;
            # [...]
        }
    }
}

为何重复那么多不必要的行?其实只要简单的使用index指令一次,只要在http{}里使用一次,下面的区块将自动继承。

优:

http {
    index index.php index.htm index.html;
    server {
        server_name www.example.com;
        location / {
            # [...]
        }
    }
    server {
        server_name example.com;
        location / {
            # [...]
        }
        location /foo {
            # [...]
        }
    }
}
使用if指令

只有少数一些讨论if的文章,有篇叫 if是魔鬼 的你一定要看,下面举些列子说明为何if如此坏。

server_name指令与if

劣:

server {
    server_name example.com *.example.com;
        if ($host ~* ^www\.(.+)) {
            set $raw_domain $1;
            rewrite ^/(.*)$ $raw_domain/$1 permanent;
        }
        # [...]
    }
}

这里实际上有三个问题。首先看看if,也是我们现在要关注的,为何是劣的?你读过这篇文章 If是魔鬼 吗?当nginx接收到一个请求不管子域名是什么,即使是www.example.com或example.com,if指令也是每次都要调用,因为NGINX需要每次对请求头Host做处理,这特别没有效率,你要千万注意避免它。可以替换为两个server区块,如下面的列子:

优:

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

这种配置也可以使配置更好阅读,这种方法减少了NGINX的处理需求。我们去除了谬误的if,同时我们使用了$schema避免了硬编码URI,如http或https。

检查文件是否存在(if)

使用if来判断一个文件是否存在太可怕了。也就是说如果你有最新版的NGINx,使用tryfiles指令将更加容易。

劣:

server {
    root /var/www/example.com;
    location / {
        if (!-f $request_filename) {
            break;
        }
    }
}
优:
server {
    root /var/www/example.com;
    location / {
        try_files $uri $uri/ /index.html;
    }
}

我们只是修改了判断文件是否存在但又不使用if指令,使用tryfiles表示可以测试一系列文件,如果$uri不存在,再试$uri/,如果还不存在,就使用默认位置(index.html)。

 

在这个列子,如果$uri存在就使用它,如果不存在,再判断$uri/目录是否存在,如果不存在就使用index.html,必须要保证最后一个检测的文件存在。很简单吧!下面是另一个例子去掉if指令。

WEB应用的前端控制模式

"前端控制模式"-Front controller patterm在php开源界非常流行,但大都使用的比较复杂,如Drupal、jammla等,只要像这样:

try_files $uri $uri/ /index.php?q=$uri&$args;

注意-参数根据你使用的开源软件不同而不同。如:

  • "q"是Drupal,Joomla,Wordpress的参数
  • "page"是CMS Make Simple的参数

有些软件甚至不需要查询参数而是用REQUEST_URI参数,如,Wordpress支持这个:

try_files $uri $uri/ /index.php;

如果你不关心检查目录,只要去掉$uri/。

当然,你可能遇到些特殊情况,需要更复杂的配置,但对一般站点,这些就够了。

传递未受控的请求到PHP

很多NGINX+PHP的配置会传递所有以.php结尾的请求给php,但这里会出现一个严重的安全问题,可能导致精心构造的代码被执行。

这类问题看起来如:

location ~* \.php$ {
    fastcgi_pass backend;
    # [...]
}

这里,每个以.php结尾的请求将传递给FastCGI后端。这会导致一个问题,PHP的默认配置对于找不到的文件,会对整个请求文件路径猜测哪个部分需要执行。

举例,如果请求是/forum/avatar/1232.jpg/file.php,文件并不存在,但/forum/avatar/1232.jpg存在,则php也会执行1232.jpg,如果1232.jpg包含php代码,也会被执行。

避免执行的选项有:

  • 在php.ini设置cgi.fixpathinfo=0.这会导致php不尝试字面上的路径,如果文件没找到就停止处理。
  • 保证NGINX只传递特定文件给PHP
location ~* (file_a|file_b|file_c)\.php$ {
    fastcgi_pass backend;
    # [...]
}
  • 指定用户上传的目录不可以执行php
location /uploaddir {
    location ~ \.php$ {return 403;}
    # [...]
}
  • 使用tryfles指令过滤有问题的条件
location ~* \.php$ {
    try_files $uri =404;
    fastcgi_pass backend;
    # [...]
}
  • 使用嵌套location过滤
location ~* \.php$ {
    location ~ \..*/.*\.php$ {return 404;}
    fastcgi_pass backend;
    # [...]
}
脚本文件中的FastCGI路径

太多例子说用绝对路径来指定路径的错误做法。通常见于php配置块。当你从svn中安装NGINX,通常会有include fastcgiparams;在你的配置中,目录一般在/etc/nginx。

优:

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;

劣:

fastcgi_param  SCRIPT_FILENAME    /var/www/yoursite.com/$fastcgi_script_name;

$docmentroot在哪设的?通常是在你的server块里,不在?看看上面的第一个坑。

费力的Rewrites

在这不要犯糊,很容易被正则表达式搞蒙,事实上,很简单,只要努力做到足够简单就行。

劣:

rewrite ^/(.*)$ http://example.com/$1 permanent;

优:

rewrite ^ http://example.com$request_uri? permanent;

更优:

return 301 http://example.com$request_uri;

看看上面的例子,第一个规则是获取全部url然后减fcfu最一个反斜杆,事实上使用内置变量$request_uri可以更简单。

Rewrite丢失的http://

非常简单,rewrites规则都是相对路径,除非你告诉NGINX不是,使用rewrite的绝对路径也很简单,添加一个schema。

劣:

rewrite ^ example.com permanent;

优:

rewrite ^ http://example.com permanent;

上面的例子中只是添加了http://,简单而有效。

代理 所有内容

劣:

server {
    server_name _;
    root /var/www/site;
    location / {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/tmp/phpcgi.socket;
    }
}

恶心。这个例子中,什么内容都代理给了PHP,为什么?Apache也许用来替代,但没必要。try_files指令神奇的地方是:它按一定的顺序尝试使用文件。NGINX可以首先尝试静态文件,如果没有,继续尝试。意思是PHP不一定要处理所有文件。速度将更快!例如你有个1M的图片比较下通过用PHP来处理和用服务器直接处理的速度。看看优化后的方案:

server {
    server_name _;
    root /var/www/site;
    location / {
        try_files $uri $uri/ @proxy;
    }
    location @proxy {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/tmp/phpcgi.socket;
    }
}

同样也是好的方案

server {
    server_name _;
    root /var/www/site;
    location / {
        try_files $uri $uri/ /index.php;
    }
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/tmp/phpcgi.socket;
    }
}

很容易不是吗?如果请求的URI存在,NGINX可以直接处理,如果不存在,如果是个目录也可以处理,如果还不是,再传递给代理。仅当NGINX不能处理时才传递给代理。

考虑下你的多少内容是静态的(图片、css、javascript等),可能能节省下大量的消耗。

缓存问题

浏览器缓存的问题。你的配置也许很完善但也有撞墙的时候。出现问题的原因就是浏览器缓存。当下载页面时,浏览器会做缓存,同时也保存了文件怎么更新,如果你在测试 types{}指令,你可能需要通过以下方法来清缓存

  1. 在firefox使用ctrl+shift+delete,清掉缓存;
  2. 使用curl查看文件是否更新

VirtualBox虚拟机

如果nginx工作不正常可能是因为sendfile指令,只要注释掉再试下。

丢失的HTTP头信息

如果你没有设置underscores_in_headers on;指令,NGINX将把包括下划线的头信息丢掉(依据http标准),这也是为了一种保护机制,防止异常的头信息与CGI变量冲突。

没有使用标准的Document Root 位置信息

所有系统都有些不能使用的目录,如/和root,永远不要设置成document root目录。一般都是放在/var/www或/srv或/usr/share/www/。

使用默认的Document Root

不要使用系统安装包默认的DocumentRoot目录,因为软件升级或重新安装时,有可能修改该目录,如果你的业务刚好在使用这个目录,oops,目录有可能被删除并安装它的默认文件。小心。

使用主机名来解析地址

劣:

upstream {
    server http://someserver;
}

优:

server {
    listen myhostname:80;
    # [...]
}

永远不要在listen指令中使用主机名。虽然可以工作,但会带来很多问题,一个是系统启动或service启动时hostname不一定能解析,这将导致nginx不能绑定到指令的tcp socket并启动失败。

安全的做法是指令ip地址来代替主机名。避免了域名解析的成本。同理,在upstream也一样,尽量避免使用主机名。

优:

upstream {
    server http://10.48.41.12;
}

注:多虚拟主机名时还是避免不了。

HTTPS使用SSLv3

SSLv3因为有安全风险,建议不要使用,而用TLS代替。

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

翻译 朱淦<350050183@qq.com> 2016.7.20

转载于:https://my.oschina.net/swingcoder/blog/715230

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于nginx配置常见错误解决方法,我可以给您一些简单的介绍和建议。 首先,nginx作为一个开源的高性能Web服务器和反向代理服务器,其配置文件的语法非常简单,易于学习和使用。一般来说,nginx配置文件主要包含以下几个部分: 1. 全局块:主要是一些全局参数的设置,比如worker_processes、pid、error_log等。 2. events块:主要是一些与事件相关的参数设置,比如worker_connections等。 3. http块:主要是配置http协议相关的参数,比如http服务器、虚拟主机、upstream负载均衡等。 4. server块:主要是配置http服务器相关的参数,比如监听端口、域名、SSL证书等。 当然,nginx配置还可以包括一些额外的模块配置,比如gzip、fastcgi等等。 关于常见错误解决方法,以下是一些可能会遇到的问题和解决方法: 1. nginx启动失败:这个问题可能是由于配置文件语法错误、端口占用等原因导致的。解决方法可以通过查看日志、检查配置文件、查看端口占用情况等。 2. 403 Forbidden错误:这个错误通常是由于权限不足导致的。解决方法可以通过修改文件或目录的权限、检查SELinux等。 3. 404 Not Found错误:这个错误通常是由于资源不存在导致的。解决方法可以通过检查文件路径、检查文件权限、检查文件是否存在等。 4. 502 Bad Gateway错误:这个错误通常是由于后端服务器连接失败导致的。解决方法可以通过检查后端服务器是否正常运行、检查网络连接等。 总之,nginx作为一个高性能的Web服务器和反向代理服务器,其配置错误处理都需要一定的经验和技巧,建议您多练习和学习,掌握一些常用的技巧和方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值