kaji
kaji

Reputation: 7827

how to expose server port in upstream block of Nginx configuration?

We have a handful of homogenous application loosely under SOA pattern. Because of homogeneity, we have been able to define some neat pattern in Nginx to proxy all of our SOA apps through one configuration. Following Nginx configuration is absolutely working absolute wonders in conjunction with DNSmasq to resolve anything.yourdomain.devel eg. a.stackoverflow.devel, b.stackoverflow.devel domains and route that to appropriate app servers under your project folder via designated ports via maps.

 worker_processes  2;

    events {
      worker_connections  1024;
    }

    http {

          map $host $static_content_root {
            hostnames;
            default /path/to/project/folder;
            # For typical standalone apps living in your project directory
            # *.myapp.local.devel -> /path/to/project/myapp/public
            ~^([^\.]+\.)*(?<app>[^\.]+)\.devel$ /path/to/project/folder/$app/public; #rails pattern
          }

          map $app $devel_proxy_port1 {
            default 3000;
            domain1 3000;         
            domain2 4000;

          }

          map $app $devel_proxy_port2 {
            default 3001;
            domain1 3001;
            domain2 4001;
          }

          server {
            listen 127.0.0.1;
            server_name  ~^([^\.]+\.)*(?<app>[^\.]+)\.[^\.]+.devel$;


            location / {
              root  $static_content_root; # Using the map we defined earlier
              try_files $uri $uri/index.html @dynamic;
            }

            location @dynamic {
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forward-Proto http;
                proxy_set_header X-Nginx-Proxy true;
                proxy_redirect off;
                proxy_pass http://127.0.0.1:$devel_proxy_port1;
            }
          }
        }

Now, in order to simulate multiple servers behind Nginx load balancer. I thought of doing following proxy configuration which points to upstream rather than directly pointing to one server:port pair.

proxy_pass http://backend;

upstream backend {
   server http://127.0.0.1:$devel_proxy_port1;
   server http://127.0.0.1:$devel_proxy_port2;
}

I thought above would work but it always emits following error hinting the variables of map blocks are not available inside upstream context.

[emerg] 69478#0: invalid host in upstream "http://127.0.0.1:$devel_proxy_port1" in /usr/local/etc/nginx/nginx.conf:57

Is this an expected behavior?

Upvotes: 1

Views: 5948

Answers (1)

Dmitry MiksIr
Dmitry MiksIr

Reputation: 4445

Yes, variable can not be used inside upstream. You can create few upstream blocks with different names (upstream backend, upstream backend_domain, etc), resolve upstream name through map and put this variable to proxy_pass:

upstream backend {
 server http://127.0.0.1:3000;
 server http://127.0.0.1:3001;
}

upstream backend_domain1 {
 server http://127.0.0.1:3002;
 server http://127.0.0.1:3003;
}

upstream backend_domain2 {
 server http://127.0.0.1:3004;
 server http://127.0.0.1:3005;
}

...

upstream backend_domain30 {
 server http://127.0.0.1:3060;
 server http://127.0.0.1:3061;
}

map $app $devel_proxy {
 default backend;
 domain1 backend_domain1;
 domain2 backend_domain2;
 ...
 domain30 backend_domain30;
}

...
proxy_pass $devel_proxy;
...

In some cases you can skip map block using $app inside proxy_pass: proxy_pass backend_$app;, but need additional checks for $app values. Also, map allow to to map different "domains" to same applications.

Upvotes: 2

Related Questions