Nginx forwarding to different app's different path using `#` symbol - nginx

Quick question. We have two apps. Ports 3001 and 3002. Our domain is www.domain.com.
What we want to have it once person enters www.domain.com/pathname we want them to be redirected into another app's specific path.
How to do it?
We already came up to this in my nginx
location /pathname/ {
proxy_pass http://127.0.0.1:3002/;
}
It nearly works. However, our app under 3002 works on path /#/pathname.
We can access it by typing www.domain.com/pathname/#/pathname. We want to access same link by typing www.domain.com/pathname.
How to shorten it? What do I miss?

(upd) Just redirect /pathname to /pathname/#/pathname
According to your comment, you want just redirect from /pathname to /pathname/#/pathname
Try these combined directives:
rewrite to append # and fragment identifier
and proxy_pass to reverse proxy to the app.
E.g.:
location /short_path_name/ {
rewrite ^ /pathname/#/$uri permanent;
break;
}
location /pathname/ {
proxy_pass http://127.0.0.1:3002/;
}
And use www.domain.com/short_path_name/ link for your app.
Unfortunately, nginx can't see the fragment identifier
Unfortunately, you can't. Because server never get the fragment identifier from browser.
The fragment identifier functions differently to the rest of the URI: its processing is exclusively client-sided with no participation from the web server
Naming a bit amusing, but it has a long history. See TBL (1997): Fragment Identifiers on URIs:
The URI reference is a thing you build by taking a URI for an information object, adding a "#" sign and then a Fragement identifier. (The last term is historical, so try not to thinl of it necessarily identifying a fragment).
Workarounds
There are workarounds, e.g. encode hashtag symbol into %23 but I'm not sure is it your way.
Handle request arguments with nginx
Note: rewriting url, nginx can preserve request arguments if you add ? at the end of rewrite directive.
See Nginx rewrite manual:
If a replacement string includes the new request arguments, the previous request arguments are appended after them. If this is undesired, putting a question mark at the end of a replacement string avoids having them appended, for example:
rewrite ^/users/(.*)$ /show?user=$1? last;

Related

Nginx 301 Permanent Redirect For Language Support

I am now enabling language support for my web site. I am including the language as part of the URL. For example: domain.com/en/page I need to setup 301 redirects for existing search engine indexing.
The following works in Nginx to redirect from domain.com/blog to domain.com/en/blog
location = /blog {
return 301 /en/blog;
}
I don't understand the redirect needed to go from domain.com/blog/read/# to domain.com/en/blog/read/# (where # is the sequence field in a postgres database table)
I have spent time looking, searching and reading docs to find this answer myself. I am not understanding.
To prefix the existing requested URI with /en you can use:
return 301 /en$request_uri;
The above will add the three characters before the existing request and also include any arguments that may be present.
To match any URI that begins with /blog, use location /blog { ... }. To match any URI that begins with /blog/read/ use location /blog/read/ { ... }.
Nginx chooses a location to process a request based on a set of rules. So, you will need to consider the other location blocks present within your configuration.

Nginx wordpress rewrites for pattern to a particular page

I'm trying to set it up so that certain URLs will rewrite (not change URL in address bar) to a particular page with identifying parameters.
I would like
site.com/reviews/froot_loops_review.php AND
site.com/reviews/froot_loops_review
to actually show
site.com/review?title=froot_loops
Additionally, I would like to be able to append any other parameters so:
site.com/reviews/froot_loops_review.php?var=1
would show what's at:
site.com/review?title=froot_loops&var=1
I'm having a hard time with this because it's my first time editing nginx conf files this is as far as I've got but it doesn't work (I think because it doesn't make the first match):
location /reviews/ {
rewrite ^/reviews/(.*)_review.php(.*) /review?title=$1 break;
return 403;
}
What am I doing wrong here? What should my next step be? What is a good resource for learning Nginx rewrites?
I am not sure if this is strictly an answer. But there are multiple issues with your current solution.
This is a WordPress site, so there is already a location ~ \.php$ block which is handling any URI that ends with .php. The URI /reviews/froot_loops_review.php will never make it to the location /reviews/ block in your question.
You can use the ^~ modifier on the location directive to force nginx to ignore any matching regular expression location block. See this document for details.
The rewritten URI cannot be processed within the same location block, so break is the wrong suffix to use. You will have more success using last. See this document for details.
But the main problem is WordPress itself. WordPress normally uses the REQUEST_URI (which is the URI as originally presented) to identify the requested page. Which is why we can rewrite everything to /index.php and still get the right page.
Trying to make WordPress use your rewritten URI without an external redirect (which you say you do not want to do) is tricky. You may be better off looking for a WordPress plugin to achieve it - or try to make the pretty permalinks work the way you want.

How do I confiugre nginx to send a specific static file when a specific url is requested?

I have a file, say client.app.js, which I want to send when http://mydomain.local/app.js is requested.
I want to only send a single specific file when get a specific request.
How do I configure nginx to work like this?
To change the URI you can use a rewrite directive. The simplest solution is a rewrite statement at the server block level, or within the location block that processes the original request (assuming that /client.app.js is a valid URI) (see this document for details):
rewrite ^/app.js$ /client.app.js last;
Alternatively, use an exact match location. This also gives you the ability to set the root of the replacement file (see this document for details):
location = /app.js {
root /path/to/file/dir;
rewrite ^ /client.app.js break;
}

Fix duplicate query string in nginx

I've got a strange case where my app is now for some reason appending a duplicate query string onto a URL that already has one. I don't have the access or the time to dig into the application code right now, but I do have access to Nginx configs.
What I need is a rewrite rule that will ignore the duplicate query string, ie
http://foo.com?test=bar?test=bar will redirect to http://foo.com?test=bar
Is this even possible? Thank you.
Here, add this inside your server block, before any other location or if:
if ($query_string ~ ^([^?]+)\?\1$) {
set $clean $1;
rewrite . $uri?$clean?;
}
It's quite tricky to get right, because there are more than a few obscure behaviours:
$query_string is the query string without the initial ?
the \1 in the regexp matches a second copy of the first group (...)
you need to save $1 into a new variable because rewrite will overwrite it
you need to use $uri and not $request_uri in the rewrite, because the latter contains a copy of the original query string
you need to add a trailing ? to the rewrite, otherwise the rewrite would append a copy of the original query string! (that's probably the most obscure bit of Nginx syntax, ever)
The simple form of rewrite (without the redirect flag) should be enough for most applications, plus it doesn't require an additional round-trip to the browser.
If it does not work for you, you can try using the $clean query string into the appropriate backend directive (such as fastcgi_param QUERY_STRING and such) or, as a last resort, issuing a browser redirect using the redirect rewrite flag.

proxy_set_header not working as expected

I'm trying to have nginx proxy various applications on subpaths of the same domain.
My problem is that the links generated by the application use / as their root instead of their subdir.
My configuration is :
location /wiki/ {
proxy_pass http://localhost:4567/;
proxy_set_header SCRIPT_NAME /wiki;
}
I believe proxy_set_header SCRIPT_NAME /wiki; should set the header SCRIPT_NAME, which is use by the application to generate links, but instead HTTP_SCRIPT_NAME is set, which is ignore by the application.
How can I set SCRIPT_NAME so that my links are generated correctly ?
As per CGI specification, http headers are availabe with the HTTP_ prefix:
Meta-variables with names beginning with "HTTP_" contain values read
from the client request header fields, if the protocol used is HTTP.
The HTTP header field name is converted to upper case, has all
occurrences of "-" replaced with "_" and has "HTTP_" prepended to
give the meta-variable name.
That is, header Some-Header will be seen as HTTP_SOME_HEADER in your application. That is, everything works is expected - you added http header, and got it available with HTTP_ prefix.
The SCRIPT_NAME variable is special and isn't set by any header, but instead it's constructed from URI by the code which runs your application. To change it, you have to actually change URI seen by your backend, i.e. you need
proxy_pass http://localhost:4567/wiki/;
Or just no /wiki/ in proxy_pass, as long as it's in location /wiki/ anyway, i.e.
location /wiki/ {
proxy http://localhost:4567;
}
The bad thing here is that you probably did URI change from /wiki/ to / for some reason, i.e. your backend application expects /. There are several possible solutions to this problem:
Actually move the application to /wiki/. Usually this is simple to do.
Change your app to accept it's base url used for generating links etc. by some out-of-bands method. Many application already support this via some configuration option.
Try to replace what your application returns by nginx itself. There are several nginx directives to do it, in particular proxy_redirect, proxy_cookie_path, and the sub filter. It's most fragile method though, and not recommended unless you know what your application returns and what exactly have to be replaced.

Resources