How to get lua variables back into nginx variables - nginx

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

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/

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.

Avoid redirect cycle when combining access_by_lua with ngx.exec to a (named) location

I want to change an existing nginx configuration in a way where I can completely "mask" the configuration and proxy everything to the upstream when a certain cookie is available (to hide a certain server).
This includes not just some location directives but basically every location directive (as opposed to set or map a variable and update n-location's try_files and more).
My basic idea was to use lua and jump into the Rewrite/Access phase like this:
access_by_lua_block {
# proceed as usual if our cookie is not detected
if ngx.var.cookie_demo ~= nil and string.len(ngx.var.cookie_demo) ~= 32 then
return
end
# proxy and return w/out further processing
ngx.exec("#ngxbackend")
return ngx.exit(ngx.HTTP_OK)
}
# proxy upstream
location #ngxbackend {
include /etc/nginx/proxy_params_demo;
proxy_pass https://demo-upstreams;
}
But this leads to an ERR with rewrite or internal redirection cycle while redirect to named location "#ngxbackend" as the named location is probably never reached because of the access_by_lua_block after it's internal redirect.
Can I solve this by use of variables and further condition checking?

Proxy a request - get a parameter from URL, add a header and update request URL using Nginx

I am looking for a way to do the following using Nginx:
Intercept a request
Read URL, parse it and read a value from it.
Add that value as a new request header
Update the URL (remove a particular value)
Forward the request to another server
e.g
Request URL - http://<<nginx>>/test/001.xml/25
Final URL - http://<<server>>/test/001.xml with header (x-replica: 25)
I have a nginx server setup with a upstream for the actual server. I was wondering how do I setup Nginx to achieve this ?
Since the data exists within the request URI itself (available by the $uri variable in nginx), you can parse that using the nginx lua module. nginx will need to be compiled with lua for this to work, see: openresty's nginx lua module.
From there you can use the set_by_lua_block or set_by_lua_file directive given $uri as a parameter.
In configuration this would look something like:
location / {
...
set_by_lua_file $var_to_set /path/to/script.lua $uri;
# $var_to_set would contain the result of the script from this point
proxy_set_header X-Replica $var_to_set;
...
}
In script.lua we can access the $uri variable from in the ngx.arg list (see these docs):
function parse_uri( uri )
parsed_uri = uri
-- Parse logic here
return parsed_uri
end
return parse_uri( ngx.arg[1] )
Similarly, you can modify this function or create another to make a variable with the updated $uri.

Nginx how to pass a parameter to proxy server?

I have a very simple problem but I am new to nginx so I may be missing some obvious solution.
So I have a location defined in nginx
/example/$id
I would like to pass $id to parametrized route on my proxy server like so
http://server.com/example/$id
This gives me unknown id variable on nginx reload. So my question is how can I pass a parameter from nginx to my proxy server.
Assuming all the rest are correctly set, you can just create a location with a regex and pass the captured variable to your proxy.
location ~ ^/example/(.+)$ {
proxy_pass http://server.com/example/$1;
}
If your $id is numeric only, the regex could be more restrictive
location ~ ^/example/(\d+)$ {
proxy_pass http://server.com/example/$1;
}
Note that you can't just use a variable without declaring it first. Declaring $id is not necessary, it is captured inside the parentheses of the regex and passed to $1

Resources