Nginx reverse-proxy based on requested URL - nginx

I'd like to configure my nginx as reverse-proxy which will allow me such things:
requests like:
test.xxx.dev.example.com -> xxx.domain.dev.example.com
test.yyy.dev.example.com -> yyy.domain.dev.example.com
My current config:
server_name ~^test/.(?<app>\w+)\.dev\.example\.com
location / {
proxy_pass http://$app.domain.dev.example.com/;
}
I'm getting 502 error. Logs say: no resolver defined to resolve .domain.dev.example.com :( Any help?
Edit1: When added resolver 127.0.0.11 (this is docker-compose based env), error "no resolver defined to resolve..." disappears, but new one appear:
.domain.dev.example.com could not be resolved, host not found. It seems like for some reasons, variable $app is not passed to proxy_pass directive. Any idea ?

Well, It seems like the problem was with resolver and wrong regex. Below config works as expected for me:
resolver 127.0.0.11;
server {
listen 80;
server_name ~^test\.(?<app>.+)\.dev\.example\.com$;
location / {
proxy_pass http://$app.domain.dev.example.com$url;
}
}
#Richard in my regex, I'm declaring variable and value :) this is done by "?<'app>" where app is variable name.
Thanks for all the hints and help!

Related

Nginx reverse proxy - Internal servers separated by trailing slash

I'm a newbie at Nginx, and have been searching a lot for the right answer to my question, but couldn't find it; not because it is not there, but my newbie condition limits me to adapt a generic solution to my issue.
The situation is this:
I have a Mantis Bug Tracker in my private LAN (http://10.111.111.12).
On the other hand, i have an OwnCloud website also on my LAN (IP 10.111.111.5), with URL http://10.111.111.5/owncloud/.
What i want to do is to deploy a Nginx Reverse Proxy that handles all requests from Internet at publicdomain.com, and use trailing slash for each internal webserver. The desired result would be:
http://www.publicdomain.com/bugtracker -> redirects to http://10.111.111.12/index.php
http://www.publicdomain.com/cloud -> redirects to http://10.111.111.5/owncloud/ (note that "cloud" is preferred over "owncloud")
On the future, it is necessary to continue using trailing slash for other web servers to be deployed.
Questions are:
is this scenario possible? if so, is it enough with configuring nginx or I have to reconfigure internal web servers as well?
I really appreciate your help, by indicating me a possible solution or pointing me to the right direction on previous posts.
Thanks a lot in advance.
Yes it is possible to achieve such configuration and it's commonly used when NGINX is acting as a reverse proxy. You can use this configuration as an inspiration for building your own:
upstream bugtracker {
server 10.111.111.12;
}
upstream cloudupstream {
server 10.111.111.5;
}
server {
listen 80;
location /bugtracker/{
proxy_pass http://bugtracker;
}
location /cloud/{
proxy_pass http://cloudupstream/owncloud;
}
}
What's happening over here is that nginx will be listening on port 80 and as soon as a request comes for path /bugtracker, it will automatically route the request to the upstream server mentioned above. Using this you can add as many upstream servers and location blocks as you want.
Reference: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
Thanks a lot Namam for your quick answer. However, it isn't working yet. It seems that "server" at upstream directive does not allow slash, like this:
server 10.111.111.5/owncloud;
If i used it, i obtained
nginx: [emerg] invalid host in upstream "10.111.111.5/owncloud" in /etc/nginx/nginx.conf:43
I started with the first upstream bugtracker, only, and nginx.conf like this:
upstream bugtracker {
server 10.111.111.12;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
location /mstic{
proxy_pass http://bugtracker;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
After that, when accesing to my Nginx Reverse proxy http://10.111.111.10/mstic/ i obtain the following:
Not Found The requested URL /mstic/ was not found on this server.
and no further details on error or access logs.
Thanks a lot in advance for any extra help you could bring me.

Nginx rewrite with proxy_pass

I recently have a requirement in Nginx to rewrite a URL and then forward this onto to another backend server to a dynamic proxy pass address. I've tried a few things but have not had much luck at the moment. For example, this is the kind of setup I have in my nginx.conf file:
server {
listen 443;
server_name scheduler.domain-name;
rewrite ^scheduler(.*)/(.*)/(.*) $2$1$3; # scheduler.domain.local/changepass/report?target=service
...
location / {
proxy_pass $to-rewrite-address:9443; # changepass.domain.local/report?target=service
...
}
Essentially, I just need to use a re-written URL variable to forward the request on a different port but can't seen to get this to work.
I've done quite a bit of searching but haven't found the solution to this as of yet, though I understand that the DNS resolver has to be set when using a proxy pass variable (Dynamic proxy_pass to $var with nginx 1.0).
Grateful if anyone could advise on how the above could be achieved, many thanks.
Assuming your endpoint would always be specified as the first part of your URI, here is an example of configuration that should work:
server {
listen 443;
server_name scheduler.domain-name;
resolver <your resolver for domain.local>;
...
location ~ ^/(?<endpoint>changepass|endpoint2|endpoint3|...)(?<route>/.*) {
proxy_pass http://$endpoint.domain.local:9443$route;
}
}
I'm using named capturing groups here for a better readibility, this location block is equal to
location ~ ^/(changepass|endpoint2|endpoint3|...)(/.*) {
proxy_pass http://$1.domain.local:9443$2;
}
I'm not sure if query arguments would be preserved with such a construction, if they won't, change
proxy_pass http://$endpoint.domain.local:9443$route;
to
proxy_pass http://$endpoint.domain.local:9443$route$is_args$args;

Nginx pass_proxy with variables

I'm having trouble making nginx proxy an url with variable to a service within kubernetes.
Url looks like this:
http://localhost/user?username=Dave
I expect this url to take me to a subpage /user, which will read ?username=Dave and then fetch data from a database. However this takes me to the home page of the application(/ instead of /user) and does not read the variable even though url includes /user?username=Dave.
My current nginx config file looks like this:
server {
listen 0.0.0.0:80;
server_name localhost;
location / {
proxy_pass http://${FLASK_APP}:8080/;
}
location /user {
proxy_pass http://${GO_APP}:8000/;
}
}
I have read that location /user will match the url I'm passing. What is wrong with it? Or do I need to add something to proxy_pass http://${GO_APP}:8000/; or location /user?
As noted in the comments, the issue arises because you are using a variable in the proxy_pass target. As also noted in the comments, this question is related. As the answer referencing the docs states:
A special case is using variables in the proxy_pass statement: The
requested URL is not used and you are fully responsible to construct
the target URL yourself.
This means that you either need to use a static proxy_pass target, such as
// note that I added the forward slash
location /user/ {
proxy_pass http://destination:8000/;
}
Or as an alternative, I believe you can do it this way also
location /user/ {
proxy_pass http://${GO_APP}:8000/user$is_args$args;
}

Nginx: how to add /something to a uri and still keep it working

I have a nginx instance running. My config is something like the following.
server {
listen 80;
listen 443;
location / {
...
proxy_pass http://127.0.0.1:8080;
...
proxy_redirect http://127.0.0.1:8080 example.com;
}
}
I have some software running in 8080 and I want that the user enters example.com/somepath and be able to be redirected to the root 127.0.0.1:8080 through my domain. The software should receive all urls without /somepath but the browser should still show /somepath in the name.
I am quite new so sorry for the basic question I could not find any relevant info on how to do this exactly: I tried rewrite rules and setting location /mysoftware { tests with no luck.
The client browser uses /somepath/... to access /...in the application. This means that nginx must rewrite the URI before passing it upstream.
The proxy_pass directive has a basic rewrite capability. See this document for details. For example:
location /somepath/ {
proxy_pass http://127.0.0.1:8080/;
...
}
Alternatively, you might use a rewrite ... break statement. See this document for details. For example:
location /somepath {
rewrite ^/somepath/?(.*)$ /$1 break;
proxy_pass http://127.0.0.1:8080;
...
}
The difficult part is preventing your application from breaking out of /somepath. The proxy_redirect directive can handle the 3xx responses from your application. But the location of resource files (.css and .js) and the target for hyperlinks, can cause problems for applications that are not aware that they need to stay inside a subdirectory.

nginx variables (cname) in proxy_pass

i am trying dynamically set a the proxy_pass destination where the variable would be the cname of the original request.
what i have right now is:
server {
listen 8888;
server_name (.*).domain.com;
location / {
proxy_pass http://$1.otherdomain.com;
proxy_set_header Host $1.otherdomain.com;
but unfortunately this ends up in a 502 bad gateway.
nothing really works when using a variable in proxy_pass and proxy_set_header.
i also tried to use (?<cname>.+) or (?P<cname>.+) in the server name and $cname as the variable.
what is wrong and why does it end up in a 502?
To use regex in server name, you need to prepend the name with a tilde "~"
server_name ~(.*).domain.com;
[UPDATE]
Tried it and it successfully set the value in $1. But still get 502 and my nginx error log shows
no resolver defined to resolve xyz.otherdomain.com
even though I point that name to my localhost in my /etc/hosts file.
Find this article that explains this issue well. Basically in this special case (variable in upstream domain name), you need to use the "resolver" directive to point to a dns server (e.g., 8.8.8.8 from google dns server) that can resolve this dynamic domain name.
resolver 8.8.8.8;
It works in my test with a public upstream domain name. If you upstream domain names are local, you need to set up a local dns server for them.
The server name for proxy_pass using variables, will be a special situation.
proxy_pass http://$1.otherdomain.com;
In this case, the server name is searched among the described server groups, and, if not found, is determined using a resolver.
If you do not like to use resolver. You can use below like hosts file.
upstream www1.otherdomain.com { server 10.x.x.1; }
upstream www2.otherdomain.com { server 10.x.x.2; }

Resources