NGINX virtual hosts with seperate lua_package_path variables - nginx

I'm trying to serve two (Openresty) Lua web applications as virtual hosts from NGINX which both require their own unique lua_package_path, but have a hard time getting the configuration right.
# Failing example.conf
http {
lua_package_path = "/path/to/app/?.lua;;"
server{
listen 80;
server_name example.org
}
}
http {
lua_package_path = "/path/to/dev_app/?.lua;;"
server{
listen 80;
server_name dev.example.org
}
}
If you define the http twice (one for each host), you will receive this error: [emerg] "http" directive is duplicate in example.conf
If you define the lua_package_path inside the server block, you will receive this error: [emerg] "lua_package_path" directive is not allowed here in example.conf
If you define the lua_package_path twice in a http block (which does not make any sense anyway), you will receive this error: [emerg] "lua_package_path" directive is duplicate in example.conf
What is the best practise of serving multiple (Openresty) Lua applications with their own lua_package_path, being virtual hosts on the same IP and port?

I faced this issue several month ago.
I do not recommend no use debug and release projects in the same server. For instance, you launch the one nginx application for both (debug and release) key may lead to unexpectable behaviour.
But, nevertheless, you can setup:
package.path = './mylib/?.lua;' .. package.path inside lua-script.
You can setup your own local DEBUG = false state and manage inside the app.
Obviously, use the other machine for debug. Imo, the best solution.
Execute different my.release.lua or my.debug.lua file:
http {
lua_package_path "./lua/?.lua;/etc/nginx/lua/?.lua;;";
server{
listen 80;
server_name dev.example.org;
lua_code_cache off;
location / {
default_type text/html;
content_by_lua_file './lua/my.debug.lua';
}
}
server{
listen 80;
server_name example.org
location / {
default_type text/html;
content_by_lua_file './lua/my.release.lua';
}
}
}

Fixed it removing the lua_package_path from the NGINX configuration (since the OpenResty bundle already takes care of loading packages) and pointing my content_by_lua_file to the absolute full path of my app: /var/www/app/app.lua
# example.conf
http {
server{
listen 80;
server_name example.org
location / {
content_by_lua_file '/var/www/app/app.lua';
}
}
server{
listen 80;
server_name dev.example.org
location / {
content_by_lua_file '/var/www/app_dev/app.lua';
}
}
}
After that I included this at the top of my app.lua file:
-- app.lua
-- Get the current path of app.lua
local function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*/)")
end
-- Add the current path to the package path
package.path = script_path() .. '?.lua;' .. package.path
-- Load the config.lua package
local config = require("config")
-- Use the config
config.env()['redis']['host']
...
This allows me to read the config.lua from the same directory as my app.lua
-- config.lua
module('config', package.seeall)
function env()
return {
env="development",
redis={
host="127.0.0.1",
port="6379"
}
}
end
Using this I can now use multiple virtual hosts with their own package paths.
#Vyacheslav Thank you for the pointer to package.path = './mylib/?.lua;' .. package.path! That was really helpful! Unfortunately it also kept using the NGINX conf root instead of my application root. Even with prepending the . for the path.

Related

how to split traffic from same url path to 2 different upstreams?

i have these upstreams declared:
upstream upstream_1 {
server some_container_1:8000;
}
upstream upstream_2 {
server some_container_2:8001;
}
and this server:
server {
listen 7000;
server_name localhost;
location /path {
uwsgi_pass upstream_1;
}
}
where both some_container_1 and some_container_2 are based on same image (thus offer the same apis on the same paths) but differ on env vars and other non related stuff. i want to fork 1% of all traffic from localhost:7000/path to be delivered 'as is' to upstream_2 and 99% to remain on upstream_1. both cases should keep the request as received, altering neither path nor headers
with split_clients i can fork which path will be set before forwarding the request to a single upstream, which is not my case.
here the fork is done inside an upstream between servers, not inside a location splitting between upstreams, as i need.
can i define an upstream of upstreams like
upstream compound_upstream_1 {
upstream upstream_1 weight=99;
upstream upstream_2;
}
to use it on
server {
listen 7000;
server_name localhost;
location /path {
uwsgi_pass compound_upstream_1;
}
is it possible to do this with nginx? considering so, which way should be the standard to accomplish this?
I don't understand, what stops you from using server names in the upstream block directly?
upstream compound_upstream_1 {
server some_container_1:8000 weight=99;
server some_container_2:8001;
}
server {
listen 7000;
server_name localhost;
location /path {
uwsgi_pass compound_upstream_1;
}
}
Or maybe I misunderstand your question?
It might be possible to accomplish this using a load balancer: https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/
I'm not sure what the weights would be for your '1%' scenario but you can toy with it and adjust it to your liking.

Nginx location part not being replaced in proxy_pass when using variable

I have a service listening on myservice.mycompany.local
We're proxifying request like this
server {
listen 80;
location /myservice/ {
proxy_pass http://myservice.mycompany.local/;
}
}
it all works fine requests on public.mycompany.com/myservice/api/1/ping are correctly transformed into request to http://myservice.mycompany.local/api/1/ping as there is the trailing /
but now if we try to use a variable
server {
listen 80;
set $MY_SERVICE "myservice.mycompany.local";
location /acm/ {
proxy_pass http://$MY_SERVICE/;
}
}
the local service will only receive a requests to / with the URI part being lost
I've been able to reproduce this "problem" with several version of nginx
1.8.1-1~wheezy
1.4.6-1ubuntu3.5
I'm able also to reproduce it locally by replacing the proxified service by a simple nc -l 127.0.0.2 8080 and using it as the value of my variable, so it really seems to be something happening inside nginx
And this behaviour is not covered in http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
You may have discovered an undocumented feature, but you can always use a rewrite ... break instead of proxy_pass aliasing:
server {
listen 80;
set $MY_SERVICE "myservice.mycompany.local";
location /acm {
rewrite ^/acm(/.*)$ $1 break;
proxy_pass http://$MY_SERVICE;
}
}

Configure nginx and luameter not working

I am just beginner.I am trying to configure nginx and luameter for monitoring nginx.
Here are the step I follow :
1). Compile openresty
2). And configure luameter and nginx using this guide : luameter
I put this code to my nginx configuration :
http {
...
lua_shared_dict luameter 1m;
lua_package_path "{CHANGE_ME}?.luac";
init_by_lua "luameter = require 'luameter'";
log_by_lua "luameter.mark_by_host(); luameter.mark_by_path(1)";
...
}
server {
listen 127.0.0.1:8001;
location / {
root /opt/luameter;
}
location /stats {
content_by_lua "luameter.get_stats('/stats');";
expires -1;
}
}
I change {CHANGE_ME} to /opt/luameterbut it's not working.
I'm in the process of setting this up too, and according to some examples I found the text {CHANGE_ME}? should be replaced with /opt/luameter/luac/luameter. So the lua_package_path line becomes:
lua_package_path "/opt/luameter/luac/luameter.luac";

How to look for a certain header in nginx

I'm using nginx as a proxy server to basically serve image files and hand off everything else to another server at port 9000.
What I want to do is have nginx return an HTTP 500 error code if the incoming request does not contain a specific header (X-AUTH-TOKEN), but only if the requests are not for the resources "/register" or "/events". In that case, they need to go straight to port 9000.
Here's the configuration I currently have:
http {
sendfile on;
upstream my-backend {
server 127.0.0.1:9000;
}
# main ngingx server
server {
server_name localhost;
location / {
proxy_pass http://my-backend;
}
location /images/ {
root /home/images;
}
}
}
Any idea how to implement this kind of logic? Thanks.
There is native HttpCoreModule feature exists:
You can check any header exists/match by something like this:
location /blah {
if ( $http_x_auth_token ) {
// do something, allow
}
}
http://wiki.nginx.org/HttpCoreModule#.24http_HEADER
Hope it will help :)

nginx redirect to external folder

This is my nginx vhost conf:
upstream demo {
server 127.0.0.1:9002 max_fails=250 fail_timeout=180s;
}
server {
listen 80;
server_name _;
root /home/web/public;
location /demo/ {
proxy_pass http://demo/;
}
location /demo/assets/ {
#this is where I need to point localhost/demo/assets (and all of it's subfolders) to another folder
#the line below obviously doesn't work
root /home/user/Workspaces/demo/public;
}
}
The root folder is pointing to /home/web/public, but I need the url localhost/demo/assets/ and all of it's subfolders to go to another (external) folder. How do I do that?
I'm running nginx 1.4.3
You should use the alias directive, as well as read the docs. Just a quote from it:
A path to the file is constructed by merely adding a URI to the value of the root directive. If a URI has to be modified, the alias directive should be used.
Example:
location /demo/assets/ {
alias /home/user/Workspaces/demo/public/;
}

Resources