Exchanging variables between LUA directives in NGINX - nginx

I am using HttpLuaModule for my NGINX server. I want to ask if it is possible to recognize variable in different directives of this module. For example
init_by_lua ' local global_var = 5 ' ;
some config ;
set_by_lua ' print(global_var) ' ;
How is that possible with NGINX and LUA module ?

If you want global_var to be global, don't declare it as local.
From a quick look at NGINX's docs, init_by_lua and set_by_lua work on the same global Lua state and so you'll be able to make them talk if you use global variables. Local variables set in init_by_lua will be lost.
So, it should work if you just remove local in init_by_lua.

Related

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

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/

NGINX lua use secure_link_md5 from env var

I'm using NGINX with lua support to accesses hostnames and other App releated variables from my .env file.
Now i wanted to use the secure_link_md5 var. from a .env file but i dont understand how to put together the string so that nginx can understand it.
This is how my nginx config looks like:
env LINK_SECRET;
set_by_lua $curr_dl_link_secret 'return os.getenv("LINK_SECRET")'; # Needs to be set correctly
secure_link_md5 = "${curr_dl_link_secret}$uri$secure_link_expires";
Normaly i would set the config line like that without the use of lua and env vars:
secure_link_md5 "XGc7YyXERjiSvs4PtzpnBMANuFd22VAmXDc66g6JU$uri$secure_link_expires";
Currently NGINX always returns the following error:
invalid number of arguments in "secure_link_md5"
NGINX counts "=" as an argument. I am not familiar with NGINX with lua, but I think "{}" are also unnecessary.
I guess you want something like this:
secure_link_md5 "$curr_dl_link_secret$uri$secure_link_expires";

Use Environment Variable or Parameter in nginx.conf

I try to add a proxy_pass in the nginx.conf like
location /example/ {
proxy_pass http://example.com;
}
But instead of hard coding http://example.com in the conf file I want to have this value in an environment variable.
How can I use environment variables in nginx.conf? Or is there a better way with nginx no have external configuration?
If you want pure environment variables into nginx config, you will need implements some code in Lua Language:
https://blog.doismellburning.co.uk/environment-variables-in-nginx-config/
If you don't have a high load on this NGinx, I recommend implements this above solution.
In my specific case, to reduce CPU load, I prefer to use separated files with variables and a script in rc.local (or dockerfile) to change these files when launch the machine.
conf.d/exemple.conf
include backends/exemple.host;
location ~ ^/exemple {
proxy_pass $exemple;
}
backends/exemple.host
set $exemple {BACKEND};
rc.local
sed -i "s#set \$exemple.*#set \$exemple $HOSTNAME\;#" /etc/nginx/backends/exemple.host
To the last solution works, I need change the NGinx start order on O.S.
You can use lua.
ex:
set_by_lua $curr_domain_name 'return os.getenv("DOMAIN")';
add_header Content-Security-Policy 'script-src ${curr_domain_name}';
This worked for me.

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

Nginx variable for physical server name

I'm trying to setup response headers on my separate webservers that outputs the physical name of the machine that nginx is running on, so that I can tell which servers are serving the responses to our web clients.
Is there a variable that exists to do this already? Or do I just have to hardcode it per-server :(
You're after the $hostname common variable. Common variables are listed in the variable index.
The nginx access log documentation only shows variables that are specific to the access log:
The log format can contain common variables, and variables that exist
only at the time of a log write.
I guess you're looking for $hostname variable.
At first I thought the answer was to use the ENV variable and pull out the hostname from there https://docs.apitools.com/blog/2014/07/02/using-environment-variables-in-nginx-conf.html. But I couldn't get it to work for some reason.
However, this works like a charm:
perl_set $server_int 'sub { use Sys::Hostname; return hostname; }';
And example usage:
add_header 'Server-Int' "$server_int";
Just have to make sure your nginx is compiled with --with-http_perl_module - just run nginx -V to make sure. And that you have Sys::Hostname installed.
Warning: I at first used hostname to return the hostname in the Perl script, but while that did return the name, it for some reason aborted the rest of the output. I don't know if it's a bug with perl_set but you've been warned - using backticks in perl_set may be deadly.

Resources