Debian.pro/

Про Debian


Nginx, блокировка доступа по IP.

Продолжаем ковырять nginx и перекладывать на него функции с apache. В общем-то, у апача я давно не использую описанную здесь функцию, поэтому и забыл написать.

Формально, в nginx существует 2 способа ограничить доступ по ip. Первый — вполне привычные директивы — deny/allow. Второй — очень удобный для ограничения доступа в куче мест — geo переменные.

С deny/allow всё понятно, использовать их можно-нужно так же, как в любом другом веб-сервере:
deny 192.168.0.1;
allow 192.168.0.1/24;
allow 8.8.8.8;
deny all;

Эти строчки можно вписать почти в любой кусок конфига — начиная с http {} (тогда правила распространятся на весь сервер) и заканчивая отдельным location {}.

Второй способ уже интереснее и не встречается в apache. Как вы знаете, в nginx можно очень удобно работать с любыми переменными. А в переменные писать что угодно. Так вот — почему бы не делать что-либо в зависимости от того, какой IP адрес у посетителя? Прелесть такого варианта в том, что мы можем отдавать не 403ю ошибку, как в первом способе, а 404ю. Или редиректить на другой сайт. Или ещё-что нибудь… ну и так далее.

Собственно говоря, выглядит это так. Пишем в секцию http {} (для того, чтобы эту переменную мы могли использовать в любом server {} ):

geo $accessvar {
default 0;
# 1 = бухгалтеры
192.168.1.0/24 1;
# 2 = манагеры
192.168.2.0/24 2;
# 3 = веб-серверы
1.1.1.1 3;
2.2.2.2 3;
4.4.4.4 3;
}

Что мы в итоге написали. Если кто-то придет из подсети 192.168.1.0/24 — то переменная $accessvar выставляется в 1. Если из 192.168.2.0/24 — то в 2. Если пришла машина с IP адресом 1.1.1.1/2.2.2.2/4.4.4.4 — то переменная выставляется в 3. Если какой-то другой адрес — то 0.
При помощи if-ов мы можем юзать эти штуки уже как угодно. Например, у нас есть сайт internal.company.name для сотрудников (и для серверов, чтобы они забирали оттуда какую-либо информацию для обновления сайтов). И сайт compmany.com, на который должны попадать посетители.
Случайных посетителей сайта internal будем редиректить на правильный сайт:
server {
...
if ($accessvar = 0) {
rewrite ^/(.*) http://company.name permanent;
}
...
}

Это, кстати, спасет и от надоедливых ботов, которые игнорируют robots.txt.
Далее. У нас есть 3 location:
/buh — сюда нам нужно пускать только бухгалтеров (ну там морда 1с, например)
/manager — сюда только менеджеров
/export — сюда только серверы.

Представляете, какой вам ад пришлось бы разводить в конфигах, чтобы добиться этого с access/deny )? А тут вам нужно только поддерживать актуальный список адресов в одном месте.

server {
...
location /buh {
if ($accessvar != 1) {
return 404;
}
location /manager{
if ($accessvar != 2) {
return 404;
}
location /export {
if ($accessvar != 3) {
return 404;
}
...
}

Ну и не забываем порестартить nginx:
/etc/init.d/nginx restart

Помните, deny/access работает быстрее, но обладает очень узким функционалом. Но от ddos’a оно не спасет тоже — от ддоса лучше защищаться файрволлом. Поэтому переменные geo имеют право на существование. При этом они куда более удобны при правильном использовании. Кстати, можно создавать сразу именованные переменные — buh, manager, server, например =)


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

  1. alex :

    Можно не перезапускать nginx, а делать realod.

  2. Далеко не во всех случаях.

  3. alex :

    В каких нельзя?

  4. Например, при reload не перечитывается listen.
    Алсо при релоаде не получится ввести пароль от ssl-ключа, если он есть.

  5. alex :

    А где можно про это прочитать? Оф. документация ничего об этом не говорит (вот здесь например: http://nginx.org/ru/docs/control.html#reconfiguration).

  6. На практике убедиться можно.

  7. Alex :

    а как сделать чтоб в зависимости от переменной выбирать нужный локатион, а не запрещать в локатионах всех кроме.

  8. rewrite $какая-топеременная last;

    какую-то переменную, видимо, брать из map.

Написать комментарий