Nginx: защита по ip + ограничение частых запросов

Хостинг для MODX. modhost.pro

Поразбирался с правилами nginx и написал для себя универсальную «закрывашку» системных директорий для всех ip кроме нужных.

Сюда попадут любые запросы в директории manager, core и connectors. Все адреса, кроме разрешенных получат отлуп, а разрешенные обработаются. Так как nginx начинает применять правила после первого точного совпадения — отдельно указываем как обрабатывать *.php файлы.
location ~* ^\/(manager|core|connectors)\/(?:.*)$ {
	allow		айпиадмина-1;
	allow		айпиадмина-2;
	deny		all;
	
	location ~* \.php$ {
		include		fastcgi_params;
		fastcgi_param	SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_pass	backend-имясайта;
        }
}

А теперь — установка лимита запросов документов сайта. Примитивная защита от DDOS.

Создаём новую зону для работы, в nginx.conf (секция http):
limit_req_zone  $binary_remote_addr  zone=one:10m   rate=1r/s;
Ограничение на запросы — 1 в секунду.

Применяем это ограничение к выполнению *.php файлов сайта:
location ~* \.php$ {
	limit_req       zone=one  burst=3;
	include		fastcgi_params;
	fastcgi_param	SCRIPT_FILENAME $document_root$fastcgi_script_name;
	fastcgi_pass	backend-bezumkin;
}
Burst — это разрешенный кратковременный всплеск запросов. Подробнее в документации.

С этим правилом админка MODX работать не будет, ибо там идёт куча одновременных запросов, на которые nginx будет отвечать error 503.

Но нам это не важно, ибо у нас раньше прописан отдельный блок для работы с системными директориями, и там php выполняется без ограничений.

Можете зажать у меня на сайте кнопку F5 на секунду и отпустить — будет error 503. А если нажимать F5 медленно — ошибки не будет. Спасает от настырных роботов и и простеньких атак.

Любопытным —
# указание обработчика php
upstream backend-mysite {server unix:/var/run/php5-mysite.sock;}

# здесь конфиг сайта
server {
    listen		80;
    server_name		mysite.ru www.mysite.ru;
    root		/var/www/mysite/www;
    access_log		/var/log/nginx/mysite-access.log;
    error_log		/var/log/nginx/mysite-error.log;
    index		index.php;
    rewrite_log		on;

    # редирект с ww на без-www
    if ($host != 'mysite.ru' ) {
        rewrite  ^/(.*)$  http://mysite.ru/$1  permanent;
    }
    
    # если нет запрошенного файла - слать в локацию rewrite
    location / {
        try_files	$uri $uri/ @rewrite;
    }

    # отсюда слать всё на index.php - это есть быть friendly urls
    location @rewrite {
        rewrite		^/(.*)$ /index.php?q=$1;
    }

    # а вот и наша защита системных директорий по ip
    location ~* ^\/(manager|core|connectors)\/(?:.*)$ {
        allow		184.55.68.97;
        deny		all;
	location ~* \.php$ {
            include		fastcgi_params;
            fastcgi_param	SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_pass	backend-mysite;
        }
    }

    # а это выполнение всех php файлов, не попавших в предыдущий блок
    location ~* \.php$ {
	limit_req	zone=one  burst=3;
        include		fastcgi_params;
        fastcgi_param	SCRIPT_FILENAME $document_root$fastcgi_script_name;
	fastcgi_pass	backend-mysite;
    }

    # статику отдаём без участия MODX и php
    location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico|bmp|woff|eot)$ {
       access_log		off;
       expires			10d;
       break;
    }

    # на всякий случай запрещаем чтение .htaccess - вдруг у вас там еще и апач есть?
    location ~ /\.ht {
        deny			all;
    }
}

Василий Наумкин
15 января 2013, 18:05
modx.pro
4
29 002
0

Комментарии: 9

Виталий Киреев
16 января 2013, 06:40
0
limit_req zone=one burst=3;
Для всех сайтов эта строка одинаковая?
А еще заметил, что у тебя nginx той же версии: работают service nginx restart/reload? У меня только kill или killall помогает поменять конфиг, иначе выдает
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
потому что процесс nginx не останавливается…
    Василий Наумкин
    16 января 2013, 06:58
    0
    В основном конфиге задаётся зона, дальше эту ограничивающую зону можно применять к любой location любого сайта.Каждому сайту можно подкрутить параметр burst.

    Если нужно ограничить частоту запросов не 1 в сек, а, например, 2 — то задавай вторую зону и там прописывай это ограничение.
    limit_req_zone  $binary_remote_addr  zone=two:10m   rate=2r/s;

    А потом применяй вторую зону какому-нибудь сайту:
    location / {
    	limit_req zone=two burst=5;
    }

    service nginx restart/reload работает без проблем. На домашнем сервере была такая проблема с php5-fpm, решил полным удалением и установкой заново.
      Виталий Киреев
      16 января 2013, 08:16
      0
      Решил проблему с nginx, может кому-то еще пригодится. В файле /etc/init.d/nginx в функции stop было /run/$NAME.pid, а у меня все пиды в /var/run/
    Сергей Искандеров
    25 ноября 2013, 19:01
    0
    Вопрос на засыпку.
    Есть фронтенд проксирующий, к которому мы не имеем доступа, есть определенная директория, в которую нужно дать доступ пару десяткам IP, так вот, суть в чем. У нас все обращения на бэкенд поступают с 1 проксирующего IP, так как же нам заюзать Allow 123.123.123.123;? =)
    PS: конструкции типо if() отпадают сразу---ip пара десятков
      Роман
      12 октября 2014, 15:53
      0
      прописал в nginx.conf
      limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

      прописал в sites-available/user.conf
      location ~* \.php$ {
      limit_req zone=one burst=3;
      include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_pass backend-mysite;
      }

      перезапускаю service nginx reload
      Вываливается ошибка
      Убираю строку limit_req zone=one burst=3;
      Перезапускаю nginx, ошибка не вываливается.

      В чем может быть дело? :-(
        Роман
        12 октября 2014, 16:16
        0
        в логе вот чего:

        2014/10/12 12:12:16 [emerg] 11282#0: unknown limit_req_zone «one» in /etc/nginx/sites-enabled/user.conf:31
          Роман
          12 октября 2014, 16:31
          0
          Василий, а вот тут точно ссылка куда надо?
          Burst — это разрешенный кратковременный всплеск запросов. Подробнее в документации.

          я так понимаю, что ссылка должна быть сюда nginx.org/ru/docs/http/ngx_http_limit_req_module.html
          Роман
          12 октября 2014, 16:41
          1
          +1
          Разобрался с ошибкой.
          Идущих по этим же граблям предупреждаю:
          В файле nginx.conf строка:
          limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
          должна быть вставлена ДО строки:
          include /etc/nginx/sites-enabled/*;
          Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
          9