# *lua*: Suporte a scripts Lua para NGINX
## Instalação
Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:
* RedHat Enterprise Linux 7, 8, 9 e 10
* CentOS 7, 8, 9
* AlmaLinux 8, 9
* Rocky Linux 8, 9
* Amazon Linux 2 e Amazon Linux 2023
=== "CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023+"
```bash
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-lua
```
=== "CentOS/RHEL 7 e Amazon Linux 2"
```bash
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-lua
```
Ative o módulo adicionando o seguinte no início de `/etc/nginx/nginx.conf`:
```nginx
load_module modules/ngx_http_lua_module.so;
Este documento descreve o nginx-module-lua v0.10.31 lançado em 29 de maio de 2026.
-
Vídeo do YouTube "Hello World HTTP Example with OpenResty/Lua"
-
Vídeo do YouTube "Write Your Own Lua Modules in OpenResty/Nginx Applications"
-
Vídeo do YouTube "OpenResty's resty Command-Line Utility Demo"
-
Vídeo do YouTube "Measure Execution Time of Lua Code Correctly in OpenResty"
-
Vídeo do YouTube "Precompile Lua Modules into LuaJIT Bytecode to Speedup OpenResty Startup"
Sinta-se à vontade para se inscrever em nosso canal oficial do YouTube, OpenResty.
Sinopse
# defina os caminhos de busca para bibliotecas externas Lua puras (';;' é o caminho padrão):
# defina os caminhos de busca para bibliotecas externas Lua escritas em C (também pode usar ';;'):
server {
location /lua_content {
# tipo MIME determinado por default_type:
default_type 'text/plain';
content_by_lua_block {
ngx.say('Hello, world!')
}
}
location /nginx_var {
# tipo MIME determinado por default_type:
default_type 'text/plain';
# tente acessar /nginx_var?a=hello,world
content_by_lua_block {
ngx.say(ngx.var.arg_a)
}
}
location = /request_body {
client_max_body_size 50k;
client_body_buffer_size 50k;
content_by_lua_block {
ngx.req.read_body() -- lê explicitamente o corpo da requisição
local data = ngx.req.get_body_data()
if data then
ngx.say("body data:")
ngx.print(data)
return
end
-- o corpo pode ser armazenado em um arquivo temporário:
local file = ngx.req.get_body_file()
if file then
ngx.say("body is in file ", file)
else
ngx.say("no body found")
end
}
}
# I/O não bloqueante transparente em Lua via subrequisições
# (bem, uma maneira melhor é usar cosockets)
location = /lua {
# tipo MIME determinado por default_type:
default_type 'text/plain';
content_by_lua_block {
local res = ngx.location.capture("/some_other_location")
if res then
ngx.say("status: ", res.status)
ngx.say("body:")
ngx.print(res.body)
end
}
}
location = /foo {
rewrite_by_lua_block {
res = ngx.location.capture("/memc",
{ args = { cmd = "incr", key = ngx.var.uri } }
)
}
proxy_pass http://blah.blah.com;
}
location = /mixed {
rewrite_by_lua_file /path/to/rewrite.lua;
access_by_lua_file /path/to/access.lua;
content_by_lua_file /path/to/content.lua;
}
# use a variável nginx no caminho do código
# CUIDADO: conteúdos na var nginx devem ser cuidadosamente filtrados,
# caso contrário, haverá grande risco de segurança!
location ~ ^/app/([-_a-zA-Z0-9/]+) {
set $path $1;
content_by_lua_file /path/to/lua/app/root/$path.lua;
}
location / {
client_max_body_size 100k;
client_body_buffer_size 100k;
access_by_lua_block {
-- verifica se o endereço IP do cliente está na nossa lista negra
if ngx.var.remote_addr == "132.5.72.3" then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- verifica se a URI contém palavras proibidas
if ngx.var.uri and
string.match(ngx.var.request_body, "evil")
then
return ngx.redirect("/terms_of_use.html")
end
-- testes passaram
}
# configurações proxy_pass/fastcgi_pass/etc
}
}
Descrição
Este módulo embute LuaJIT 2.0/2.1 no Nginx. É um componente central do OpenResty. Se você está usando este módulo, então você está essencialmente usando OpenResty.
Desde a versão v0.10.16 deste módulo, o interpretador Lua padrão
(também conhecido como "PUC-Rio Lua") não é mais suportado. Este
documento usa de forma intercambiável os termos "Lua" e "LuaJIT" para se referir ao
interpretador LuaJIT.
Ao aproveitar as subrequisições do Nginx, este módulo permite a integração dos poderosos threads Lua (conhecidos como "corrotinas" Lua) no modelo de eventos do Nginx.
Diferente do mod_lua do Apache e do mod_magnet do Lighttpd, o código Lua executado usando este módulo pode ser 100% não bloqueante em tráfego de rede desde que a API do Nginx para Lua fornecida por este módulo seja usada para lidar com requisições a serviços upstream como MySQL, PostgreSQL, Memcached, Redis ou serviços web HTTP upstream.
Pelo menos as seguintes bibliotecas Lua e módulos Nginx podem ser usados com este módulo:
- lua-resty-memcached
- lua-resty-mysql
- lua-resty-redis
- lua-resty-dns
- lua-resty-upload
- lua-resty-websocket
- lua-resty-lock
- lua-resty-logger-socket
- lua-resty-lrucache
- lua-resty-string
- ngx_memc
- ngx_postgres
- ngx_redis2
- ngx_redis
- ngx_proxy
- ngx_fastcgi
Quase todos os módulos Nginx podem ser usados com este módulo ngx_lua por meio de
ngx.location.capture ou
ngx.location.capture_multi, mas é
recomendado usar essas bibliotecas lua-resty-* em vez de criar
subrequisições para acessar os módulos upstream do Nginx, pois as primeiras são geralmente
muito mais flexíveis e eficientes em termos de memória.
O interpretador Lua (também conhecido como "Estado Lua" ou "instância da VM LuaJIT") é compartilhado entre todas as requisições em um único processo worker do Nginx para minimizar o uso de memória. Os contextos de requisição são segregados usando corrotinas Lua leves.
Os módulos Lua carregados persistem no nível do processo worker do Nginx, resultando em uma pequena pegada de memória em Lua mesmo sob cargas pesadas.
Este módulo é integrado ao subsistema "http" do Nginx, portanto, só pode se comunicar com protocolos de comunicação downstream da família HTTP (HTTP 0.9/1.0/1.1/2.0, WebSockets, etc...). Se você deseja fazer comunicações TCP genéricas com os clientes downstream, deve usar o ngx_stream_lua módulo em vez disso, que oferece uma API Lua compatível.
Usos Típicos
Só para citar alguns:
- Mashup e processamento de saídas de várias saídas upstream do Nginx (proxy, drizzle, postgres, redis, memcached, etc.) em Lua,
- realizar controles de acesso e verificações de segurança arbitrariamente complexos em Lua antes que as requisições realmente cheguem aos backends upstream,
- manipular cabeçalhos de resposta de uma maneira arbitrária (por Lua)
- buscar informações de backend de armazenamentos externos (como redis, memcached, mysql, postgresql) e usar essas informações para escolher qual backend upstream acessar em tempo real,
- codificar aplicações web arbitrariamente complexas em um manipulador de conteúdo usando acesso síncrono, mas ainda não bloqueante, aos backends de banco de dados e outros armazenamentos,
- realizar um despacho de URL muito complexo em Lua na fase de reescrita,
- usar Lua para implementar mecanismos avançados de cache para as subrequisições do Nginx e locais arbitrários.
As possibilidades são ilimitadas, pois o módulo permite reunir vários elementos dentro do Nginx, além de expor o poder da linguagem Lua ao usuário. O módulo oferece total flexibilidade de scripting enquanto oferece níveis de desempenho comparáveis aos programas nativos em C, tanto em termos de tempo de CPU quanto de pegada de memória, graças ao LuaJIT 2.x.
Outras implementações de linguagens de script geralmente lutam para igualar esse nível de desempenho.
Compatibilidade com Nginx
A versão mais recente deste módulo é compatível com as seguintes versões do Nginx:
- 1.29.x (último testado: 1.29.8)
- 1.29.x (último testado: 1.29.2)
- 1.27.x (último testado: 1.27.1)
- 1.25.x (último testado: 1.25.1)
- 1.21.x (último testado: 1.21.4)
- 1.19.x (último testado: 1.19.3)
- 1.17.x (último testado: 1.17.8)
- 1.15.x (último testado: 1.15.8)
- 1.14.x
- 1.13.x (último testado: 1.13.6)
- 1.12.x
- 1.11.x (último testado: 1.11.2)
- 1.10.x
- 1.9.x (último testado: 1.9.15)
- 1.8.x
- 1.7.x (último testado: 1.7.10)
- 1.6.x
Os núcleos do Nginx anteriores a 1.6.0 (exclusivo) não são suportados.
Repositório de Código
O repositório de código deste projeto está hospedado no GitHub em openresty/lua-nginx-module.
Suporte a bytecode LuaJIT
Assista ao vídeo do YouTube "Measure Execution Time of Lua Code Correctly in OpenResty"
A partir do lançamento v0.5.0rc32, todos os diretivas de configuração *_by_lua_file (como content_by_lua_file) suportam o carregamento de arquivos de bytecode bruto LuaJIT 2.0/2.1 diretamente:
/path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc
A opção -bg pode ser usada para incluir informações de depuração no arquivo de bytecode LuaJIT:
/path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc
Consulte a documentação oficial do LuaJIT sobre a opção -b para mais detalhes:
https://luajit.org/running.html#opt_b
Observe que os arquivos de bytecode gerados pelo LuaJIT 2.1 não são compatíveis com LuaJIT 2.0, e vice-versa. O suporte para bytecode LuaJIT 2.1 foi adicionado pela primeira vez na versão ngx_lua v0.9.3.
Tentativas de carregar arquivos de bytecode padrão Lua 5.1 em instâncias ngx_lua vinculadas ao LuaJIT 2.0/2.1 (ou vice-versa) resultarão em uma mensagem de erro do Nginx como a abaixo:
[error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac
Carregar arquivos de bytecode via as primitivas Lua como require e
dofile deve sempre funcionar como esperado.
Suporte a Variáveis de Ambiente do Sistema
Se você deseja acessar a variável de ambiente do sistema, digamos, foo, em Lua através da API padrão Lua os.getenv, então você também deve listar este nome de variável de ambiente no seu arquivo nginx.conf através da diretiva env. Por exemplo,
env foo;
Suporte a HTTP 1.0
O protocolo HTTP 1.0 não suporta saída em partes e requer um cabeçalho Content-Length explícito quando o corpo da resposta não está vazio para suportar o keep-alive do HTTP 1.0.
Portanto, quando uma requisição HTTP 1.0 é feita e a diretiva lua_http10_buffering está ativada, ngx_lua irá armazenar em buffer a
saída das chamadas ngx.say e ngx.print e também adiar o envio dos cabeçalhos de resposta até que toda a saída do corpo da resposta seja recebida.
Nesse momento, ngx_lua pode calcular o comprimento total do corpo e construir um cabeçalho Content-Length apropriado para retornar ao cliente HTTP 1.0.
Se o cabeçalho de resposta Content-Length for definido no código Lua em execução, no entanto, esse buffering será desativado mesmo que a diretiva lua_http10_buffering esteja ativada.
Para grandes respostas de saída em streaming, é importante desativar a diretiva lua_http10_buffering para minimizar o uso de memória.
Observe que ferramentas comuns de benchmark HTTP, como ab e http_load, emitem requisições HTTP 1.0 por padrão.
Para forçar o curl a enviar requisições HTTP 1.0, use a opção -0.
Vinculação Estática de Módulos Lua Pura
Com LuaJIT 2.x, é possível vincular estaticamente o bytecode de módulos Lua puros ao executável do Nginx.
Você pode usar o executável luajit para compilar arquivos de módulo Lua .lua em arquivos de objeto .o contendo os dados de bytecode exportados, e então vincular os arquivos .o diretamente na sua construção do Nginx.
Abaixo está um exemplo trivial para demonstrar isso. Considere que temos o seguinte arquivo .lua chamado foo.lua:
-- foo.lua
local _M = {}
function _M.go()
print("Hello from foo")
end
return _M
E então compilamos este arquivo .lua para o arquivo foo.o:
/path/to/luajit/bin/luajit -bg foo.lua foo.o
O que importa aqui é o nome do arquivo .lua, que determina como você usará este módulo mais tarde no ambiente Lua. O nome do arquivo foo.o não importa, exceto pela extensão .o (que informa ao luajit qual formato de saída está sendo usado). Se você quiser remover as informações de depuração do bytecode Lua resultante, pode simplesmente especificar a opção -b acima em vez de -bg.
Então, ao construir o Nginx ou OpenResty, passe a opção --with-ld-opt="foo.o" para o script ./configure:
./configure --with-ld-opt="/path/to/foo.o" ...
Finalmente, você pode simplesmente fazer o seguinte em qualquer código Lua executado pelo ngx_lua:
local foo = require "foo"
foo.go()
E este trecho de código não depende mais do arquivo externo foo.lua, pois já foi compilado no executável nginx.
Se você quiser usar um ponto no nome do módulo Lua ao chamar require, como em
local foo = require "resty.foo"
então você precisa renomear o arquivo foo.lua para resty_foo.lua antes de compilá-lo em um arquivo .o com o utilitário de linha de comando luajit.
É importante usar exatamente a mesma versão do LuaJIT ao compilar arquivos .lua em arquivos .o que ao construir o nginx + ngx_lua. Isso ocorre porque o formato de bytecode do LuaJIT pode ser incompatível entre diferentes versões do LuaJIT. Quando o formato de bytecode é incompatível, você verá um erro de tempo de execução Lua dizendo que o módulo Lua não foi encontrado.
Quando você tem vários arquivos .lua para compilar e vincular, basta especificar seus arquivos .o ao mesmo tempo no valor da opção --with-ld-opt. Por exemplo,
./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ...
Se você tiver muitos arquivos .o, pode não ser viável nomeá-los todos em um único comando. Nesse caso, você pode construir uma biblioteca estática (ou arquivo de arquivo) para seus arquivos .o, como em
ar rcus libmyluafiles.a *.o
então você pode vincular o arquivo myluafiles como um todo ao seu executável do nginx:
./configure \
--with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive"
onde /path/to/lib é o caminho do diretório que contém o arquivo libmyluafiles.a. Deve-se notar que a opção do linker --whole-archive é necessária aqui, pois, caso contrário, nosso arquivo será ignorado porque nenhum símbolo em nosso arquivo é mencionado nas partes principais do executável do nginx.
Compartilhamento de Dados dentro de um Worker Nginx
Para compartilhar dados globalmente entre todas as requisições tratadas pelo mesmo processo worker do Nginx, encapsule os dados compartilhados em um módulo Lua, use o require embutido do Lua para importar o módulo e, em seguida, manipule os dados compartilhados em Lua. Isso funciona porque os módulos Lua requeridos são carregados apenas uma vez e todas as corrotinas compartilharão a mesma cópia do módulo (tanto seu código quanto seus dados).
Observe que o uso de variáveis globais Lua é fortemente desencorajado, pois pode levar a condições de corrida inesperadas entre requisições concorrentes.
Aqui está um pequeno exemplo de compartilhamento de dados dentro de um worker Nginx via um módulo Lua:
-- mydata.lua
local _M = {}
local data = {
dog = 3,
cat = 4,
pig = 5,
}
function _M.get_age(name)
return data[name]
end
return _M
E então acessando-o de nginx.conf:
location /lua {
content_by_lua_block {
local mydata = require "mydata"
ngx.say(mydata.get_age("dog"))
}
}
O módulo mydata neste exemplo será carregado e executado apenas na primeira requisição para a localização /lua,
e todas as requisições subsequentes para o mesmo processo worker do Nginx usarão a instância recarregada do
módulo, bem como a mesma cópia dos dados nele, até que um sinal HUP seja enviado ao processo mestre do Nginx para forçar um recarregamento.
Essa técnica de compartilhamento de dados é essencial para aplicações Lua de alto desempenho baseadas neste módulo.
Observe que esse compartilhamento de dados é por worker e não por servidor. Ou seja, quando há vários processos worker do Nginx sob um mestre do Nginx, o compartilhamento de dados não pode cruzar a fronteira de processo entre esses workers.
Geralmente é recomendado compartilhar dados somente leitura dessa forma. Você também pode compartilhar dados mutáveis entre todas as requisições concorrentes de cada processo worker do Nginx, desde que não haja operações de I/O não bloqueantes (incluindo ngx.sleep) no meio de seus cálculos. Desde que você não devolva o controle ao loop de eventos do Nginx e ao agendador de threads leves do ngx_lua (mesmo implicitamente), nunca haverá condições de corrida entre eles. Por esse motivo, tenha sempre muito cuidado quando quiser compartilhar dados mutáveis no nível do worker. Otimizações com bugs podem facilmente levar a condições de corrida difíceis de depurar sob carga.
Se o compartilhamento de dados em todo o servidor for necessário, use uma ou mais das seguintes abordagens:
- Use a API ngx.shared.DICT fornecida por este módulo.
- Use apenas um único worker do Nginx e um único servidor (isso, no entanto, não é recomendado quando há uma CPU multicore ou várias CPUs em uma única máquina).
- Use mecanismos de armazenamento de dados como
memcached,redis,MySQLouPostgreSQL. Os lançamentos oficiais do OpenResty vêm com um conjunto de módulos Nginx acompanhantes e bibliotecas Lua que fornecem interfaces com esses mecanismos de armazenamento de dados.
Problemas Conhecidos
Problemas de operação de conexão de soquete TCP
O método tcpsock:connect pode indicar sucesso apesar de falhas de conexão, como erros de Connection Refused.
No entanto, tentativas posteriores de manipular o objeto cosocket falharão e retornarão a mensagem de status de erro real gerada pela operação de conexão falhada.
Esse problema se deve a limitações no modelo de eventos do Nginx e parece afetar apenas o Mac OS X.
Yielding/Resuming de Corrotinas Lua
- Porque as funções embutidas
dofileerequiredo Lua estão atualmente implementadas como funções C no LuaJIT 2.0/2.1, se o arquivo Lua sendo carregado pordofileourequireinvocar ngx.location.capture*, ngx.exec, ngx.exit, ou outras funções da API que requerem yielding no escopo top-level do arquivo Lua, então o erro Lua "attempt to yield across C-call boundary" será levantado. Para evitar isso, coloque essas chamadas que requerem yielding em suas próprias funções Lua no arquivo Lua em vez do escopo de nível superior do arquivo.
Escopo de Variáveis Lua
Cuidados devem ser tomados ao importar módulos, e esta forma deve ser usada:
local xxx = require('xxx')
em vez da antiga forma depreciada:
require('xxx')
Aqui está o motivo: por design, o ambiente global tem exatamente a mesma duração que o manipulador de requisições do Nginx associado a ele. Cada manipulador de requisições tem seu próprio conjunto de variáveis globais Lua e essa é a ideia de isolamento de requisições. O módulo Lua é realmente carregado pelo primeiro manipulador de requisições do Nginx e é armazenado em cache pela função require() na tabela package.loaded para referência posterior, e a função module() usada por alguns módulos Lua tem o efeito colateral de definir uma variável global para a tabela do módulo carregado. Mas essa variável global será limpa no final do manipulador de requisições, e cada manipulador de requisições subsequente terá seu próprio ambiente global (limpo). Portanto, você receberá uma exceção Lua ao acessar o valor nil.
O uso de variáveis globais Lua é geralmente desaconselhável no contexto do ngx_lua, pois:
- o uso indevido de globais Lua tem efeitos colaterais prejudiciais em requisições concorrentes quando tais variáveis deveriam ser locais em escopo,
- variáveis globais Lua requerem buscas em tabelas Lua no ambiente global, o que é computacionalmente caro, e
- algumas referências a variáveis globais Lua podem incluir erros de digitação que dificultam a depuração.
Portanto, é altamente recomendado declarar sempre tais dentro de um escopo local apropriado.
-- Evitar
foo = 123
-- Recomendado
local foo = 123
-- Evitar
function foo() return 123 end
-- Recomendado
local function foo() return 123 end
Para encontrar todas as instâncias de variáveis globais Lua no seu código Lua, execute a ferramenta lua-releng em todos os arquivos fonte .lua:
$ lua-releng
Checking use of Lua global variables in file lib/foo/bar.lua ...
1 [1489] SETGLOBAL 7 -1 ; contains
55 [1506] GETGLOBAL 7 -3 ; setvar
3 [1545] GETGLOBAL 3 -4 ; varexpand
A saída diz que a linha 1489 do arquivo lib/foo/bar.lua escreve em uma variável global chamada contains, a linha 1506 lê da variável global setvar, e a linha 1545 lê a global varexpand.
Esta ferramenta garantirá que as variáveis locais nas funções do módulo Lua sejam todas declaradas com a palavra-chave local, caso contrário, uma exceção em tempo de execução será lançada. Isso previne condições de corrida indesejáveis ao acessar tais variáveis. Veja Compartilhamento de Dados dentro de um Worker Nginx para os motivos por trás disso.
Localizações Configuradas por Diretrizes de Subrequisições de Outros Módulos
As diretrizes ngx.location.capture e ngx.location.capture_multi não podem capturar localizações que incluem as diretrizes add_before_body, add_after_body, auth_request, echo_location, echo_location_async, echo_subrequest, ou echo_subrequest_async.
location /foo {
content_by_lua_block {
res = ngx.location.capture("/bar")
}
}
location /bar {
echo_location /blah;
}
location /blah {
echo "Success!";
}
$ curl -i http://example.com/foo
não funcionará como esperado.
Cosockets Não Disponíveis em Todos os Lugares
Devido a limitações internas no núcleo do Nginx, a API de cosocket está desativada nos seguintes contextos: set_by_lua*, log_by_lua*, header_filter_by_lua*, e body_filter_by_lua.
Os cosockets também estão atualmente desativados nos contextos das diretivas init_by_lua* e init_worker_by_lua*, mas podemos adicionar suporte para esses contextos no futuro, pois não há limitação no núcleo do Nginx (ou a limitação pode ser contornada).
No entanto, existe uma solução alternativa quando o contexto original não precisa esperar pelos resultados do cosocket. Ou seja, criando um temporizador de zero atraso via a API ngx.timer.at e fazendo os resultados do cosocket no manipulador do temporizador, que é executado de forma assíncrona em relação ao contexto original que cria o temporizador.
Sequências de Escape Especiais
NOTA Após o lançamento v0.9.17, essa armadilha pode ser evitada usando as diretivas de configuração *_by_lua_block {}.
Sequências PCRE como \d, \s, ou \w, requerem atenção especial porque em literais de string, o caractere de barra invertida, \, é removido tanto pelo analisador de linguagem Lua quanto pelo analisador do arquivo de configuração do Nginx antes do processamento, se não estiver dentro de uma diretiva *_by_lua_block {}. Portanto, o seguinte trecho não funcionará como esperado:
# nginx.conf
? location /test {
? content_by_lua '
? local regex = "\d+" -- ISTO ESTÁ ERRADO FORA DE UMA DIRETIVA *_by_lua_block
? local m = ngx.re.match("hello, 1234", regex)
? if m then ngx.say(m[0]) else ngx.say("not matched!") end
? ';
? }
# avalia para "not matched!"
Para evitar isso, escape duplamente a barra invertida:
# nginx.conf
location /test {
content_by_lua '
local regex = "\\\\d+"
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
';
}
# avalia para "1234"
Aqui, \\\\d+ é reduzido a \\d+ pelo analisador do arquivo de configuração do Nginx e isso é processado corretamente.
Alternativamente, o padrão regex pode ser apresentado como um literal de string Lua entre colchetes longos, [[...]], caso em que as barras invertidas precisam ser escapadas apenas uma vez para o analisador do arquivo de configuração do Nginx.
# nginx.conf
location /test {
content_by_lua '
local regex = [[\\d+]]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
';
}
# avalia para "1234"
Aqui, [[\\d+]] é reduzido a [[\d+]] pelo analisador do arquivo de configuração do Nginx e isso é processado corretamente.
Observe que uma forma mais longa do colchete longo, [=[...]=], pode ser necessária se o padrão regex contiver sequências [...].
A forma [=[...]=] pode ser usada como a forma padrão, se desejado.
# nginx.conf
location /test {
content_by_lua '
local regex = [=[[0-9]+]=]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
';
}
# avalia para "1234"
Uma abordagem alternativa para escapar sequências PCRE é garantir que o código Lua seja colocado em arquivos de script externos e executado usando as várias diretivas *_by_lua_file.
Com essa abordagem, as barras invertidas são removidas apenas pelo analisador de linguagem Lua e, portanto, precisam ser escapadas apenas uma vez cada.
-- test.lua
local regex = "\\d+"
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
-- avalia para "1234"
Dentro de arquivos de script externos, sequências PCRE apresentadas como literais de string Lua longas não requerem modificação.
-- test.lua
local regex = [[\d+]]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
-- avalia para "1234"
Como mencionado anteriormente, sequências PCRE apresentadas dentro de diretivas *_by_lua_block {} (disponíveis após o lançamento v0.9.17) não requerem modificação.
# nginx.conf
location /test {
content_by_lua_block {
local regex = [[\d+]]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
}
}
# avalia para "1234"
NOTA É recomendado usar by_lua_file quando o código Lua é muito longo.
Mistura com SSI Não Suportada
Misturar SSI com ngx_lua na mesma requisição Nginx não é suportado. Use apenas ngx_lua exclusivamente. Tudo o que você pode fazer com SSI pode ser feito em cima do ngx_lua de qualquer maneira e pode ser mais eficiente ao usar ngx_lua.
Modo SPDY Não Total ou Totalmente Suportado
Certas APIs Lua fornecidas pelo ngx_lua não funcionam no modo SPDY do Nginx ainda: ngx.location.capture, ngx.location.capture_multi, e ngx.req.socket.
Dados Ausentes em Requisições de Curto Circuito
O Nginx pode encerrar uma requisição cedo com (pelo menos):
- 400 (Bad Request)
- 405 (Not Allowed)
- 408 (Request Timeout)
- 413 (Request Entity Too Large)
- 414 (Request URI Too Large)
- 494 (Request Headers Too Large)
- 499 (Client Closed Request)
- 500 (Internal Server Error)
- 501 (Not Implemented)
Isso significa que fases que normalmente são executadas são puladas, como a fase de reescrita ou fase de acesso. Isso também significa que fases posteriores que são executadas independentemente, por exemplo, log_by_lua, não terão acesso a informações que normalmente são definidas nessas fases.
Mudanças
As mudanças feitas em cada lançamento deste módulo estão listadas nos logs de alterações do pacote OpenResty:
https://openresty.org/#Changes
Veja Também
Postagens de blog:
- Introdução aos Gráficos de Chama de CPU do Lua-Land
- Como OpenResty e Nginx Alocam e Gerenciam Memória
- Como OpenResty e Zonas de Memória Compartilhadas do Nginx Consomem RAM
- Fragmentação de Memória em OpenResty e Zonas de Memória Compartilhadas do Nginx
Outros módulos e bibliotecas relacionadas:
- ngx_stream_lua_module para uma porta oficial deste módulo para o subsistema "stream" do Nginx (fazendo comunicações TCP downstream genéricas).
- lua-resty-memcached biblioteca baseada no cosocket ngx_lua.
- lua-resty-redis biblioteca baseada no cosocket ngx_lua.
- lua-resty-mysql biblioteca baseada no cosocket ngx_lua.
- lua-resty-upload biblioteca baseada no cosocket ngx_lua.
- lua-resty-dns biblioteca baseada no cosocket ngx_lua.
- lua-resty-websocket biblioteca para servidor e cliente WebSocket, baseada no cosocket ngx_lua.
- lua-resty-string biblioteca baseada em LuaJIT FFI.
- lua-resty-lock biblioteca para uma API de bloqueio simples não bloqueante.
- lua-resty-cookie biblioteca para manipulação de cookies HTTP.
- Roteamento de requisições para diferentes consultas MySQL com base em argumentos URI
- Roteamento Dinâmico Baseado em Redis e Lua
- Usando LuaRocks com ngx_lua
- Introdução ao ngx_lua
- ngx_devel_kit
- echo-nginx-module
- drizzle-nginx-module
- postgres-nginx-module
- memc-nginx-module
- O pacote OpenResty
- Toolkit do Nginx Systemtap
Diretivas
- lua_load_resty_core
- lua_capture_error_log
- lua_use_default_type
- lua_malloc_trim
- lua_code_cache
- lua_thread_cache_max_entries
- lua_regex_cache_max_entries
- lua_regex_match_limit
- lua_package_path
- lua_package_cpath
- init_by_lua
- init_by_lua_block
- init_by_lua_file
- init_worker_by_lua
- init_worker_by_lua_block
- init_worker_by_lua_file
- exit_worker_by_lua_block
- exit_worker_by_lua_file
- set_by_lua
- set_by_lua_block
- set_by_lua_file
- precontent_by_lua_block
- precontent_by_lua_file
- content_by_lua
- content_by_lua_block
- content_by_lua_file
- server_rewrite_by_lua_block
- server_rewrite_by_lua_file
- rewrite_by_lua
- rewrite_by_lua_block
- rewrite_by_lua_file
- access_by_lua
- access_by_lua_block
- access_by_lua_file
- header_filter_by_lua
- header_filter_by_lua_block
- header_filter_by_lua_file
- body_filter_by_lua
- body_filter_by_lua_block
- body_filter_by_lua_file
- log_by_lua
- log_by_lua_block
- log_by_lua_file
- balancer_by_lua_block
- balancer_by_lua_file
- balancer_keepalive
- lua_need_request_body
- ssl_client_hello_by_lua_block
- ssl_client_hello_by_lua_file
- ssl_certificate_by_lua_block
- ssl_certificate_by_lua_file
- ssl_session_fetch_by_lua_block
- ssl_session_fetch_by_lua_file
- ssl_session_store_by_lua_block
- ssl_session_store_by_lua_file
- proxy_ssl_certificate_by_lua_block
- proxy_ssl_certificate_by_lua_file
- proxy_ssl_verify_by_lua_block
- proxy_ssl_verify_by_lua_file
- lua_shared_dict
- lua_socket_connect_timeout
- lua_socket_send_timeout
- lua_socket_send_lowat
- lua_socket_read_timeout
- lua_socket_buffer_size
- lua_socket_pool_size
- lua_socket_keepalive_timeout
- lua_socket_log_errors
- lua_ssl_ciphers
- lua_ssl_crl
- lua_ssl_protocols
- lua_ssl_certificate
- lua_ssl_certificate_key
- lua_ssl_trusted_certificate
- lua_ssl_verify_depth
- lua_ssl_key_log
- lua_ssl_conf_command
- lua_upstream_skip_openssl_default_verify
- lua_http10_buffering
- rewrite_by_lua_no_postpone
- access_by_lua_no_postpone
- precontent_by_lua_no_postpone
- lua_transform_underscores_in_response_headers
- lua_check_client_abort
- lua_max_pending_timers
- lua_max_running_timers
- lua_sa_restart
- lua_worker_thread_vm_pool_size
Os blocos básicos de construção de scripts Nginx com Lua são as diretivas. As diretivas são usadas para especificar quando o código Lua do usuário é executado e como o resultado será usado. Abaixo está um diagrama mostrando a ordem em que as diretivas são executadas.

lua_load_resty_core
sintaxe: lua_load_resty_core on|off
padrão: lua_load_resty_core on
contexto: http
Esta diretiva está depreciada desde o lançamento v0.10.16 deste
módulo. O módulo resty.core do
lua-resty-core agora é carregado obrigatoriamente
durante a inicialização da VM Lua. Especificar esta diretiva não terá
efeito.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.10.15 e
era usada para carregar opcionalmente o módulo resty.core.
lua_capture_error_log
sintaxe: lua_capture_error_log size
padrão: nenhum
contexto: http
Habilita um buffer do tamanho especificado para capturar todos os dados de mensagens de log de erro do Nginx (não apenas aqueles produzidos por este módulo ou pelo subsistema http do Nginx, mas tudo) sem tocar em arquivos ou discos.
Você pode usar unidades como k e m no valor de size, como em
lua_capture_error_log 100k;
Como regra geral, um buffer de 4KB pode geralmente conter cerca de 20 mensagens de log de erro típicas. Então faça as contas!
Esse buffer nunca cresce. Se estiver cheio, novas mensagens de log de erro substituirão as mais antigas no buffer.
O tamanho do buffer deve ser maior que o comprimento máximo de uma única mensagem de log de erro (que é 4K no OpenResty e 2K no NGINX padrão).
Você pode ler as mensagens no buffer na área Lua através da função get_logs() do módulo ngx.errlog da biblioteca lua-resty-core. Essa função da API Lua retornará as mensagens de log de erro capturadas e também removerá essas já lidas do buffer de captura global, abrindo espaço para quaisquer novos dados de log de erro. Por esse motivo, o usuário não deve configurar esse buffer para ser muito grande se o usuário ler os dados de log de erro em buffer rapidamente.
Observe que o nível de log especificado na diretiva padrão error_log tem efeito sobre essa instalação de captura. Ele captura apenas mensagens de log de um nível não inferior ao nível de log especificado na diretiva error_log. O usuário ainda pode escolher definir um nível de filtragem de log ainda mais alto dinamicamente através da função da API Lua errlog.set_filter_level. Portanto, é mais flexível do que a diretiva estática error_log.
Vale a pena notar que não há como capturar os logs de depuração
sem construir o OpenResty ou o Nginx com a opção ./configure
--with-debug. E habilitar logs de depuração é
fortemente desencorajado em builds de produção devido ao alto overhead.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.10.9.
lua_use_default_type
sintaxe: lua_use_default_type on | off
padrão: lua_use_default_type on
contexto: http, server, location, location if
Especifica se deve usar o tipo MIME especificado pela diretiva default_type para o valor padrão do cabeçalho de resposta Content-Type. Desative esta diretiva se um cabeçalho de resposta Content-Type padrão para manipuladores de requisições Lua não for desejado.
Esta diretiva está ativada por padrão.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.9.1.
lua_malloc_trim
sintaxe: lua_malloc_trim <contagem-de-requisições>
padrão: lua_malloc_trim 1000
contexto: http
Pede à biblioteca de tempo de execução libc subjacente para liberar sua memória livre em cache de volta ao sistema operacional a cada
N requisições processadas pelo núcleo do Nginx. Por padrão, N é 1000. Você pode configurar a contagem de requisições
usando seus próprios números. Números menores significam liberações mais frequentes, o que pode introduzir um maior consumo de tempo de CPU e
uma pegada de memória menor, enquanto números maiores geralmente levam a menos sobrecarga de tempo de CPU e uma pegada de memória relativamente maior.
Ajuste o número para seus próprios casos de uso.
Configurar o argumento para 0 desativa essencialmente a limpeza periódica de memória completamente.
lua_malloc_trim 0; # desativa a limpeza completamente
A implementação atual usa um manipulador de fase de log do Nginx para contar as requisições. Portanto, a aparência das
diretivas log_subrequest on em nginx.conf
pode acelerar a contagem quando subrequisições estão envolvidas. Por padrão, apenas "requisições principais" contam.
Observe que esta diretiva não afeta a memória alocada pelo próprio alocador do LuaJIT baseado na chamada de sistema mmap.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.10.7.
lua_code_cache
sintaxe: lua_code_cache on | off
padrão: lua_code_cache on
contexto: http, server, location, location if
Habilita ou desabilita o cache de código Lua para código Lua nas diretivas *_by_lua_file (como set_by_lua_file e
content_by_lua_file) e módulos Lua.
Ao desligar, cada requisição servida pelo ngx_lua será executada em uma instância separada da VM Lua, começando a partir do lançamento 0.9.3. Portanto, os arquivos Lua referenciados em set_by_lua_file,
content_by_lua_file, access_by_lua_file,
e etc não serão armazenados em cache
e todos os módulos Lua usados serão carregados do zero. Com isso, os desenvolvedores podem adotar uma abordagem de edição e atualização.
Observe, no entanto, que o código Lua escrito embutido dentro do nginx.conf
como aqueles especificados por set_by_lua, content_by_lua,
access_by_lua, e rewrite_by_lua não será atualizado quando você editar o código Lua embutido em seu arquivo nginx.conf porque apenas o analisador de arquivos de configuração do Nginx pode analisar corretamente o arquivo nginx.conf
e a única maneira é recarregar o arquivo de configuração
enviando um sinal HUP ou apenas reiniciar o Nginx.
Mesmo quando o cache de código está habilitado, arquivos Lua que são carregados por dofile ou loadfile
em *_by_lua_file não podem ser armazenados em cache (a menos que você armazene os resultados você mesmo). Normalmente, você pode usar a diretiva init_by_lua
ou init_by_lua_file para carregar todos esses arquivos ou apenas tornar esses arquivos Lua módulos reais
e carregá-los via require.
O módulo ngx_lua não suporta o modo stat disponível com o
módulo Apache mod_lua (ainda).
Desabilitar o cache de código Lua é fortemente desencorajado para uso em produção e deve ser usado apenas durante o desenvolvimento, pois tem um impacto negativo significativo no desempenho geral. Por exemplo, o desempenho de um exemplo Lua "hello world" pode cair em uma ordem de magnitude após desabilitar o cache de código Lua.
lua_thread_cache_max_entries
sintaxe: lua_thread_cache_max_entries <num>
padrão: lua_thread_cache_max_entries 1024
contexto: http
Especifica o número máximo de entradas permitidas no cache de objetos de thread Lua no nível do processo worker.
Esse cache recicla os objetos GC da thread Lua entre todos os nossos "threads leves".
Um valor zero de <num> desativa o cache.
Observe que esse recurso requer o LuaJIT do OpenResty com a nova API C lua_resetthread.
Esse recurso foi introduzido pela primeira vez na versão v0.10.9.
lua_regex_cache_max_entries
sintaxe: lua_regex_cache_max_entries <num>
padrão: lua_regex_cache_max_entries 1024
contexto: http
Especifica o número máximo de entradas permitidas no cache de regex compilados no nível do processo worker.
As expressões regulares usadas em ngx.re.match, ngx.re.gmatch, ngx.re.sub, e ngx.re.gsub serão armazenadas em cache dentro deste cache se a opção regex o (ou seja, flag compile-once) for especificada.
O número padrão de entradas permitidas é 1024 e quando esse limite é atingido, novas expressões regulares não serão armazenadas em cache (como se a opção o não tivesse sido especificada) e haverá um aviso, e apenas um, no arquivo error.log:
2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ...
Se você estiver usando a implementação ngx.re.* da biblioteca lua-resty-core carregando o módulo resty.core.regex (ou apenas o módulo resty.core), então um cache LRU é usado para o cache de regex que está sendo usado aqui.
Não ative a opção o para expressões regulares (e/ou argumentos de string replace para ngx.re.sub e ngx.re.gsub) que são geradas on the fly e dão origem a variações infinitas para evitar atingir o limite especificado.
lua_regex_match_limit
sintaxe: lua_regex_match_limit <num>
padrão: lua_regex_match_limit 0
contexto: http
Especifica o "limite de correspondência" usado pela biblioteca PCRE ao executar a API ngx.re. Para citar a página man do PCRE, "o limite ... tem o efeito de limitar a quantidade de retrocesso que pode ocorrer."
Quando o limite é atingido, a string de erro "pcre_exec() failed: -8" será retornada pelas funções da API ngx.re.
Ao definir o limite como 0, o "limite de correspondência" padrão ao compilar a biblioteca PCRE é usado. E este é o valor padrão desta diretiva.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.8.5.
lua_package_path
sintaxe: lua_package_path <lua-style-path-str>
padrão: O conteúdo da variável de ambiente LUA_PATH ou os padrões compilados do Lua.
contexto: http
Define o caminho de busca de módulos Lua usado por scripts especificados por set_by_lua,
content_by_lua e outros. A string do caminho está na forma padrão do caminho Lua, e ;;
pode ser usado para representar os caminhos de busca originais.
A partir do lançamento v0.5.0rc29, a notação especial $prefix ou ${prefix} pode ser usada na string do caminho de busca para indicar o caminho do prefixo do servidor, geralmente determinado pela opção de linha de comando -p PATH ao iniciar o servidor Nginx.
lua_package_cpath
sintaxe: lua_package_cpath <lua-style-cpath-str>
padrão: O conteúdo da variável de ambiente LUA_CPATH ou os padrões compilados do Lua.
contexto: http
Define o caminho de busca de módulos C Lua usado por scripts especificados por set_by_lua,
content_by_lua e outros. A string cpath está na forma padrão do cpath Lua, e ;;
pode ser usado para representar o cpath original.
A partir do lançamento v0.5.0rc29, a notação especial $prefix ou ${prefix} pode ser usada na string do caminho de busca para indicar o caminho do prefixo do servidor, geralmente determinado pela opção de linha de comando -p PATH ao iniciar o servidor Nginx.
init_by_lua
sintaxe: init_by_lua <lua-script-str>
contexto: http
fase: loading-config
NOTA O uso desta diretiva é desencorajado após o lançamento v0.9.17. Use a diretiva init_by_lua_block em vez disso.
Semelhante à diretiva init_by_lua_block, mas aceita o código fonte Lua diretamente em um literal de string Nginx (o que requer escape de caracteres especiais).
Por exemplo,
init_by_lua '
print("I need no extra escaping here, for example: \r\nblah")
'
Esta diretiva foi introduzida pela primeira vez no lançamento v0.5.5.
init_by_lua_block
sintaxe: init_by_lua_block { lua-script }
contexto: http
fase: loading-config
Quando o Nginx recebe o sinal HUP e começa a recarregar o arquivo de configuração, a VM Lua também será recriada e init_by_lua_block será executado novamente na nova VM Lua. Caso a diretiva lua_code_cache esteja desligada (ativada por padrão), o manipulador init_by_lua_block será executado a cada requisição porque, nesse modo especial, uma VM Lua autônoma é sempre criada para cada requisição.
Normalmente, você pode pré-carregar módulos Lua na inicialização do servidor por meio deste gancho e aproveitar a otimização de cópia sob demanda (COW) dos sistemas operacionais modernos. Aqui está um exemplo para pré-carregar módulos Lua:
# isso é executado antes de criar processos worker do nginx:
init_by_lua_block { require "cjson" }
server {
location = /api {
content_by_lua_block {
-- o seguinte require() apenas retornará
-- o módulo já carregado de package.loaded:
ngx.say(require "cjson".encode{dog = 5, cat = 6})
}
}
}
Você também pode inicializar o armazenamento shm lua_shared_dict nesta fase. Aqui está um exemplo para isso:
lua_shared_dict dogs 1m;
init_by_lua_block {
local dogs = ngx.shared.dogs
dogs:set("Tom", 56)
}
server {
location = /api {
content_by_lua_block {
local dogs = ngx.shared.dogs
ngx.say(dogs:get("Tom"))
}
}
}
Mas note que o armazenamento shm do lua_shared_dict não será limpo através de um recarregamento de configuração (via sinal HUP, por exemplo). Portanto, se você não quiser reinicializar o armazenamento shm no seu código init_by_lua_block nesse caso, você só precisa definir uma flag personalizada no armazenamento shm e sempre verificar a flag no seu código init_by_lua_block.
Como o código Lua neste contexto é executado antes que o Nginx fork seus processos workers (se houver), os dados ou códigos carregados aqui desfrutarão do recurso de Cópia sob Demanda (COW) fornecido por muitos sistemas operacionais entre todos os processos workers, economizando assim muita memória.
Não inicialize suas próprias variáveis globais Lua neste contexto, pois o uso de variáveis globais Lua tem penalidades de desempenho e pode levar à poluição do namespace global (veja a seção Escopo de Variáveis Lua para mais detalhes). A maneira recomendada é usar arquivos de módulo Lua apropriados (mas não use a função padrão Lua module() para definir módulos Lua porque também polui o namespace global) e chamar require() para carregar seus próprios arquivos de módulo em init_by_lua_block ou outros contextos (require() armazena em cache os módulos Lua carregados na tabela global package.loaded no registro Lua, então seus módulos serão carregados apenas uma vez para toda a instância da VM Lua).
Apenas um pequeno conjunto da API do Nginx para Lua é suportado neste contexto:
- APIs de Log: ngx.log e print,
- API de Dicionário Compartilhado: ngx.shared.DICT.
Mais APIs do Nginx para Lua podem ser suportadas neste contexto mediante solicitações futuras dos usuários.
Basicamente, você pode usar com segurança bibliotecas Lua que fazem I/O bloqueante neste contexto, pois bloquear o processo mestre durante a inicialização do servidor é completamente aceitável. Mesmo o núcleo do Nginx faz I/O bloqueante (pelo menos na resolução de nomes de hosts upstream) na fase de carregamento de configuração.
Você deve ter muito cuidado com potenciais vulnerabilidades de segurança em seu código Lua registrado neste contexto, pois o processo mestre do Nginx é frequentemente executado sob a conta root.
Esta diretiva foi introduzida pela primeira vez no lançamento v0.9.17.
Veja também as seguintes postagens de blog para mais detalhes sobre as zonas de memória compartilhadas do OpenResty e do Nginx:
- Como OpenResty e Zonas de Memória Compartilhadas do Nginx Consomem RAM
- Fragmentação de Memória em OpenResty e Zonas de Memória Compartilhadas do Nginx
init_worker_by_lua
sintaxe: init_worker_by_lua <lua-script-str>
contexto: http
fase: starting-worker
NOTA O uso desta diretiva é desencorajado após o lançamento v0.9.17. Use a diretiva init_worker_by_lua_block em vez disso.
Semelhante à diretiva init_worker_by_lua_block, mas aceita o código fonte Lua diretamente em um literal de string Nginx (o que requer escape de caracteres especiais).
Por exemplo,
init_worker_by_lua '
print("I need no extra escaping here, for example: \r\nblah")
';
Esta diretiva foi introduzida pela primeira vez no lançamento v0.9.5.
init_worker_by_lua_block
sintaxe: init_worker_by_lua_block { lua-script }
contexto: http
fase: starting-worker
Executa o código Lua especificado em cada inicialização do processo worker do Nginx quando o processo mestre está habilitado. Quando o processo mestre está desabilitado, este gancho será executado após init_by_lua*.
Este gancho é frequentemente usado para criar temporizadores recorrentes por worker (via a API ngx.timer.at), seja para verificação de saúde de backend ou outros trabalhos de rotina temporizados. Abaixo está um exemplo,
init_worker_by_lua_block {
local delay = 3 -- em segundos
local new_timer = ngx.timer.at
local log = ngx.log
local ERR = ngx.ERR
local check
check = function(premature)
if not premature then
-- faça a verificação de saúde ou outro trabalho rotineiro
local ok, err = new_timer(delay, check)
if not ok then
log(ERR, "failed to create timer: ", err)
return
end
end
-- faça algo no temporizador
end
local hdl, err = new_timer(delay, check)
if not hdl then
log(ERR, "failed to create timer: ", err)
return
end
-- outro trabalho em init_worker_by_lua
}
Esta diretiva foi introduzida pela primeira vez no lançamento v0.9.17.
Este gancho não é mais executado nos processos de gerenciador de cache e carregador de cache desde o lançamento v0.10.12.
exit_worker_by_lua_block
sintaxe: exit_worker_by_lua_block { lua-script }
contexto: http
fase: exiting-worker
Executa o código Lua especificado em cada saída do processo worker do Nginx quando o processo mestre está habilitado. Quando o processo mestre está desabilitado, este gancho será executado antes que o processo Nginx saia.
Este




