using proxy_pass with dynamic variables nginx - nginx

I'm trying to use proxy_pass with nginx to mask redirects to my image CDN. I'd like to be able to go to a path like:
myserver.com/images/12345/whatever-name-goes-here.jpg
I'd like that to proxy to
http://imagecdn.com/12345.jpg
i've tried the following
location ~ /images/(.*)/(.*) {
proxy_pass http://imagecdn.com/$1.jpg;
}
But i keep getting 502 errors. Any idea if this is even possible ?

I would suggest using an actual redirect, such as:
location ~ ^/images/(.*)/(.*)$ {
return 301 $scheme://imagecdn.com/$1.jpg;
}

Related

Nginx proxy pass with rewrite and regex

Can Nginx rewrite a URL then use it as a proxy pass?
For example when I visit http://localhost/downloads/example-com/pc.html it should proxy to http://example.com/pc.html
Basically, I want to use my domain to download a file from another website that is why I am doing this
Yes you can rewrite url and proxy_pass to rewritten url.
But as per what you want to achieve, this simple solution should also work :
location ~ /example-com/(.*)$ {
proxy_pass http://example.com/$1;
}
if you want you achieve it by rewriting only then you can try following one :
location ~ /example-com/ {
rewrite /example-com/(.*) /$1 break;
proxy_pass http://example.com;
}
UPDATE :
pass another website url as query param like below :
http://yourdomain/downloads/data?data_url=example.com/pc.html
and change your nginx configuration as below.
location ~ /downloads/data {
set $data_url $arg_data_url;
proxy_pass http://$data_url;
}
after this configuration change you might get resolver issue as we are passing hostname in proxy_pass at runtime. To solve resolver issue you can follow this link : https://runkiss.blogspot.com/2020/01/using-nginx-authrequest-to-proxy-to.html

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;
}

Trouble rewriting urls

I'm using nginx as a reverse proxy for a service running on port 8080 of the local machine. Additionally I need to prefix paths sent to the upstream with /vp. This is simple and I have a working location block for it:
location ~ ^/(.*?)$ {
proxy_pass $scheme://127.0.0.1:8080/vp/$1;
proxy_set_header Host $host;
proxy_redirect $scheme://$host/vp/ $scheme://$host/;
}
So the above would support a url like example.com/resource and work perfectly.
However, I also want to support urls like example.com/vp/resource. For this I have to write another location block or else it would passed to the upstream as /vp/vp/resource which doesn't work.
location ~ ^/vp/(.*?)$ {
rewrite /vp(.*?)$ /$1;
}
The above works and now I have support for urls like example.com/vp/resource.
But I have one last thing I'd like to fix. When a user would access example.com/vp/resource I want the url in the browser to be rewritten to just example.com/resource. My above configuration does not do this and I do not know how to modify it so that it does. I thought the point of rewrite was to rewrite urls seen in the browser but that doesn't seem to be the case.
First I tried change this:
location ~ ^/vp/(.*?)$ {
rewrite /vp(.*?)$ /$1;
}
to this:
location ~ ^/vp/(.*?)$ {
return /$1;
}
And this mostly worked. All URIs starting with /vp would be redirected to ones without which would change the url in the browser. However, this had the side effect of making POST requests not work. This is because the POST request never actually makes it to the upstream server. Instead the POST returns the 301 redirect immediately, without a proxy pass. The browser then GETS the redirect Location and that's the end.
So I needed to selectively return a true 301 only when the request was NOT a POST and when it was I needed to proxy_pass it. After reading the If is Evil I learned I can't use a proxy_pass inside of an if (inside of a location), only return and rewrite. Doing reading on rewrite, I learned that it rewrites the URI of a request but doesn't send it back to the client immediately. Instead it runs the newly rewritten URI against all the location blocks and executes whichever one matches. So in my case I just needed to use a rewrite to execute my original location block.
My final config ended up looking like this:
location ~ ^/vp/(.*?)$ {
if ($request_method = POST ) {
rewrite /vp(.*?)$ /$1;
}
if ($request_method != POST) {
return 301 /$1;
}
}
location ~ ^/(.*?)$ {
proxy_pass http://127.0.0.1:8080/vp/$1;
proxy_set_header Host $host;
proxy_redirect $scheme://$host/vp/ $scheme://$host/;
}

nginx proxypass with multiple locations

I try to setup nginx such that it proxies requests to multiple locations. E.g. /location1 and /location2 should both be proxied to http://localhost:8080. I just can't figure out how to configure this without using multiple location blocks. I already tried:
location /(location1|location2) {
proxy_pass http://localhost:8080/
}
which will only give 404s. And I've also tried:
location ~ /(location1|location2) {
proxy_pass http://localhost:8080/
}
Which will thrown an error that regular expressions are not allowed with proxy pass.
Is it possible to configure this proxy without having to create multiple location blocks?
Apparently is missing a slash and a ';'. Try this:
location ~ (/location1|/location2) {
proxy_pass http://localhost:8080;
}

NGINX Location troubles

I have django and flask applications running on the same machine through different ports:
Django runs on server:8088
Flask runs on server:666
In NGINX.conf I have the following code:
location / {
proxy_pass http://127.0.0.1:8088;
}
location ^/server2 {
proxy_pass http://127.0.0.1:666;
}
Django has been running for over a year successfully with this set up, where as flask is a new addition. Any time I try to access one of the Flask urls I either get a "this url does not exist on this server" error, or on occasion a 500 error (when i've been fiddling).
If I write location information for a specific flask url like this:
location /server2/splash {
proxy_pass http://127.0.0.1:666/splash;
}
It works, but I obviously don't want to write individual location information for each and every URL in the flask application.
I've gone through many of the existing Nginx location posts on stackoverflow but I've not been able to get it working. Any ideas?
Thanks!
EDIT
this is an example of what I'm trying to achieve, but rather than an individual mapping for each URL, I want a single mapping that covers all URLs:
location /server2{
proxy_pass http://127.0.0.1:666/splash;
}
location /server2/split {
proxy_pass http://127.0.0.1:666/split;
}
location /server2/export {
proxy_pass http://127.0.0.1:666/export;
}
location /server2/import {
proxy_pass http://127.0.0.1:666/import;
}
Why do you use the ^ sign? Just remove it I think it will work:
location /server2 {
proxy_pass http://127.0.0.1:666;
}
Note that when you use location /server2 the server2 is still being passed to your flask application.
In this case Nginx is doing the following:
server.com/server2 => http://127.0.0.1:666/server2
server.com/server2/splash => http://127.0.0.1:666/server2/splash
In this case location is not doing a rewrite. Always check /var/log/nginx (or wherever your logs are located) to check the requests done by the browser and what Nginx looks for after the rules for your site are processed.
What you probably want is to set an upstream directive:
upstream flask_server {
server 127.0.0.1:666;
}
server {
...
location /server2 {
proxy_pass http://flask_server;
}
}

Resources