nginx 504 Gateway Time-out的一些方法

从错误代码基本可以确定跟nginx本身无关,主要是提交给php-fpm的请求未能正确反馈而导致,一般情况下,提交动态请求的时候,nginx会直接把请求转交给php-fpm,而php-fpm再分配php-cgi进程来处理相关的请求,之后再依次返回,最后由nginx把结果反馈给客户端浏览器,但我这个vps目前跑的是个纯php应用内容,实际上用户所有的请求都是php请求,有的耗费时间比较久,php-cgi进程就一直都被用满,而php-fpm本身的配置文件只打开了10组php-cgi进程,这样的话在线用户稍微多的话就会导致请求无法被正常处理而出错。

大概分析出了原因,下面做就比较容易了,首先是更改php-fpm的几处配置:

把max_children由之前的10改为现在的30,这样就可以保证有充足的php-cgi进程可以被使用;
把request_terminate_timeout由之前的0s改为60s,这样php-cgi进程处理脚本的超时时间就是60秒,可以防止进程都被挂起,提高利用效率。

接着再更改nginx的几个配置项,减少FastCGI的请求次数,尽量维持buffers不变:

fastcgi_buffers由 4 64k 改为 2 256k;
fastcgi_buffer_size由 64k 改为 128K;
fastcgi_busy_buffers_size 由 128K 改为 256K;
fastcgi_temp_file_write_size 由 128K 改为 256K。

Nginx启动脚本的编写

# vi /etc/init.d/nginx 写入
#!/bin/bash
# chkconfig: - 30 21
# description: http service.
# Source Function Library
. /etc/init.d/functions

# Nginx Settings
NGINX_SBIN="/usr/local/nginx/sbin/nginx"
NGINX_CONF="/usr/local/nginx/conf/nginx.conf"
NGINX_PID="/usr/local/nginx/var/nginx.pid"

RETVAL=0
prog="Nginx"

start() {
        echo -n $"Starting $prog: "
        mkdir -p /dev/shm/nginx_temp
        daemon $NGINX_SBIN -c $NGINX_CONF
        RETVAL=$?
        echo
        return $RETVAL
}

stop() {
        echo -n $"Stopping $prog: "
        killproc -p $NGINX_PID $NGINX_SBIN -TERM
        rm -rf /dev/shm/nginx_temp
        RETVAL=$?
        echo
        return $RETVAL
}

reload(){
        echo -n $"Reloading $prog: "
        killproc -p $NGINX_PID $NGINX_SBIN -HUP
        RETVAL=$?
        echo
        return $RETVAL
}

restart(){
        stop
        start
}

configtest(){
    $NGINX_SBIN -c $NGINX_CONF -t
    return 0
}

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  reload)
        reload
        ;;
  restart)
        restart
        ;;
  configtest)
        configtest
        ;;
  *)
        echo $"Usage: $0 {start|stop|reload|restart|configtest}"
        RETVAL=1
esac

exit $RETVAL

# chmod 755 /etc/init.d/nginx

nginx限制只让某个ip访问

server
{
    listen       80;
    server_name  www.aldjflas.cn;
    access_log   /home/logs/bbs/access.log combined buffer=32k;
    error_log    /home/logs/bbs/error.log warn;
    index           index.html index.htm index.php;
    root            /data/www/wwwroot/bbs;
    allow          219.232.244.234;
    deny           all;
}

nginx 禁止通过ip访问站点

在server部分加如下代码:

server {
             listen 80 default;
             server_name  suibian.com;  #这里的域名可以乱填一个
             return 444;
     }

基于thinkphp框架开发的代码,nginx需要的配置

开发的人跟我说基于thinkphp框架开发的代码在apache下能用,在nginx下为什么用不了呢,总是提示404的错误,原来apache默认就支持thinkphp等所需的PATH_INFO,而nginx不可以,那么接下来,我们就配置一下nginx,让他支持PATH_INFO,我是这么做的:
        1,更改php.ini

           首先php.ini的配置中把

       ;cgi.fix_pathinfo=0   改为


      cgi.fix_pathinfo=1
        
         2,改nginx配置文件中php的location如下:
  
           location ~ \.php {
                fastcgi_pass unix:/dev/shm/php-fcgi.sock;
                fastcgi_index index.php;
                set $path_info "";
                set $real_script_name $fastcgi_script_name;
                if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
                set $real_script_name $1;
                set $path_info $2;
                }
               fastcgi_param SCRIPT_FILENAME /data/www/wwwroot$real_script_name;
               fastcgi_param SCRIPT_NAME $real_script_name;
               fastcgi_param PATH_INFO $path_info;
               include  /usr/local/nginx/conf/fastcgi_params;
               }
      以前是这样的:
         location ~ \.php$ {
             include fastcgi_params;
             fastcgi_pass  unix:/tmp/php-fcgi.sock;
             fastcgi_index index.php;
             fastcgi_param SCRIPT_FILENAME /data/www/wwwroot$fastcgi_script_name;

nginx实现动静态负载均衡

具体请看帖子
http://mylinux.5d6d.com/viewthre ... mp;fromuid=1#pid526

nginx文件类型错误解析漏洞

漏洞介绍:nginx是一款高性能的web服务器,使用非常广泛,其不仅经常被用作反向代理,也可以非常好的支持PHP的运行。80sec发现其中存在一个较为严重的安全问题,默认情况下可能导致服务器错误的将任何类型的文件以PHP的方式进行解析,这将导致严重的安全问题,使得恶意的攻击者可能攻陷支持php的nginx服务器。


漏洞分析:nginx默认以cgi的方式支持php的运行,譬如在配置文件当中可以以


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

的方式支持对php的解析,location对请求进行选择的时候会使用URI环境变量进行选择,其中传递到后端Fastcgi的关键变量SCRIPT_FILENAME由nginx生成的$fastcgi_script_name决定,而通过分析可以看到$fastcgi_script_name是直接由URI环境变量控制的,这里就是产生问题的点。而为了较好的支持PATH_INFO的提取,在PHP的配置选项里存在cgi.fix_pathinfo选项,其目的是为了从SCRIPT_FILENAME里取出真正的脚本名。
那么假设存在一个http://www.80sec.com/80sec.jpg我们以如下的方式去访问

http://www.80sec.com/80sec.jpg/80sec.php

将会得到一个URI

/80sec.jpg/80sec.php

经过location指令,该请求将会交给后端的fastcgi处理,nginx为其设置环境变量SCRIPT_FILENAME,内容为

/scripts/80sec.jpg/80sec.php

而在其他的webserver如lighttpd当中,我们发现其中的SCRIPT_FILENAME被正确的设置为

/scripts/80sec.jpg

所以不存在此问题。
后端的fastcgi在接受到该选项时,会根据fix_pathinfo配置决定是否对SCRIPT_FILENAME进行额外的处理,一般情况下如果不对fix_pathinfo进行设置将影响使用PATH_INFO进行路由选择的应用,所以该选项一般配置开启。Php通过该选项之后将查找其中真正的脚本文件名字,查找的方式也是查看文件是否存在,这个时候将分离出SCRIPT_FILENAME和PATH_INFO分别为

/scripts/80sec.jpg和80sec.php

最后,以/scripts/80sec.jpg作为此次请求需要执行的脚本,攻击者就可以实现让nginx以php来解析任何类型的文件了。

POC: 访问一个nginx来支持php的站点,在一个任何资源的文件如robots.txt后面加上/80sec.php,这个时候你可以看到如下的区别:

访问http://www.80sec.com/robots.txt

HTTP/1.1 200 OK
Server: nginx/0.6.32
Date: Thu, 20 May 2010 10:05:30 GMT
Content-Type: text/plain
Content-Length: 18
Last-Modified: Thu, 20 May 2010 06:26:34 GMT
Connection: keep-alive
Keep-Alive: timeout=20
Accept-Ranges: bytes

访问访问http://www.80sec.com/robots.txt/80sec.php

HTTP/1.1 200 OK
Server: nginx/0.6.32
Date: Thu, 20 May 2010 10:06:49 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=20
X-Powered-By: PHP/5.2.6

其中的Content-Type的变化说明了后端负责解析的变化,该站点就可能存在漏洞。

漏洞厂商:http://www.nginx.org

解决方案:

我们已经尝试联系官方,但是此前你可以通过以下的方式来减少损失

关闭cgi.fix_pathinfo为0

或者

if ( $fastcgi_script_name ~ \..*\/.*php ) {
return 403;
}

转载至:http://www.80sec.com/nginx-securit.html

nginx升级方法


Nginx编译后就一个小文件,不带动态库,升级也可以无缝升级,并不影响访问。

首先下载Nginx:nginx-0.7.65.tar.gz

再执行 ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module ,按原来的路径配置,自己需要的包打上,基本上没啥,基本功能Nginx都自带了。

然后make,但不要install

编译完,在objs目录下有一个nginx执行文件,就是它了。

备份下原来老的nginx文件

mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old

在把新objs下的nginx cp到sbin下。
cp -p objs/nginx /usr/local/nginx/sbin/

nginx -t 测试下,显示通过。

//让nginx把nginx.pid改成nginx.pid.oldbin 跟着启动新的nginx,一般lnmp一键安装包安装的按下面执行命令即可。
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`

//退出旧的nignx
kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`

升级完成!

nginx 配置代理出错

错误信息 "proxy_pass" may not have URI part in location given by regular expression,

我的配置文件
       location ~ .*\.(php|jsp|cgi)?$  {
                proxy_pass     http://192.168.2.1:8080/;
                proxy_set_header  Host $host;
                proxy_set_header X-Forwarded-For $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }

修改为
       location ~ .*\.(php|jsp|cgi)?$  {
                proxy_pass     http://192.168.2.1:8080;
                proxy_set_header  Host $host;
                proxy_set_header X-Forwarded-For $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }

不要加斜杠,否则就会报错。

Nginx 防盗链设置

在 nginx.conf中的server部分中添加如下代码
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip|doc|pdf|gz|bz2|jpeg|bmp|xls)$ {   
                valid_referers none blocked server_names  *.taobao.com *.baidu.com *.google.com *.google.cn *.soso.com ;  // 对这些域名的网站不进行盗链。
                if ($invalid_referer) {
#                        rewrite   ^/   http://www.52blackberry.com/403.html;
#                        return 403;
                        rewrite ^/ http://www.example.com/nophoto.gif;
                        }
                }
其中 rewrite ^/ 后边可以是一个错误页面,如上边那一行,也可以是一个图片,如下面那个。
对于开头location 部分有的是这样的形式  location ~ .*\.(gif|jpg|png),经我验证都可以实现。

Nginx的代理

upstream bbs.aaa.cn{
            server 1.2.3.1:80;
            server  1.2.3.4:80;
        }


        server {
            listen 80;
            server_name bbs.aaa.cn;

            location / {
                proxy_pass      http://bbs.aaa.cn/;
                proxy_set_header Host   $host;
                proxy_set_header X-Real-IP      $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }
#            access_log  /home/logs/bbs.access combined;
        }


        upstream blog.aaa.cn{
            server  1.2.3.1:80;
            server  1.2.3.4:80;
        }

        server {
            listen 80;
            server_name blog.aaa.cn;

            location / {
                proxy_pass      http://blog.aaa.cn/;
                proxy_set_header Host   $host;
                proxy_set_header X-Real-IP      $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }
#            access_log  /home/logs/ss.access combined;
        }

nginx的代理配置缓存

需要第三方的ngx_cache_purge模块:
wget http://labs.frickle.com/files/ngx_cache_purge-1.0.tar.gz
如果上边地址失效,可以下载这里的  http://mylinux.5d6d.com/userdirs ... he_purge-1.0.tar.gz

编译nginx时,需要加上参数
--add-module=/usr/local/src/ngx_cache_purge-1.0

nginx.conf 需要有下面参数

proxy_connect_timeout 600;                 #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_read_timeout    600;                    #连接成功后,后端服务器响应时间(代理接收超时)
proxy_send_timeout    600;                    #后端服务器数据回传时间(代理发送超时)
proxy_buffer_size     32k;                        #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers         4 32k;                       #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
proxy_busy_buffers_size  64k;               #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size  1024m;     #设定缓存文件夹大小,大于这个值,将从upstream服务器传递请求,而不缓冲到磁盘
proxy_ignore_client_abort on;               #不允许代理端主动关闭连接

#注:proxy_temp_path和proxy_cache_path指定的路径必须在同一分区
proxy_temp_path   /cache/proxy_temp_path;   这里的/cache/proxy_temp_path 是要手动创建的,否则会报错。
#设置Web缓存区名称为cache_one,内存缓存空间大小为200MB,1天没有被访问的内容自动清除,硬盘缓存空间大小为30GB。
proxy_cache_path  /cache/proxy_cache_path levels=1:2 keys_zone=cache_one:200m inactive=1d max_size=30g;


另外虚拟主机配置文件如下:
server {
            listen  80;
            server_name  www.test.com;
            location / {
                proxy_pass     http://192.168.1.111:8080;
                proxy_next_upstream http_502 http_504 error timeout invalid_header;
                proxy_cache cache_one;
                proxy_cache_valid 200 304 12h;
                proxy_cache_valid 301 302 1m;
                proxy_cache_valid any 1m;
                proxy_cache_key $host$uri$is_args$args;
                proxy_set_header Host   $host;
                proxy_set_header X-Real-IP      $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                expires  12h;
            }
            location ~ .*\.(php|jsp|cgi)?$  {
                proxy_pass     http://192.168.1.111:8080;
                proxy_set_header  Host $host;
                proxy_set_header X-Forwarded-For $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }
            access_log  /dev/null combined_realip;
        }

nginx代理--根据访问的目录来区分后端的web

我的需求: 当请求的目录是 /aaa/ 则把请求发送到机器a,当请求的目录为/bbb/则把请求发送到机器b,除了目录/aaa/与目录/bbb/外,其他的请求发送到机器b

我的配置文件内容为:upstream aaa.com
{
            server 192.168.111.6;
}

upstream bbb.com
{
            server 192.168.111.20;
}

server {
        listen 80;
        server_name li.com;
        location /aaa/
        {
            proxy_pass http://aaa.com/aaa/;
            proxy_set_header Host   $host;
            proxy_set_header X-Real-IP      $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        }

        location /bbb/
        {
            proxy_pass http://bbb.com/bbb/;
            proxy_set_header Host   $host;
            proxy_set_header X-Real-IP      $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        }
        location /
        {
            proxy_pass http://bbb.com/;
            proxy_set_header Host   $host;
            proxy_set_header X-Real-IP      $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        }

}
说明:
1 以上配置文件中的 aaa.com 以及 bbb.com 都是自定义的,随便写。
2 upstream 中的server 可以写多个,例如

upstream aaa.com
{
            server 192.168.111.6;
            server  192.168.111.4;
            server  192.168.111.5;
}

3 proxy_pass http://aaa.com/aaa/  这里必须要加这个目录,不然就访问到根目录了。
4 实际上,上述配置文件中, localtion /bbb/ 部分是可以省略掉的,因为后边的 location /  已经包含了/bbb/,所以即使我们不去定义  localtion /bbb/ 也是会访问到 bbb.com 的。

nginx 与 awstats

配置nginx 日志切割


修改日志格式
            log_format  combined_realip  '$remote_addr - $remote_user [$time_local] "$request" '
                 '$status $body_bytes_sent "$http_referer" '
                 '"$http_user_agent" ';

如果,你使用了代理,那么日志格式为:
       log_format  combined_realip  '$http_x_forwarded_for - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" ';


下载awstats 软件
wget  http://cdnetworks-kr-1.dl.source ... awstats-6.95.tar.gz
或者:http://www.ypl.cc/attachments/month_1011/awstats-6.95.tar.gz
tar zxvf  awstats-6.95.tar.gz

安装 awstats
mv awstats-6.95  /usr/local/awstats
cd  /usr/local/awstats/tools

创建一个新的统计

./awstats_configure.pl
-----> Check for web server install

Enter full config file path of your Web server.
Example: /etc/httpd/httpd.conf
Example: /usr/local/apache2/conf/httpd.conf
Example: c:\Program files\apache group\apache\conf\httpd.conf
Config file path ('none' to skip web server setup):
#> none  #因为我们这里用的是 Nginx,所以写 none,跳过。


回车

Your web server config file(s) could not be found.
You will need to setup your web server manually to declare AWStats
script as a CGI, if you want to build reports dynamically.
See AWStats setup documentation (file docs/index.html)

-----> Update model config file '/usr/local/awstats/wwwroot/cgi-bin/awstats.model.conf'
  File awstats.model.conf updated.

-----> Need to create a new config file ?
Do you want me to build a new AWStats config/profile
file (required if first install) [y/N] ?
#> y        #y 创建一个新的统计配置



回车

-----> Define config file name to create
What is the name of your web site or profile analysis ?
Example: www.ypl.cc
Example: demo
Your web site, virtual server or profile name:
#> www.ypl.cc        #统计网站的域名 例:
www.ypl.cc



回车 -----> Define config file path
In which directory do you plan to store your config file(s) ?
Default: /etc/awstats
Directory path to store config file(s) (Enter for default):
#>        


使用默认直接回车,接下来便会出现以下的提示 ----> Add update process inside a scheduler
Sorry, configure.pl does not support automatic add to cron yet.
You can do it manually by adding the following command to your cron:
/usr/local/awstats/wwwroot/cgi-bin/awstats.pl -update -config=www.ypl.cc
               #回头把该命令填入crontab 按指定时间执行
Or if you have several config files and prefer having only one command:
/usr/local/awstats/tools/awstats_updateall.pl now
Press ENTER to continue...                回车继续

A SIMPLE config file has been created: /etc/awstats/awstats.www.ypl.cc.conf  
            #新配置文件所在的路径
You should have a look inside to check and change manually main parameters.
You can then manually update your statistics for 'www.ypl.cc' with command:
> perl awstats.pl -update -config=www.ypl.cc
You can also build static report pages for 'www.ypl.cc' with command:
> perl awstats.pl -output=pagetype -config=www.ypl.cc

Press ENTER to finish...

nginx相关的正则匹配

~ 匹配,区分大小写
~*  不区分大小写的匹配
!~   不匹配
!~*  不匹配
^~   常用于location 语法中,后边是一个字符串。它的意思是,在这个字符串匹配后停止进行正则表达式的匹配。
如: location ^~ /images/,你希望对/images/这个目录进行一些特别的操作,如增加expires头,防盗链等,但是你又想把除了这个目录的图片外的所有图片只进行增加expires头的操作,这个操作可能会用到另外一个location,例如:location ~* \.(gif|jpg|jpeg)$,这样,如果有请求/images/1.jpg,nginx如何决定去进行哪个location中的操作呢?结果取决于标识符^~,如果你这样写:location /images/,这样nginx会将1.jpg匹配到location ~* \.(gif|jpg|jpeg)$这个location中,这并不是你需要的结果,而增加了^~这个标识符后,它在匹配了/images/这个字符串后就停止搜索其它带正则的location。
=      表示精确的查找地址,如location = /它只会匹配uri为/的请求,如果请求为/index.html,将查找另外的location,而不会匹配这个,当然可以写两个location,location = /和location /,这样/index.html将匹配到后者,如果你的站点对/的请求量较大,可以使用这个方法来加快请求的响应速度。
@      表示为一个location进行命名,即自定义一个location,这个location不能被外界所访问,只能用于Nginx产生的子请求,主要为error_page和try_files。