Маленький пример на NginX+GeoIP
Задача следующая. Есть фирма, в ней используется корпоративный антивирус 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”, объяснил в предыдущей заметке.