Север Angie вобрал в себя всю функциональность, которая десятилетиями формировалась в Nginx. Кроме того, разработчики за несколько лет добавили еще несколько модулей и расширили возможности существующих. Тем не менее, при реализации сложных задач может потребоваться индивидуальное решение, нестандартное поведение сервера и кастомизированная конфигурация. В таких задачах полезно использовать модули для расширения функциональности сервера на базе различных языков программирования: доступны njs, Lua и Perl.
Навигация по циклу
Настройка location в Angie. Разделение динамических и статических запросов.
Перенаправления в Angie: return, rewrite и примеры их применения.
Сжатие текста в Angie: статика, динамика, производительность.
Кастомизация Angie (njs, Lua, Perl).
Видеоверсия
Для вашего удобства подготовлена видеоверсия этой статьи, доступна на Rutube, VKVideo и YouTube.
Модуль Perl
Начнём с классического модуля Perl, вносящего динамику в конфигурацию Angie. На всякий случай: документация предупреждает нас об экспериментальном статусе модуля. Он появился на ранних этапах развития Nginx и до сих пор поставляется в комплекте с Angie. Хотя сегодня язык Perl не пользуется большой популярностью у разработчиков, он имеет ряд преимуществ. Во‑первых, интерпретатор Perl входит в комплект большинства дистрибутивов Linux, то есть обладает высокой совместимостью. Также, язык обладает очень высокой стабильностью с точки зрения синтаксиса. Если вы найдёте решение, написанное лет 20 назад, практически всегда оно будет работать на современной версии интерпретатора.
Использовать модуль Perl можно для нескольких задач:
определение внутренних переменных Angie;
подключение полноценных обработчиков запросов;
использование при включении Perl‑скриптов в SSI.
Модуль Perl работает только в контексте HTTP. Установка и подключение модуля стандартны:
apt install angie-module-perl
Подключение (в контексте main):
load_module modules/ngx_http_perl_module.so;
Рассмотрим несложный пример определения переменных. Задача следующая: конвертировать URI запросов в нижний регистр. Например, /Uri -> /uri, /URI -> /uri, /TeSt -> /test.
Для решения задачи настроим переменную с изменённым URI через подпрограмму Perl:
http {
perl_set $my_uri_to_lowercase 'sub {
my $r = shift;
my $uri = $r->uri;
$uri = lc($uri);
return $uri;
}';
}
В директиве perl_set мы создаём переменную $my_uri_to_lowercase, которая будет содержать новый URI запроса. Для этого мы заносим в Perl‑переменную $uri исходный URI запроса и применяем к нему функцию lc — перевод в нижний регистр. Результат работы функции присваивается Angie‑переменной $my_uri_to_lowercase.
Использование новой переменной можно реализовать следующим образом: создаём локацию с для URI с символами в верхнем регистре и возвращаем редирект на новый URI из переменной:
server {
location ~ [A-Z] {
return 301 $scheme://$host$my_uri_to_lowercase;
}
}
На этом наша задача решена. Если требуется менять регистр не для всех запросов, локацию можно сделать вложенной.
Для реализации более сложных сценариев наверняка потребуется подключить дополнительные модули Perl (из CPAN). Сделать это можно директивой perl_require. Рассмотрим пример с подключением модуля и установкой обработчика запроса. Конфигурация Angie:
http {
perl_modules perl/lib;
perl_require hello.pm;
server {
location / {
perl hello::handler;
}
}
}
Здесь указывается директория для поиска Perl‑модулей (perl_modules) и подключается модуль hello.pm. В серверном блоке для локации определяется обработчик hello::handler — вызов функции handler из модуля hello.pm.
Код модуля Perl для обработчика (hello.pm):
package hello;
use nginx;
sub handler {
my $r = shift;
$r->send_http_header("text/html");
return OK if $r->header_only;
$r->print("hello!\n<br/>");
if (-f $r->filename or -d _) {
$r->print($r->uri, " exists!\n");
}
return OK;
}
1;
__END__
Основная часть модуля — функция обработчика запроса (handler). Она выводит текст «hello!» и в случае наличия файла или директории, совпадающих с URI, добавляет «$uri exists!».
Важно понимать, что Perl‑модуль работает в синхронном режиме, поэтому во время исполнения кода рабочий процесс не может обрабатывать другие запросы. По этой причине не рекомендуется реализовывать таким образом длительные операции с непредсказуемым временем ответа.
Модуль Lua
Сторонние модули позволяют использовать популярный скриптовый язык Lua в Angie. Мы рассмотрим базовые возможности модуля lua из комплекта фреймворка OpenResty.
При подключении модуля lua также необходим модуль NDK. Установка:
apt install angie-module-lua
Подключение модулей:
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_lua_module.so;
Для примера использования модуля будем использовать задачу записи тела запроса (request body) в лог-файл. Для этого определим соответствующий формат лога и дополнительную переменную:
http {
log_format bodylog '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" $request_time '
'<"$request_body" >"$resp_body"';
lua_need_request_body on;
body_filter_by_lua '
local resp_body = string.sub(ngx.arg[1], 1, 1000)
ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body
if ngx.arg[2] then
ngx.var.resp_body = ngx.ctx.buffered
end
';
server {
listen 80;
set $resp_body "";
access_log /var/log/nginx/server.log bodylog;
}
}
Этот код добавляет специальный формат лога и устанавливает директиву lua_need_request_body on, чтобы у Lua был доступ к телу запроса. Далее добавлен обработчик для тела запроса на Lua, задача которого — заполнить переменную в Angie ($resp_body). В данном примере размер ограничен 1000 байтами. Сама переменная объявляется на уровне блока сервера, и там же используется кастомный access_log.
В отличие от модуля Perl, Lua можно использовать как в контексте HTTP, так и в Stream. Кроме того, Lua позволяет создавать неблокирующий код для доступа к внешним системам. В общем, возможности модуля Lua широки и охватывают практически все аспекты работы с запросом и ответом в Angie.
Модуль NJS
Наконец, мы добрались до модуля NJS. Пожалуй, это самый естественный способ расширения функциональности для Angie. Дело в том, что NJS — подмножество языка JavaScript, специально адаптированное для использования в Nginx (а значит, и в Angie). Создание модуля NJS было обусловлено необходимостью создания гибких конфигураций сервера и нестандартных сценариев обработки запросов.
Модуль NJS поддерживает работу как в контексте HTTP, так и в Stream. Установка модуля стандартна:
apt install angie-module-lua
Подключение модуля, как обычно, производится в контексте main (существуют отдельные модули для http и stream):
load_module modules/ngx_http_js_module.so;
load_module modules/ngx_stream_js_module.so;
Для примера возьмём задачу перевода тела ответа в нижний регистр. Будем использовать код примеров из репозитория. Клонируем репозиторий в директорию /etc/angie:
cd /etc/angie
git clone https://github.com/nginx/njs-examples.git
В конфигурации сервера подключим файлы скриптов и обработчик NJS.
http {
js_path "/etc/angie/njs-examples/njs/";
js_import main from http/response/to_lower_case.js;
server {
listen 80;
location / {
js_body_filter main.to_lower_case;
proxy_pass http://localhost:8080;
}
}
server {
listen 8080;
location / {
return 200 'Hello World';
}
}
}
Директива js_path определяет директорию для поиска файлов njs-скриптов. Далее мы импортируем файл скрипта по относительному пути (код мы получили из репозитория).
Первый блок server (80 порт) отвечает за основную точку входа в наше импровизированное приложение. При этом в корневой локации подключён обработчик js_body_filter. Он будет вызывать функцию to_lower_case из файла to_lower_case.js для обработки тела ответа. Код скрипта максимально лаконичен:
function to_lower_case(r, data, flags) {
r.sendBuffer(data.toLowerCase(), flags);
}
export default {to_lower_case};
По сути, скрипт приводит к нижнему регистру любые входящие данные.
Второй блок server (8080) выступает бэкендом и отвечает на любой запрос фразой «Hello World».
При проверке такой конфигурации увидим эффект:
curl localhost
hello world
Возможности работы с запросами, ответами и заголовками здесь очень широкие. Для быстрого старта можно начать с примеров в эталонном репозитории модуля.
Итоги
Возможности Angie можно расширять за счет стандартных и сторонних модулей на базе ряда языков программирования. С помощью программной обработки можно преобразовывать заголовки, модифицировать ответ или запрос, создать собственную систему аутентификации. Наиболее близким по задумке к Angie является модуль NJS, так как он создавался специально для расширения возможностей сервера разработчиками Nginx. То есть, NJS в какой‑то степени позволяет создавать динамические модули для сервера без необходимости работать c внутренностями сервера Angie на языке C.
ExiTest
pingora