Is it possible to create Nginx routing configuration from file? - nginx

I tried to look everywhere but I was not able to find any solution. I need to create Nginx routing configuration based on a data in my custom file. File will be updated automatically and look like this.
api_key_1: instance_id_1
api_key_2: instance_id_2
And in nginx.conf I expect something like this
upstream instance_id_1 {
server 127.0.0.1:8080;
}
upstream instance_id_2 {
server 127.0.0.1:8081;
}
map $http_x_instance_id $pool {
api_key_1 "instance_id_1";
api_key_2 "instance_id_2";
}
Is it possible to create the map {} part dynamically according to content of my config file?

How would I solve this task.
Use include directive in your nginx config:
map $http_x_instance_id $pool {
include /path/to/instances;
}
Install inotify-tools.
Write a script for watching your file (see some examples here). On every file change execute something like this:
sed -n 's/\(.*\):[[:blank:]]*\(.*\)/\1 "\2";/p' /path/to/your/custom/file >/path/to/instances
nginx -reload

Related

Css files doesn't load using proxy in Nginx

I have these lines in my nginx config:
location /proxy {
proxy_pass http://mysite.ru/;
proxy_redirect http://localhost/app http://mysite.ru/app;
}
Css files from mysite.ru are located in app folder, but it can't be loaded because full path to css file is like this: http://mysite.ru/app/files/css/style.css and it hasn't proxy in path, so it's trying to load http://localhost/app/files/css/style.css, and in the second line I'm trying to redirect this, but nothing works, what means that I'm doing something wrong (I don't know much about Nginx, what I'm trying is to understand)

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)

In nginx config, how to show something to log file directly in the config file?

I'm config a nginx, and debugging the config file,
How to show something from the config file directly to log file?
for example:
location ..... {
to_log "some string";
}
There is no direct way (on the todo list of the echo nginx module), but this solution seems fine https://serverfault.com/questions/404626/how-to-output-variable-in-nginx-log-for-debugging

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