Is it possible to have live reloading of lua scripts using openresty and docker? - nginx

I'm newish to LUA and want to practice some LUA scripting using nginx/openrestry.
Is there a workflow where I can use docker that runs openresty, and link my laptops filesystem to my docker container such that when I make a change to my lua script, I can quickly reload openrestry server so I can quickly see my lua changes take effect?
Any help or guidance would be appreciated.

You can disable Lua code cache — https://github.com/openresty/lua-nginx-module#lua_code_cache — add lua_code_cache off inside the http or server directive block. This is not actually “hot reload”, it's more like php request lifecycle:
every request served by ngx_lua will run in a separate Lua VM instance
You can think of it as if the code is hot–reloaded on each request.
However, pay attention to this:
Please note however, that Lua code written inlined within nginx.conf [...] will not be updated
It means that you should move all your Lua code from the nginx config to Lua modules and only require them:
server {
lua_code_cache off;
location /foo {
content_by_lua_block {
-- OK, the module will be imported (recompiled) on each request
require('mymodule').do_foo()
}
}
location /bar {
content_by_lua_block {
-- Bad, this inlined code won't be reloaded unless nginx is reloaded.
-- Move this code to a function inside a Lua module
-- (e.g., `mymodule.lua`).
local method = ngx.req.get_method()
if method == 'GET' then
-- handle GET
elseif method == 'POST' then
-- handle POST
else
return ngx.exit(ngx.HTTP_NOT_ALLOWED)
end
}
}
}
Then you can mount your Lua code from the host to the container using --mount or --volume: https://docs.docker.com/storage/bind-mounts/

Related

'init_by_lua_block' directive not getting executed on nginx start

I wanted one of my lua script to get executed whenever nginx server starts or is reloaded. I tried using init_by_lua_block and init_by_lua_file directive but i dont see any log traces for the lua script in init_by_lua_block when i run the nginx docker. My http block looks like below. nginx.config is located in container path/etc/nginx/nginx.conf .
http {
sendfile on;
init_by_lua_block /etc/nginx/lua/init.lua;
include /etc/nginx/conf.d/proxy-config.conf;
}
Can anyone please tell me what I am missing here?
init_by_lua_block
syntax: init_by_lua_block { lua-script }
https://github.com/openresty/lua-nginx-module#init_by_lua_block
init_by_lua_block expects inlined Lua code, not a path to the Lua file.
Use dofile to execute Lua script:
init_by_lua_block {
dofile('/etc/nginx/lua/init.lua')
}
https://www.lua.org/manual/5.1/manual.html#pdf-dofile
or use init_by_lua_file:
init_by_lua_file /etc/nginx/lua/init.lua;
UPD:
You should use the NOTICE logging level (or higher) in init_by_lua_* directives because your error_log configuration is not yet applied in this phase:
Under the hood, the init_by_lua runs in the nginx configuration loading phase, so your error_log configuration in nginx.conf does not take effect until the whole configuration is loaded successfully (due to the bootstrapping requirements: the configuration loading MAY fail). And nginx initially uses a logger with the NOTICE filtering level upon startup which is effect in the whole first configuration loading process (but not subsequent configuration (re)loading triggered by the HUP signal).
https://github.com/openresty/lua-nginx-module/issues/467#issuecomment-82647228
So, use ngx.log(ngx.NOTICE, ...) (or ngx.WARN, ngx.ERR, etc. — see https://github.com/openresty/lua-nginx-module#nginx-log-level-constants) to see the output in the log.
Alternatively you can use print. It's equivalent to ngx.log(ngx.NOTICE, ...) under the hood: https://github.com/openresty/lua-nginx-module#print

How to get lua variables back into nginx variables

I have a lua script that uses lua-resty to call another service via co-sockets.
Now I would like to use the information from this call to route the request in nginx.
nginx includes the lua script in access_by_lua*
which sets the var like this:
ngx.var.blocked = '1'
and routes in the location like this:
if ( $blocked ) {
proxy_pass http://haproxy-9001;
break;
}
the problem is now that nginx does not pick up the variable change (in this phase).
if I include the lua script in set_by_lua* phase then the variable passing works but I dont have access to the co-sockets in this phase.
Any idea how to get the variable out of lua land into the nginx variable in the access_by_lua, rewrite_by_lua or content_by_lua phase so that I can use the co-socket api to make a http call?
if nginx directive is implemented by https://nginx.ru/en/docs/http/ngx_http_rewrite_module.html.
Obviously it works on rewrite phase, so your changes at access phase doesn't work.
Just don't use if. Below is snippet from one of my nginx config:
proxy_pass $scheme://$upstream$uri$is_args$args;
Just set $upstream variable at access phase and it will work at content phase (proxy_pass).
Maybe you could capture location with that proxy instead of variable, it works in access_by_lua scope
https://github.com/openresty/lua-nginx-module#ngxlocationcapture

How to call a Lua method on startup in NGINX?

I'm using Lua with NGINX. My code has a lua method called "rabbitmq.createExchange". I want to call this method, when nginx server starts.
I tried following code, but i failed with error "content_by_lua_block directive is not allowed here". Any solutions?
http {
lua_package_path '/app/nginx/src/?.lua;;';
server {
listen 4000;
include 'src/proj1.conf';
}
content_by_lua_block {
local rabbitmq = require 'src/rabbitmq.lua';
rabbitmq.createExchange("nginx", "topic");
}
}
You probably want init_by_lua_block - the content_by_lua_block directive is specifically for responding to a particular location, whereas the init_ version is for startup:
init_by_lua_block
syntax: init_by_lua_block { lua-script }
context: http
phase: loading-config
Similar to the init_by_lua directive except that this
directive inlines the Lua source directly inside a pair of curly
braces ({}) instead of in an NGINX string literal (which requires
special character escaping).
For instance,
init_by_lua_block {
print("I need no extra escaping here, for example: \r\nblah") }
(From the init_by_lua section, "Runs the Lua code [...] on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file.")

Sending multiple html files to a web client with HttpLuaModule‎

When I run this script, only the header is displayed:
ngx.exec('/header.html')
ngx.exec('/footer.html')
What's the best way to serve my template?
I've also tried this:
local f = io.read('/header.html','r')
ngx.print(f)
but I can't seem to get past a 404 error.
Your description is not very clear, but
ngx.exec() allows you to access a location with args.
If you want to show the html file, you can write a lua script and use the content_by_lua_file command.
Nginx config:
locaction /test {
default_type "text/plain";
content_by_lua_file "x.lua";
}
Lua Script:
local ngx = require 'ngx'
local f = io.open('header.html', 'r')
local html_text = f:read()
ngx.print(html_text)
You can access 127.0.0.1/test through the nginx server
and see your html file now.

Lua's package path in nginx

I am now programming in Lua with nginx. I write my Lua file and place it in a directory in /usr/local/nginx/lua. Then in nginx.conf I write a location, such as
location /lua {
lua_need_request_body on;
content_by_lua_file lua/test.lua;
}
When I access this location through Nginx, the Lua script will be executed.
In a Lua file, one usually can include your own Lua module, and indicate the search path
common_path = '../include/?.lua;'
package.path = common_path .. package.path
In common Lua programming, a relative path is relative to my Lua file.
But with nginx, the relative paths are relative to the directory where I start Nginx.
Like, I am in /usr/local/nginx and execute sbin/nginx, then in Lua package.path will be the /usr/local/include.
If I am in /usr/local/nginx/sbin and execute ./nginx, then in Lua package.path will be /usr/local/nginx/include.
I think the directory I start the nginx server should not been limited,
but I don't know how to resolve this.
You want to modify the Lua package.path to search in the directory where you have your source code. For you, that's lua/.
You do this with the lua_package_path directive, in the http block (the docs say you can put it in the top level, but when I tried that it didn't work).
So for you:
http {
#the scripts in lua/ need to refer to each other
#but the server runs in lua/..
lua_package_path "./lua/?.lua;;";
...
}
Now your lua scripts can find each other even though the server runs one directory up.
You can use $prefix now.
For example
http{
lua_package_path "$prefix/lua/?.lua;;";
}
And start your nginx like this
nginx -p /opt -c /etc/nginx.conf
Then the search path will be
/opt/lua

Resources