Nginx модуль map

Thank you for reading this post, don't forget to subscribe!

Модуль map поз­во­ля­ет созда­вать в кон­фи­гу­ра­ци­он­ном фай­ле Nginx пере­мен­ные, зна­че­ния кото­рых явля­ют­ся услов­ны­ми, то есть зави­сят от зна­че­ний дру­гих пере­мен­ных. В этом руко­вод­стве вы узна­е­те, как исполь­зо­вать модуль map Nginx. Для это­го мы попро­бу­ем выпол­нить два при­ме­ра: настро­ить спи­сок пере­на­прав­ле­ний ста­рых URL-адре­сов сай­тов на новые и создать спи­сок раз­ре­шен­ных стран для управ­ле­ния тра­фи­ком сайта.

1: Создание тестовой веб-страницы

Сна­ча­ла мы созда­дим тесто­вый файл, кото­рый будет пред­став­лять собой све­жий веб-сайт. В даль­ней­шем мы будем исполь­зо­вать этот файл для про­вер­ки нашей кон­фи­гу­ра­ции веб-сервера.

Давай­те созда­дим в ката­ло­ге веб-сай­та Nginx по умол­ча­нию про­стую стра­ни­цу index.html. В этом фай­ле будет текст, опи­сы­ва­ю­щий стра­ни­цу – «Home».

sudo sh -c 'echo "Home" > /var/www/html/index.html'

Давай­те с помо­щью curl про­ве­рим, пра­виль­но ли обслу­жи­ва­ет­ся этот файл. Нам не нуж­но ука­зы­вать index.html в этой коман­де, пото­му что этот файл обслу­жи­ва­ет­ся по умол­ча­нию, если точ­ное имя фай­ла не указано:

curl http://localhost/

В резуль­та­те вы долж­ны уви­деть одно сло­во Home.

Теперь давай­те попро­бу­ем полу­чить доступ к фай­лу, кото­ро­го нет в /var/www/html/, напри­мер old.html:

curl -L http://localhost/old.html

В ответ вы уви­ди­те сооб­ще­ние об ошиб­ке 404 Not Found, что озна­ча­ет, что стра­ни­ца не существует:

404 Not Found

В этом руко­вод­стве мы исполь­зу­ем нена­сто­я­щий веб-сайт, но если бы файл old.html был стра­ни­цей реаль­но­го сай­та, кото­рую уда­ли­ли, резуль­тат 404 озна­чал бы, что все ссыл­ки на эту стра­ни­цу не рабо­та­ют. Это не очень хоро­шо, посколь­ку эти ссыл­ки мог­ли быть про­ин­дек­си­ро­ва­ны Google, поль­зо­ва­те­ли мог­ли сохра­нить их или поде­лить­ся с кем-нибудь, а теперь они не работают.

В сле­ду­ю­щем раз­де­ле мы будем исполь­зо­вать модуль map, что­бы этот ста­рый адрес сно­ва стал рабо­тать – путем авто­ма­ти­че­ско­го пере­на­прав­ле­ния поль­зо­ва­те­лей на новые страницы.

2: Настройка перенаправления

Для настрой­ки реди­рек­та на неболь­ших веб-сай­тах подой­дут и про­стые услов­ные опе­ра­то­ры if. Одна­ко на боль­шом сай­те такую кон­фи­гу­ра­цию нелег­ко под­дер­жи­вать или рас­ши­рять в дол­го­сроч­ной пер­спек­ти­ве, посколь­ку спи­сок усло­вий будет быст­ро расти.

Модуль map – более про­стое и лако­нич­ное реше­ние. Он поз­во­ля­ет срав­ни­вать зна­че­ния пере­мен­ных Nginx со спис­ком усло­вий, а затем свя­зы­вать новое зна­че­ние с пере­мен­ной в зави­си­мо­сти от сов­па­де­ния. В этом при­ме­ре мы будем срав­ни­вать запро­шен­ный URL со спис­ком ста­рых стра­ниц, кото­рые нуж­но пере­на­пра­вить на их новые вер­сии. Каж­дый ста­рый адрес мы свя­жем с новым.

Модуль map явля­ет­ся встро­ен­ным моду­лем Nginx, то есть его не нуж­но уста­нав­ли­вать отдель­но. Что­бы создать необ­хо­ди­мую кон­фи­гу­ра­цию пере­на­прав­ле­ния, открой­те в тек­сто­вом редак­то­ре кон­фи­гу­ра­ци­он­ный файл бло­ка server по умолчанию:

sudo nano /etc/nginx/default

Най­ди­те кон­фи­гу­ра­цию server, она выгля­дит так:

Мы доба­вим два новых раз­де­ла: один перед бло­ком server, вто­рой – внут­ри него. Раз­дел перед бло­ком server – это новый блок map, кото­рый опре­де­ля­ет соот­вет­ствие меж­ду ста­ры­ми и новы­ми URL-адре­са­ми с помо­щью моду­ля map. Раз­дел внут­ри бло­ка server – это сам редирект:

Дирек­ти­ва map $uri $new_uri при­ни­ма­ет содер­жи­мое систем­ной пере­мен­ной $uri, кото­рая содер­жит URL-адрес запра­ши­ва­е­мой стра­ни­цы, и затем срав­ни­ва­ет его со спис­ком усло­вий в фигур­ных скоб­ках. Каж­дый эле­мент в спис­ке усло­вий име­ет два раз­де­ла: зна­че­ние для сопо­став­ле­ния и новое зна­че­ние, кото­рое будет при­сво­е­но пере­мен­ной, если пер­вое зна­че­ние совпадает.

Стро­ка /old.html /index.html внут­ри бло­ка map озна­ча­ет, что если зна­че­ние $uri рав­но /old.html, зна­че­ние $new_uri будет изме­не­но на /index.html. Если зна­че­ние не сов­па­да­ет – ниче­го не меня­ет­ся. В этом при­ме­ре мы опре­де­ля­ем толь­ко одно усло­вие, но вы може­те опре­де­лить в бло­ке map любое коли­че­ство условий.

Исполь­зуя услов­ный опе­ра­тор if внут­ри бло­ка server, мы про­ве­ря­ем, уста­нов­ле­но ли зна­че­ние пере­мен­ной $new_uri. Если зна­че­ние уста­нов­ле­но, это озна­ча­ет, что усло­вие бло­ка map было выпол­не­но, и веб-сер­вер дол­жен пере­на­пра­вить посе­ти­те­ля на новый веб-сайт с помо­щью коман­ды rewrite. Клю­че­вое сло­во permanent дела­ет пере­на­прав­ле­ние посто­ян­ным (HTTP-пере­на­прав­ле­ние 301, Moved Permanently) – это озна­ча­ет, что ста­рый адрес боль­ше не дей­стви­те­лен и не будет использоваться.

Сохра­ни­те и закрой­те файл.

Что­бы вклю­чить новую кон­фи­гу­ра­цию, пере­за­пу­сти­те Nginx:

systemctl restart nginx

Что­бы про­те­сти­ро­вать новую кон­фи­гу­ра­цию, выпол­ни­те тот же запрос, что и раньше:

curl -L http://localhost/old.html

На этот раз в выво­де не будет ошиб­ки 404 Not Found. Вме­сто это­го вы уви­ди­те домаш­нюю стра­ни­цу, кото­рую мы созда­ли в раз­де­ле 1.

Это зна­чит, что блок map настро­ен пра­виль­но, и вы може­те исполь­зо­вать его для пере­на­прав­ле­ния URL-адре­сов. Поз­же вы смо­же­те доба­вить в него и дру­гие записи.

Пере­на­прав­ле­ние URL-адре­сов – одна из полез­ных функ­ций моду­ля map. Вто­рая функ­ция, кото­рую мы рас­смот­рим в сле­ду­ю­щем раз­де­ле, – это филь­тра­ция тра­фи­ка на осно­ве гео­гра­фи­че­ско­го рас­по­ло­же­ния посетителей.

3: Ограничение доступа к сайту

Ино­гда сер­вер может полу­чать чрез­мер­ное коли­че­ство авто­ма­ти­зи­ро­ван­ных вре­до­нос­ных запро­сов. Это может быть DDoS-ата­ка, под­бор паро­лей к пане­ли адми­ни­стра­то­ра или попыт­ка исполь­зо­вать извест­ные уяз­ви­мо­сти в про­грамм­ном обес­пе­че­нии для ата­ки на сайт и исполь­зо­ва­ния его для рас­сыл­ки спа­ма или раз­ме­ще­ния дру­го­го контента.
Такие авто­ма­ти­че­ские ата­ки могут исхо­дить с рас­пре­де­лен­ных сер­ве­ров, нахо­дя­щих­ся в раз­ных стра­нах, что затруд­ня­ет бло­ки­ров­ку. Один из мето­дов смяг­че­ния послед­ствий такой ата­ки – это спи­сок раз­ре­шен­ных стран, кото­рые могут полу­чить доступ к веб-сайту.

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

Филь­тра­ция тра­фи­ка на уровне сер­ве­ра про­ис­хо­дит быст­рее, чем на уровне веб-сай­та, так­же она охва­ты­ва­ет все запро­сы (вклю­чая ста­ти­че­ские фай­лы, напри­мер, изоб­ра­же­ния). Этот вид филь­тра­ции так­же предот­вра­ща­ет попа­да­ние запро­сов непо­сред­ствен­но в про­грамм­ное обес­пе­че­ние веб-сай­та, что затруд­нит исполь­зо­ва­ние уязвимостей.

Что­бы исполь­зо­вать гео­гра­фи­че­скую филь­тра­цию, мы долж­ны сна­ча­ла уста­но­вить модуль Nginx GeoIP, а так­же базу дан­ных GeoIP, содер­жа­щую сопо­став­ле­ния меж­ду IP-адре­са­ми посе­ти­те­лей и стра­на­ми. Для это­го нуж­но запу­стить команду:

yum -y install https://extras.getpagespeed.com/release-latest.rpm

yum install nginx-module-geoip2

добавляем в /etc/nginx/nginx.conf:

load_module modules/ngx_http_geoip2_module.so;

yum install geoipupdate geoipupdate-cron

Теперь давай­те созда­дим новый кон­фи­гу­ра­ци­он­ный файл:

nano /etc/nginx/conf.d/geoip.conf

Вставь­те в файл сле­ду­ю­щие стро­ки. Эти пара­мет­ры сооб­щат Nginx, где най­ти базу дан­ных GeoIP для опре­де­ле­ния стран по IP-адре­сам посетителей:

Сле­ду­ю­щим шагом явля­ет­ся созда­ние необ­хо­ди­мой кон­фи­гу­ра­ции огра­ни­че­ний и бло­ка map. Открой­те блок server по умолчанию:

nano /etc/nginx/conf.d/default

Най­ди­те блок server, кото­рый после изме­не­ний, вне­сен­ных в раз­де­лах 1 и 2, выгля­дит так:

Давай­те доба­вим два раз­де­ла: один перед бло­ком server и один внут­ри него. Раз­дел перед бло­ком – это новый блок map, кото­рый опре­де­ля­ет дей­ствие по умол­ча­нию (в дан­ном слу­чае – доступ запре­щен), а так­же спи­сок кодов стран, кото­рым раз­ре­шен доступ к сай­ту. Раз­дел внут­ри бло­ка server запре­ща­ет доступ к сай­ту, если так гово­рит блок map.

Сохра­ни­те и закрой­те файл.

Здесь в каче­стве запол­ни­те­лей мы исполь­зо­ва­ли country_code_1 и country_code_2. Заме­ни­те эти услов­ные зна­че­ния двух­сим­воль­ным кодом стран, тра­фик из кото­рых вы хоти­те раз­ре­шить. Пол­ный спи­сок кодов стран вы най­де­те здесь.

В отли­чие от бло­ка map, в этом бло­ке пере­мен­ная $allowed_country все­гда будет иметь какое-то зна­че­ние. По умол­ча­нию для нее уста­нов­ле­но зна­че­ние no; если пере­мен­ная $geoip_country_code соот­вет­ству­ет одно­му из кодов стра­ны в бло­ке, пере­мен­ной allowed_country при­сва­и­ва­ет­ся зна­че­ние yes. Если пере­мен­ная $allowed_country име­ет зна­че­ние no, поль­зо­ва­тель полу­чит ответ 444 Connection Closed Without Response и не смо­жет попасть на сайт.

Что­бы вклю­чить новую кон­фи­гу­ра­цию, пере­за­пу­сти­те Nginx:

systemctl restart nginx

Если вы не доба­ви­ли свою стра­ну в спи­сок раз­ре­шен­ных, при попыт­ке посе­тить http://your_server_ip вы уви­ди­те сооб­ще­ние об ошиб­ке, напри­мер The page isn’t working или The page didn’t send any data. Если вы доба­ви­ли свою стра­ну в спи­сок раз­ре­шен­ных, вы уви­ди­те то же, что и рань­ше: стра­ни­цу Home.