Практический пример на 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-адресом клиента.