我正在使用 Nginx、MariaDB、PHP-FPM 运行一个 Wordpress 网站,并被来自大量 IP 的大量不同 404 请求轰炸(每小时约有 10,000 个不同的 IP 请求随机 URL,导致非常高的 SQL 负载和随机停机)。
我尝试将主服务器放在不同的 Nginx 服务器后面,该服务器将对站点进行反向代理缓存以减少负载,但由于 404 请求通过了 Nginx 代理缓存服务器,主服务器仍然负载很高。
我认为服务器现在出现 5XX 错误是因为 MYSQLD 占用了所有 CPU 来处理其内容,从而导致 PHP-FPM 处于饥饿状态并且无法响应 Nginx 的请求?
我在错误日志中看到很多这样的信息:
2017/05/13 03:48:40 [error] 24894#24894: *2936187 upstream timed out (110: Connection timed out) while connecting to upstream
我的服务器有 16 核、64GB RAM 和 200GB SSD 磁盘,运行 Ubuntu 17.04,MYSQLD 总是尽可能地占用所有 CPU。
我的主服务器 Nginx 配置:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 2048;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 32M;
disable_symlinks off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
gzip off;
### START SERVER CONFIG
server {
listen 80 default_server;
root /var/www/html;
index index.php index.html index.htm;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
server_name _;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass 127.0.0.1:9000;
}
location ~ /\.ht {
deny all;
}
}
### END OF SERVER CONFIG
}
PHP-FPM 配置:
[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
listen.owner = www-data
listen.group = www-data
listen.allowed_clients = 127.0.0.1
process.priority = -10
pm = dynamic
pm.max_children = 64
pm.start_servers = 32
pm.min_spare_servers = 2
pm.max_spare_servers = 32
有什么办法可以改善这种情况吗?正如我所说,所有请求都来自许多不同的 IP,这些 IP 请求不同的 URL,并且请求看起来非常合法(标头看起来与浏览器完全一样),因此我无法制定任何防火墙规则来阻止它,但我知道它们是自动请求,因为有些用户代理告诉它来自 IA64 架构,而我的任何访问者都不会拥有它。
不,由于某种原因,我无法使用 Cloudflare 或类似服务来阻止自动请求...那么,是否有任何 Nginx 插件可以通过测试 javascript 或类似方法来检测它是真正的浏览器加载还是机器人,然后才允许它进入网站?
答案1
首先,我会研究传入的请求。它们真的是攻击吗,还是您的应用程序有很多断开的链接?如果您能修复原因,那总是更好的。
Fail2Ban 也是我推荐的,但是如果每个 IP 只发出一个请求,它就起不了多大作用。
无论如何,您都希望避免出现 404 错误,以便访问 Wordpress/PHP/MySQL。如果请求中存在任何可以匹配的模式,则 Web 服务器可以处理它。如果没有明确的模式,则更棘手,但仍然可以做到。
这些针对 MySQL 的说明可以适用于 Nginx:
https://www.pipeten.info/2015/10/better-handling-wordpress-404-errors/
但可能更好的是 Repsheet。
它可以帮助判断请求是否是您想要的,并对其进行不同的处理。这些 IP 随机出现 404 错误显然不是在模仿正常的用户行为。Repsheet 经过一些学习后就能判断出来,然后您可以在请求到达整个 Web 堆栈之前发出 404 或 403 错误。
Repsheet 有一个适用于 Nginx 的模块:https://github.com/repsheet/repsheet-nginx
反过来,它会将您的真实(重复)用户视为优秀的参与者,并且您可以设置规则来对他们进行优先排序。
最后,因为大多数 HTTP 机器人都很愚蠢,您可以使用 Nginx 的测试 Cookie 模块来测试这是否是真正的用户代理:
https://github.com/kyprizel/testcookie-nginx-module
(但要小心阻止像 Google 这样的好机器人,不要毁掉你的 SEO,将它们列入白名单!)