Задача следующая. Есть фирма, в ней используется корпоративный антивирус Eset NOD32. Обновление происходит по протоколу HTTP с собственного зеркала, расположенного на веб-сервере в датацентре. Фирма состоит из крупных филиалов, мелких филиалов и сотрудников, работающих удалённо. Требуется достичь следующего поведения зеркала обновлений.
- Если IP клиента соответствует мелкому филиалу (фиксирован и заранее известен), то отдать обновления без запроса логина-пароля.
- Если IP клиента соответствует крупному филиалу (также фиксирован и заранее известен), то выдать HTTP 302 и перенаправить на другое зеркало, расположенное в локальной сети этого филиала с целью экономии трафика.
- Во всех остальных случаях запросить логин и пароль. Если они окажутся верными, то отдать обновления.
В NginX подобные задачи рекомендуется решать директивой "satisfy any;", но в данном случае такой трюк не проходит из-за необходимости делать редиректы. Приходится прибегать к помощи http_geo_module.
Работает он достаточно просто. В контексте http прописываем список IP адресов и вместе с ними значения переменной, которые будут присвоены в случае совпадения IP клиента со строкой в списке. По умолчанию переменная принимает значение, указанное в строке "default". В моем случае:
geo $geo {
default world;
192.168.0.0/22 internal;
1.2.3.4/32 internal;
192.168.14.0/24 branch;
5.6.7.8/32 branch;
}
Где "$geo" - имя переменной; "world" - значение этой переменной, присваиваемое когда клиент пришел "из мира", то есть не из локальных сетей; "internal" - "свои клиенты" (отдавать без пароля); "branch" - филиал с собственным зеркалом, то есть случай когда нужно делать редирект. Разумеется, все эти имена я придумал сам, они могут быть любыми.
Далее, в настройках сервера (или виртуального хоста) задаем примерно следующую конфигурацию.
server {
listen 80;
server_name nod.my-company.ru nod;
access_log /var/log/nginx/nod.access.log;
charset UTF-8;
root /var/www/nod;
autoindex on;
# Из "мира" только с авторизацией
location @world {
auth_basic "Please provide password to access updates";
auth_basic_user_file nodpwd;
}
# Изнутри используем дефолтные настройки
location @internal { }
# Из филиала - перенаправление на внутренний сервер
location @branch {
rewrite ^
http://my.server.local/?; }
location / {
# Редирект в нужный именованный location
error_page 418 = @$geo;
return 418;
}
}
В корневом location-е (последний в списке) анализируется переменная "$geo" и в зависимости от её значения происходит внутреннее перенаправление в один из именованных location-ов. А дальше уже можно творить всё что нам хочется, при этом поведение сервера будет определяться IP-адресом клиента.
Почему в предпоследнем location-е перенаправление идет в корень локального сервера, а не на "$request_uri", объяснил в
предыдущей заметке.