1
vote

I'm running a couple of web hosting servers with Directadmin. I'm running Apache as main web server with Nginx working as a proxy in front of it.

In order to keep Nginx "invisible" to Directadmin, I run Nginx on port 81 and forward all connections arriving port 80 to port 81, and then let Nginx work as a proxy (I based my setup on this post). This has been working perfectly for over a year.

The thing is that yesterday we started to notice an attack in a couple of our servers. We receive requests like this (taken from Apache's mod_status):

11-2    29087   0/17/17 W   1.88    19  0   0.0 0.07    0.07    31.7.58.56  www.somedomain.com  GET http://124.108.121.178/?.src=pop&.intl=e1&.help=1&.v=0&.u=c
12-2    29105   0/5/5   W   0.02    42  0   0.0 0.06    0.06    95.79.20.72 www.somedomain.com  GET http://chek.zennolab.com/proxy.php HTTP/1.1
13-2    29111   0/14/14 W   0.29    26  0   0.0 0.07    0.07    87.227.9.151    www.somedomain.com  POST http://arhack.net/vb/index.php HTTP/1.1
14-2    29113   0/5/5   W   0.80    35  0   0.0 0.00    0.00    94.153.69.101   www.somedomain.com  GET http://72.14.203.105/search?as_q=%22/yybbs53a/yybbs.cgi%22+
15-2    29117   0/12/12 W   1.16    19  0   0.0 0.06    0.06    27.159.254.158  www.somedomain.com  GET http://search.sky.com/web?term=chiropractic+seattle+%22Rece
16-2    29118   0/5/5   W   0.61    36  0   0.0 0.30    0.30    31.7.58.56  www.somedomain.com  GET http://217.146.187.123/?.src=pop&.intl=e1&.help=1&.v=0&.u=c
17-2    29119   0/3/3   W   0.71    38  0   0.0 3.95    3.95    203.116.85.147  www.somedomain.com  GET http://119.160.247.158/?.src=pop&.intl=e1&.help=1&.v=0&.u=c
18-2    29120   0/4/4   W   0.52    36  0   0.0 0.06    0.06    176.9.25.25 www.somedomain.com  GET http://www.bing.com/search?q=link%3Arapidvisa.com&setplang=
19-2    29132   0/12/12 W   1.75    25  0   0.0 0.08    0.08    176.31.122.7    www.somedomain.com  GET http://www.baidu.com/%22>Inicio</a>+|+<a+href=%22/webmail%2
20-2    29142   0/11/11 W   1.48    20  0   0.0 0.58    0.58    87.245.203.22   www.somedomain.com  GET http://www.baidu.com/ HTTP/1.1

The thing is that if I let the requests get to Apache, the load average starts rising. If I suspend the domain (which makes Apache just return an error page, without much processing) it get's much better. So what I would like to do is have Nginx deny those sort of requests so that they don't even get to Apache.

How should I do this?

I tried adding this but it didn't work (maybe the regexp is wrong).

location ~* ^http.* {
            deny all;
        }

Here's my nginx.conf (X.X.X.X is my server's public IP):

user  apache;
worker_processes  4;


events {
    worker_connections  4096;
}

http {

    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  /var/log/nginx/access.log  main;

    ## Size Limits
    client_body_buffer_size     128K;
    client_header_buffer_size   128K;
    client_max_body_size          1M;
    large_client_header_buffers 1 1k;

    ## Timeouts
    client_body_timeout   60;
    client_header_timeout 60;
    keepalive_timeout     60 60;
    send_timeout          60;

    ## General Options
    ignore_invalid_headers   on;
    keepalive_requests      100;
    limit_zone gulag $binary_remote_addr 5m;
    limit_rate              512k;
    recursive_error_pages    on;
    sendfile                 on;
    server_name_in_redirect off;
    server_tokens           off;

    ## TCP options
    tcp_nodelay on;
    tcp_nopush  on;

    ## Compression
    gzip              on;
    gzip_buffers      16 8k;
    gzip_comp_level   6;
    gzip_http_version 1.0;
    gzip_min_length   0;
    gzip_types        text/plain text/css image/x-icon application/x-perl application/x-httpd-cgi;
    gzip_vary         on;

    server_names_hash_bucket_size 64;
    reset_timedout_connection on;

        server {
        listen       0.0.0.0:81;
        server_name  myserver.fqdn.com _;

        charset off;

        access_log off;

        limit_conn  gulag 20;

        # Main reverse proxy for most requests
        location / {
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

                    proxy_pass              http://X.X.X.X;    # apache here

                    client_max_body_size       16m;
                    client_body_buffer_size    128k;

                    proxy_buffering     on;  

                    proxy_connect_timeout      90;
                    proxy_send_timeout         90;
                    proxy_read_timeout         120;
                    proxy_buffer_size          8k;
                    proxy_buffers              32 32k;
                    proxy_busy_buffers_size    64k;
                    proxy_temp_file_write_size 64k;

                    error_page              502 503 /50x.html;
        }

        location /nginx_status {
            stub_status on;
            access_log   off;
            allow 127.0.0.1;
            deny all;
        }

        location ~* ^http.* {
                deny all;
        }        

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /var/www/html;
    }

}
4
votes

There's no way to match those requests with a location, since that style of request uri will be processed by nginx to strip out the scheme://host part.

if ($request ~* https?://) { return 444; }

In the server will match any request lines that contain http:// or https://. 444 is a special code to nginx, it will drop the connection without sending any sort of response. You can change that to a return 403 if you'd prefer.

  • I just realized there's a domain which is on a different IP where Nginx isn't setup as a proxy. Do you know how to do the same in Apache? – El Barto Aug 2 '12 at 21:09
  • 1
    I don't know apache at all anymore, sorry – kolbyjack Aug 2 '12 at 21:30
  • Just a minor change: I had to change the regexp to: ^https?://, because I had problems with other legitimate requests where an URL was passed as a parameter. – El Barto Aug 6 '12 at 18:58

Not the answer you're looking for? Browse other questions tagged or ask your own question.