Геотаргетинг nginx, частный случай

в 16:00, , рубрики: drupal, geo, nginx, Веб-разработка, геотаргетинг, метки: , ,

Возникла задача сделать геотаргетинг для регионов России на новостном сайте, т.е. при заходе на главную страницу, должно происходить перенаправление на региональную страницу сайта с адресами вида: region/[номер региона], причем перенаправление клиента должно осуществляться на nginx-е без передачи данных на апач, в противном случае это лишняя ненужная нагрузка на сервер.

Средняя посещаемость ресурса 40т в сутки. Drupal, кеширующий модуль boost, создающий статичные страницы которые выдает nginx.

Поиск решения в google предлагал варианты js перенаправление на стороне клиента, либо передачу данных на апач, запрос базы данных для получения нужного урла, что изначально не устраивало.

Рассмотрев доступные базы ip адресов: www.wipmania.com/ru/base/, www.maxmind.com/en/home, ipgeobase.ru/, возникла «гениальная идея», что если бы в базе были необходимые нам урлы [номер региона], то счастье было бы полным.

Исходя из этого и условий, что геотаргетинг делается только для регионов России, остановился на модуле nginx geo и базе адресов от ipgeobase, так как модуль geo может принимать текстовый файл в качестве базы адресов, ну а база от ipgeobase распространяется в текстовом формате. Осталось, собственно, привести базу адресов в нужный формат…

Итак:
Отсюда ipgeobase.ru/files/db/Main/geo_files.tar.gz скачиваем базу данных, получаем архив, распаковываем и получаем 2 файла cidr_optim.txt и cities.txt.
cidr_optim.txt имеет следующий формат записи:
<начало блока> <конец блока> <блок адресов> <страна> <идентификатор города>

<начало блока> — число, полученное из первого ip адреса блока (диапазона) ip-адресов вида a.b.c.d по формуле a*256*256*256+b*256*256+c*256+d
<конец блока> — число, полученное из второго ip адреса блока (диапазона) ip-адресов вида e.f.g.h по формуле e*256*256*256+f*256*256+g*256+h
<блок адресов> — блок (диапазон) ip-адресов вида a.b.c.d — e.f.g.h, для кторого определено положение
<страна> — двухбуквенный код страны, к которой относится блок
<идентификатор города> — идентификатор города из файла cities.txt. Если вместо идентификатора стоит прочерк, значит, либо город не удалось определить, либо страна блока не Россия и не Украина.

cities.txt имеет следующий формат записи:
<идентификатор города> <название города> <название региона> <название округа> <широта центра города> <долгота центра города>
Описание файлов находится здесь ( ipgeobase.ru/Help.html#35 )

Из всего этого, распарсив файлы в базу данных, получил 2 таблицы с данными из файлов, которые, затем, используя названия регионов привел к формату

«блок (диапазон) ip-адресов вида a.b.c.d — e.f.g.h» -> (необходимый урл) [номер региона]

Дело осталось за малым — перевести формат:
«блок (диапазон) ip-адресов вида a.b.c.d — e.f.g.h» в формат понимаемый модулем geo:
0.0.0.0/0 (начальный адрес/битовая маска).

Тут, как ни странно, началось самое веселое. Опросил все знакомых админов, все дружно сказали что проходили то как перевести диапазон в нужный мне формат, но, за ненадобностью, все давно забыли, а вспоминать некогда. Google, который всегда нам в помощь, предлагал либо инструкции по расчету диапазона по адресу и маске, либо досконально изучить принцип формирования сетей ip4.
Для решения задачи выбрал 3-й вариант. В сети нашел ip-calculator.ru/, связался с администратором домена, который любезно согласился помочь с переводом и разъяснением принципа перевода адресов в нужный формат. (еще раз спасибо).

В итоге получился файл формата «0.0.0.0/0 (необходимый урл);» c 57 тысячами строк, назовем его, скажем, geo_ru.conf.

Теперь, собственно, nginx:
в блоке http{} включаем модуль

geo $region_number {
	    default        all;
	    include        [адрес где лежит файлик]/geo_ru.conf
}

т.е. после обращения, в случае нахождения адреса клиента в файле, в переменной $region будет находиться соответствующее значение, а именно [номер региона], в противном случае 'all'. (подробнее: nginx.org/ru/docs/http/ngx_http_geo_module.html )
Далее, собственно, редирект:
в блоке server{} сайта

# установили переменную $get_redirect со значением donot_redirect
set $get_redirect donot_redirect; 
# в случае, если клиент заходит на главную страницу присваеваем переменной значение do_redirect                             
if ($uri = '/') {                                               
    set $get_redirect do_redirect;                              
} 
# если nginx не нашел адреса клиента в базе и в переменной $region_number значение 'all' , то и редиректить незачем                                                           
if ($city = 'all') {                                            
    set $get_redirect donot_redirect;                           
}  
# если уже есть кука, т.е. клиент уже заходил к нам и мы его редиректили на его регион (должна же быть возможность смотреть главную страницу)                                                             
if ($cookie_geolocate = 1) {                                    
    set $get_redirect donot_redirect;                           
} 
# ну и собственно сам редирект на нужную страницу                                                              
if ($get_redirect = do_redirect) {                                          
    rewrite ^(.*)$ http://fedpress.ru/region/$region_number redirect;    
}    

(т.е. в итоге мы получили то что хотели — переход на region/[номер региона])

Ну и последнее — чтобы клиент мог все-таки посмотреть главную страницу, в блоке
location / {} отправляем клиенту куку:

add_header Set-Cookie "geolocate=1;Path=/;Domain=.example.com;";  

Вот, собственно, и все. Надеюсь кому-нибудь поможет. Поводом для написания статьи стало то что решение, вроде бы очевидное, появилось не сразу. Буду рад комментариям, советам, уточнениям.

PS Уважаемые админы, присутствующие на хабре, напишите, пожалуйста, статью с пошаговым руководством «для чайников» о том что такое ip адреса, как расчитывать маску по диапазону и наоборот, зачем нужны <начало блока> (a*256*256*256+b*256*256+c*256+d) и <конец блока> (e*256*256*256+f*256*256+g*256+h), думаю многие были бы благодарны.

Автор: ApremierA

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js