How can I pass Path parameters to lua code by nginx? - nginx

I want to create a Location in my Nginx with such route /resource/{{state}} though the {{state}} is a place holder for a variable that must pass to my Lua script and according to this variable I want to process some resources.
I cannot find any documentation or guideline for creating such a route in Nginx and passing path parameters to Lua. Are path parameters available in nginx and if the answer is yes how can I access them in mylua code?

Use the regex location syntax with the ngx.var.VARIABLE API:
location ~ ^/resource/(?<state>[^/]+)/?$ {
content_by_lua_block {
ngx.say(ngx.var.state)
}
}
Note: nginx uses the PCRE2 library for regex support. Check the documentation for the syntax.

Related

NGINX - Redirecting certain routes to a subdomain

I created a project, where I have:
my-project.com to show my Angular 8 App
api.my-project.com to access my Symfony 5 API
I built a very basic landing page on my Angular app, but now, I changed my mind and I want to have my angular app into app.my-project.com and keep the my-project.com to show a beautifull landing page.
The problem is that there are some clients that are already using the service on the main domain, and that request should be redirected to the app.my-project.com subdomain.
Should be something like this:
my-project.com/login -> app.my-project.com/login
my-project.com/pm-something -> app.my-project.com/pm-something
Here is a pseudocode of what I need:
if( url.includes('login') or url.includes('pm-') ) {
redirectTo(app.my-project.com)
}
I thought the easiest way to achieve that is to rewriting the routes in my NGINX config file, but I am not sure the correct way to do it.
Thanks in advance.
NGINX chooses request URI processing rules according to defined location blocks within the server configuration. Official documentation on this directive is here, and here are some additional explanations. You can achieve desired behavior using two prefix locations:
location /login {
return 301 $scheme://app.my-project.com$request_uri;
}
location /pm- {
return 301 $scheme://app.my-project.com$request_uri;
}
This two prefix locations could be replaced by a single regex matching location:
location ~ ^/(login|pm-) {
return 301 $scheme://app.my-project.com$request_uri;
}
NGINX uses system PCRE library and the general PCRE regex syntax, except you should not use delimiter characters for regex patterns (matching against a regex specified using ~ (case-sensitive matching), ~* (case-insensitive matching) or !~/!~* (case-sensitive/case-insensitive non-matching) operators). Additionally you are not required to prefix / character with a backslash (although you still can do it, it won't change the regex pattern meaning).

How to include multiple js_include tags in Nginx

I want to include multiple Nginx javaScript files (njs) in Nginx Configuration. But i am not able to add more than one js_include directive to load a file.
I have two njs files, sample1.javascript containing authorization code, sample2.javascript containing throttling logic code. I have created 2 files for modularity and readability.
Every request should go through both authorization and throttling logic, so i use below in http tag
http {
js_include /path/to/njs/file/sample1.javascript;
js_include /path/to/njs/file/sample2.javascript;
}
But i get error saying too many arguments for js_include directive.
You should try js_import if you have njs version > 0.4.0.
I have also tried js_include and it seems NGINX supports just one js_include declaration.
From the documentation:
The directive is deprecated since 0.4.0 , the js_import directive should be used instead.

select server block based on existence of certain query parameters

I have a single page application, I want to make it crawlable so I have generated snapshots. My application stack is rails + unicorn + nginx(as reverse proxy).
Now, Aws Opsworks generates a nginx config from this cookbook. I ssh-ed into the system & modified the default config to include the following lines to redirect all requests from search engine bots as follows(they convert the url which contains #! & send a new request with _escaped_fragment_ in query parameters):
if ($args ~ "_escaped_fragment_=(.+)") {
rewrite ^ /snapshots$uri$1?;
}
Everything worked great when I loaded the url in the browser. The issue I am facing is with automating the same thing using chef. Since the code I added was in the config file generated using default cookbook by opsworks, I need a way to define a nginx server block to achieve this. So, I defined the following server block.
server {
listen 80;
server_name example.com;
if ($args ~ "_escaped_fragment_=(.+)") {
set $foo $1;
rewrite ^ /snapshots$uri$foo?;
}
}
But nginx will never select this block given there already exists another server block with the same server_name. So, is there a way that I can define a server block to be selected by nginx based on the existence of _escaped_fragment_ in the $args ?
Something as follows(I know this won't work since regex doesn't match query parameters)
server {
listen 80;
server_name example.com(.+)_escaped_fragment_=(.+);
...
}
In order to do this in chef, you need to create a custom cookbook (if you don't have one already) and a recipe in it which would overwrite the opsworks generated file with your preferred file. In the cookbook you'd need 2 files, nginx template and a recipe to overwrite the default template with the custom one:
mycookbook -> templates -> default -> custom_nginx.erb
mycookbook -> recipes -> customise_nginx.rb
Content of (1):
whatever you want your nginx config file to be, so:
server {
listen 80;
server_name example.com;
if ($args ~ "_escaped_fragment_=(.+)") {
set $foo $1;
rewrite ^ /snapshots$uri$foo?;
}
}
Content of (2):
template "/etc/nginx/sites-enabled/<nginx file name>" do
source "custom_nginx.erb"
user "root"
group "root"
mode "644"
end
service "nginx" do
action :reload
end
Then add mycookbook::customise_nginx to the custom setup recipe section in your layer settings.
If you don't have a custom cookbook already, a bit more set up will be needed:
https://www.digitalocean.com/community/tutorials/how-to-create-simple-chef-cookbooks-to-manage-infrastructure-on-ubuntu
http://docs.aws.amazon.com/opsworks/latest/userguide/workingcookbook-installingcustom-enable.html
Edit:
If you want to keep opsworks config file, you have two options: to take the template that opsworks is using, I'm guessing this one? https://github.com/aws/opsworks-cookbooks/blob/release-chef-11.10/nginx/templat‌​es/default/site.erb, create a copy and put your changes there in file 1 as above. Or use chef to modify the existing file content - for example using FileEdit library (check the second answer to this question)

Nginx: Use different backend based on value of argument

We have a legacy application written in php which we are now migrating to java.
The Application being hige, we are trying to migrate features in part.
Keeping this scenario in mind, i need to split traffic between php-fpm backend and the java app based on the value of a query string argument
for eg
if $format="csv", use fast-cgi and process request using php
If $format="xml",connect to the java backend using the proxy_pass directive.
Unfortunately i am finding it difficult to do this on nginx.
I tried the following
if ($args_format ="csv")
include php;
if ($args_format ="xml")
include proxy;
here php and proxy are files containing the proxy_pass and fast-cgi related statements
Unfortunately this throws a syntax error
Then I create a map by using something like
map $args_output $provider {
default "proxy";
csv "php";
}
then did an
include $provider;
This also fails as nginx seems to load the includes at start time and not during execution of each call.
Any suggestions on how i can achieve this in an elegant way.
The variable name is $arg_format
http://nginx.org/en/docs/http/ngx_http_core_module.html#var_arg_
You must use { } after if statement.
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if
Try something like ...
if ($arg_format ="csv") {
include php;
}
if ($arg_format ="xml") {
include proxy;
}

How to reference OS Environment Variables in nginx.conf

In nginx.conf.
After set a variable by set $name value,
i can reference it like $name,
But when I export an OS Environment Variable
by env name_from_env,
like https://nginx.org/en/docs/ngx_core_module.html#env said,
and i am sure the name_from_env is valid which
defined form nginx's parent process.
But, my friends, how to reference it ?
$name_from_env or ${name_from_env} or
%name_from_env% didn't work what I've tried before.
nginx doesn't have the built-in ability to reference its environment variables in the configuration at present. The simplest solution however is the perl_set directive from ngx_http_perl_module, an extra module for nginx. The official nginx packaging builds the Perl module dynamically so it's a case of ensuring you install the extra nginx-module-perl package (or configure your custom build of nginx, if that's what you're doing).
Configuration looks like this:
# Make environment variable available
env NAME_FROM_ENV;
# Load dynamic module (if built with Perl as dynamic module; omit if static)
load_module modules/ngx_http_perl_module.so;
http {
server {
location / {
# Use Lua to get get and set the variable
perl_set $name_from_env 'sub { return $ENV{"NAME_FROM_ENV"}; }';
...
}
}
}
See also https://docs.apitools.com/blog/2014/07/02/using-environment-variables-in-nginx-conf.html for how to use Lua to achieve the same thing. Lua support requires a third party module and isn't shipped with nginx's default packages.
It should be $name_from_env, just like any other Nginx variable.
Note that env can only be used in the main part of your config, not http, server or location blocks.
I'm guessing that env isn't really what you need in any case. If you are trying to pass variables down to your application, you should use proxy_param or fastcgi_param (depending on how you are talking to your upstream):
fastcgi_param MYVAR foo;

Resources