nginx limit_req 不工作

nginx limit_req does not work

我正在尝试使用 nginx (v1.6.2) 实现一个简单的速率限制系统

sites-available/mysite.com:

limit_req_zone $binary_remote_addr zone=myzone:10m rate=2r/m;

server {
    listen                      80;
    server_name                 mysite.com;
    root                        /var/www/vhosts/mysite.com;
    error_log                   [..];
    access_log                  [..];

    include                     conf.d/php-fpm.conf;

    location = / {
        limit_req               zone=myzone burst=3 nodelay;
        index                   index.html;
    }

    location / {
        try_files               $uri =404;
    }

    location ^~ /pages {
        include                 conf.d/php-fpm.conf;
        internal;
    }

    location = /email {
        rewrite ^(.*)$          /pages/email.html;
    }

    location = /email/subscribe {
        limit_req               zone=myzone burst=2 nodelay;
        rewrite ^(.*)$          /pages/email.php?action=subscribe;
    }

    location ~ /api {
       limit_req                zone=myzone burst=5 nodelay;
       rewrite ^(.*)$           /pages/api.php;
    }
}

conf.d/php-fpm.conf:

location ~ \.php$ {
    if (!-f $document_root$fastcgi_script_name) {
        return 404;
    }
    fastcgi_pass                unix:/var/run/php5-fpm.sock;
    fastcgi_index               index.php;
    fastcgi_param               SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_split_path_info     ^(.+?\.php)(/.*)$;
    fastcgi_param               PATH_INFO $fastcgi_path_info;
    include                     fastcgi_params;
}

nginx.conf: 没什么意思,只有
include sites-enabled/*;

速率限制 / 工作正常。如果对此页面的请求过多,我会收到错误 503。
问题: /email/subscribe/api/api/test 都没有速率限制,我不知道为什么。肯定是跟rewrite有关系,但是有什么问题吗?
有任何想法吗?我什么都试过了!

请注意:我更改了文件名和 URL 端点。

问题是 nginx 进程请求在几个 phasesrewrite 阶段在 preaccess 阶段之前(这是在哪里limit_req 已应用)。因此,在您的配置中,请求在有机会受到限制之前被重写为 /pages/...。为避免这种情况,您要么在重写后留在同一位置块中(使用 break 标志),要么使用 try_files.

进行一些修改

我更喜欢第一个选项,因此您的配置可能如下所示:

limit_req_zone $binary_remote_addr zone=myzone:10m rate=2r/m;

server {
    listen                      80;
    server_name                 mysite.com;
    root                        /var/www/vhosts/mysite.com;
    error_log                   [..];
    access_log                  [..];

    include                     conf.d/php-fpm.conf;

    location = / {
        limit_req               zone=myzone burst=3 nodelay;
        index                   index.html;
    }

    location / {
        try_files               $uri =404;
    }

    location ^~ /pages {
        include                 conf.d/php-fpm.conf;
        internal;
    }

    location = /email {
        rewrite ^(.*)$          /pages/email.html;
    }

    location = /email/subscribe {
        limit_req               zone=myzone burst=2 nodelay;
        rewrite ^(.*)$          /pages/email.php?action=subscribe break;
        fastcgi_pass            unix:/var/run/php5-fpm.sock;
        fastcgi_param           SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include                 fastcgi_params;
    }

    location ~ /api {
       limit_req                zone=myzone burst=5 nodelay;
       rewrite ^(.*)$           /pages/api.php break;
       fastcgi_pass             unix:/var/run/php5-fpm.sock;
       fastcgi_param            SCRIPT_FILENAME $document_root$fastcgi_script_name;
       include                  fastcgi_params;
    }
}

如果您选择第二个选项,您的配置会更简洁一些,但有点老套。我们将使用 try_files 阶段在 limit_req 阶段之后运行的事实,并且 try_files 将内部重定向到它的最后一个参数。

limit_req_zone $binary_remote_addr zone=myzone:10m rate=2r/m;

server {
    listen                      80;
    server_name                 mysite.com;
    root                        /var/www/vhosts/mysite.com;
    error_log                   [..];
    access_log                  [..];

    include                     conf.d/php-fpm.conf;

    location = / {
        limit_req               zone=myzone burst=3 nodelay;
        index                   index.html;
    }

    location / {
        try_files               $uri =404;
    }

    location ^~ /pages {
        include                 conf.d/php-fpm.conf;
        internal;
    }

    location = /email {
        rewrite ^(.*)$          /pages/email.html;
    }

    location = /email/subscribe {
        limit_req               zone=myzone burst=2 nodelay;
        try_files SOME_NONEXISTENT_FILE /pages/email.php?action=subscribe;
    }

    location ~ /api {
       limit_req                zone=myzone burst=5 nodelay;
       try_files SOME_NONEXISTENT_FILE /pages/api.php;
    }
}