How to escape "?" in nginx rewrite rule output - nginx

I am trying to reverse proxy in nginx, rewriting a front end page like "/a/b?page=2" into a backend request to "/a/b%3fpage=2"
I cannot figure out how to get nginx to make reverse proxy requests which include "%3f".
With the following config:
rewrite ^/one$ /a%3fb;
rewrite ^/two$ /a?b;
rewrite ^/three$ /a\?b;
/one makes a backend request like GET /a%253fb HTTP/1.0
/two makes a backend request like GET /a?b HTTP/1.0
/three makes a backend request like GET /a\?b HTTP/1.0
How can I get a backend request like GET /a%3fb HTTP/1.0?

Thanks to #Richard Smith's comment, I was able to fix this for my specific case with the following code:
location / {
set $backend_uri $request_uri;
if ($args ~* "page=(\d+)") {
set $page $1;
set $backend_uri $uri%3fpage=$1;
}
proxy_pass http://example.com$backend_uri;
}
I think that I might also have been able to do something more general with the lua rewrite directive, but I was unable to install mod-lua on an Amazon Linux 2 machine, see https://serverfault.com/questions/961337/how-to-install-nginx-mod-lua-on-amazon-linux-2

Related

Can a response from an http request alter the base address in the next client request?

I have an octoprint server running at http://192.168.1.205. I also have an nginx server hosting myDomain. I want to be able to use the nginx server to pass on a request for http://myDomain/octo to http://192.168.1.205 using a reverse proxy. Here is my nginx code...
server {
server_name myDomain;
location /octo/ {
rewrite ^/octo/(.*) /$1 break; #strip /octo from url
proxy_pass http://192.168.1.205;
}
}
The first http://myDomain/octo request is passed on to http://192.168.1.205 correctly. But after the first response the code in the client makes another request to http://myDomain/moreUri. Since this uri doesn't have /octo nginx doesn't know to send it to http://192.168.1.205/moreUri. Is there a way to have nginx change something in the first response so that the client then makes following requests to http://myDomain/octo/moreUri?
I was able to accomplish this for a case where the octoprint server responded with a redirect. I used ...
proxy_redirect http://192.168.1.205/ http://myDomain/octo/;
and it worked. But that only works on redirects and the following requests were wrong again.
Is there a way to have nginx change something in the first response so
that the client then makes following requests to
http://myDomain/octo/moreUri?
I am not aware that this is possible.
What about to adjust the nginx configuration accordingly ? using location / to process all requests within that block and add an additional redirect directive to address the "Since this uri doesn't have /octo nginx doesn't know to send it to http://192.168.1.205/moreUri" should do the trick.
server {
server_name myDomain;
location / {
rewrite ^/octo/(.*) /$1 break; #strip /octo from url
rewrite ^/(.*)/(.*) /octo/$2 break; #rewrite /moreURI to /octo/moreURI
proxy_pass http://192.168.1.205;
}
}
No matter if the above nginx reconfiguration fixes your issue, i assume the root cause why you need to configure the nginx as reverse proxy in this way might be a misconfigured (or not optimally configured) application. Check the config file if it is possible to configure the applications base path. If so, set it to /octo/ (so the application itself prepends /octo/ to all the links it presents to the user and all requests to the backend automatically) and adjust the rewrite rules accordingly.

How can I rewrite parts of a Location header with nginx?

I'm trying to setup a reverse proxy nginx in a docker-compose setup I have. It works fairly well, but I have a problem with a 302 redirect.
The nginx server runs on https://localhost:1253. When I return the redirect within my internal server, nginx will use the internal name (serviceweb) of my docker container in the redirect uri. This is my redirect uri:
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&<...>&redirect_uri=https%3A%2F%serviceweb%2Fsignin-google...
I'd like to change serviceweb to localhost:1253.
How can I do this with nginx?
I've tried this simple setup:
location / {
proxy_pass https://serviceweb;
proxy_redirect serviceweb localhost:1253;
}
But this does not quite work. The location header still contains the original value. I'm sure I somehow have a problem in the proxy_redirect rule , but I'm not sure how. There's a regex based way of doing it according to http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect, and I think my current setup would work with that.
What am I doing wrong?

Use nginx as proxy to get around CORS

I am trying to use nginx as a proxy so that i can hit an API directly from a browser.
Currently. I wrote the nginx line below,
location /binance-api {
add_header Access-Control-Allow-Origin *;
rewrite ^/binance-api/(.*) /$1 break;
proxy_pass http://api.binance.com;
}
Basically whenever i try to hit the server containing nginx
http://nginx-server/binance-api/
I want nginx to hit http://api.binance.com instead.
But for some reason, judging by inspecting XHR responses, my request URL itself keeps getting redirected to https://api.binance.com and CORS would trigger and my request will fail.
What am I missing here?
Thanks

How nginx rewrite and proxy? http://sa.com/rabbitmq/api/#/queues/%2F/somequeue

I try to use a single domain to proxy several programs like this:
http://sa.com/rabbitmq/ ---> http://localhost:15672/
http://sa.com/zabbix/ ---> http://localhost:10000/
and my conf is blow:
location /rabbitmq {
rewrite /rabbitmq(.*) $1 break;
proxy_pass http://localhost:15672;
It works well until I click a queue name to watch the detail,
which url is as the title said:
http://sa.com/rabbitmq/api/#/queues/%2F/somequeue
an 404 error occured, I saw an request in dev-tools of chrome:
http://rabbitmq.testing.gotokeep.com:15672/api/queues/%2F/dailyNewLike?lengths_age=60&lengths_incr=5&msg_rates_age=60&msg_rates_incr=5
this request returned 404.
I guess that when rewrite processed, the uri was decoded (.../%2F/... -> ...///...) and the extra slashes will be removed...
Is my guess right? Is there a solution?
Your guess is good, but no, the real problem is that nginx converts %2F into %252F (% -> %25).
%2F is vhost name (/). I don't found the real solution for this problem, and my workaround was to use other vhost name which do not contains / symbol (e.g. pool1).
You can use $request_uri to prevent nginx decode the uri.
use conf like below
location /rabbitmq {
if ($request_uri ~* "/rabbitmq/(.*)") {
proxy_pass http://localhost:15672/$1;
}
}

Simple Nginx Proxy Pass and Regex

I want a simple nginx rule to pass the following example.
request http://myserver:8888/application/external/testUrl_1
redirect to
http://myglassfishserver:8080/application/external/testUrl_1
Then say I sent in
http://myserver:8888/application/external/testUrl_2
it would redirect to
http://myglassfishserver:8080/application/external/testUrl_2
I should also keep all post data if I were to send a http POST.
To me this seems like it should be simple.
I'm trying
location ^/application/external {
proxy_pass http://myglassfishserver:8080/$1;
allow all;
}
I'm getting *1 access forbidden by rule, client: which I know is because it didn't match a rule. I've tried numerous combinations. What is it I've done wrong ? I'm guessing its the $1
location /application/external/ {
proxy_pass http://myglassfishserver:8080;
}

Resources