Pular para conteúdo
# *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.


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()  --  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:

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"

Precompile Lua Modules into LuaJIT Bytecode to Speedup OpenResty Startup

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:

  1. Use a API ngx.shared.DICT fornecida por este módulo.
  2. 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).
  3. Use mecanismos de armazenamento de dados como memcached, redis, MySQL ou PostgreSQL. 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 dofile e require do Lua estão atualmente implementadas como funções C no LuaJIT 2.0/2.1, se o arquivo Lua sendo carregado por dofile ou require invocar 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:

  1. o uso indevido de globais Lua tem efeitos colaterais prejudiciais em requisições concorrentes quando tais variáveis deveriam ser locais em escopo,
  2. variáveis globais Lua requerem buscas em tabelas Lua no ambiente global, o que é computacionalmente caro, e
  3. 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:

Outros módulos e bibliotecas relacionadas:

Diretivas

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.

Diretivas de Módulos Lua Nginx

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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  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:

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:

Voltar ao TOC

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.

Voltar ao TOC

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.

Voltar ao TOC

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