Nginx redirect to url with /#/url - nginx

I'm new to using nginx and I'm trying to redirect one url to another.
https://server.com/#/page.html -> https://server.com/page.html
The /#/ comes from using Angular2's router functionality. I decided to change the page to static html because Angular2 loads the entire app at start up and it's unnecessary for this single page of information to be presented as such.
My attempts at solving the problem is as follows. I can redirect from /anotherpage -> /page.html but /#/anotherpage -> /page.html loads the Angular2 app and tries to route to the non existent route.
Using this config and location directives:
server {
listen 8001;
server_name server.com;
...
#SSL Things
...
root /to/root/folder/public;
#Redirects:
location = /anotherpage {
rewrite ^/.* https://$server_name/page.html;
}
#Does not redirect:
location = /#/anotherpage {
rewrite ^/.* https://$server_name/page.html;
}
}
Any suggestions on best practices are welcome as well.

The browser does not send any information after a # is encountered.
Thus when sending https://server.com/#/page.html only https://server.com/ is seen by nginx.
Thus redirecting is not possible and changing the client side application is the only option.

Related

How to configure domain and page level nginx redirects

I've searched and looked at various documentation on this but I'm having trouble understanding exactly different config settings interact with each other.
I have a wordpress installation hosted in Google cloud using one of the Bitnami deployments.
I have two domain names for the site, an older one from years ago and the one that I have been using for the past few years.
DNS for both point to the IP address of the server and requests to either domain work and display the current domain name in the browser and redirect to https. I suspect this is because of the site configuration in wp config.
server {
# Port to listen on, can also be set in IP:PORT format
listen 443 ssl default_server;
root /opt/bitnami/wordpress;
# Catch-all server block
server_name _;
ssl_certificate bitnami/certs/server.crt;
ssl_certificate_key bitnami/certs/server.key;
rewrite ^(/history.*) /a-new-url/ last;
# BEGIN Fix for WordPress plugins and themes
# Certain WordPress plugins and themes do not properly link to PHP files because of symbolic links
rewrite ^/bitnami/wordpress(/.*) $1 last;
there's more to it than this but I think that the above is the relevant bit.
The rewrite directive is not working as I expect.
For newwebsite/history.php the rewrite works
For newwebsite/history.html I get a 404 error (wordpress 404 page displayed)
For oldwebsite/history.php I get a file not found but not the wordpress 404 page
For oldwebsite/history.html I get a wordpress 404 page
I've tried adding a server block for oldwebsite that does a return to newwebsite eg
if ($host != "example.com") {
return 301 https://example.com$request_uri;
}
but this just results in a too many redirects error. I also tried creating a new server block but this also appears to break the website altogether.
I have multiple page level redirects that I need to configure where there are links to pages at the old url that need to be redirected to the new pages on the new url.
I'm sure that this should be a relatively simple configuration but I can't seem to get the right combination of config to make it work.
Any assistance would be appreciated, please let me know if there's any further information required.

How to proxy between 2 apps containing shared paths in a DRY way

I'm a newbie with Ngnix and I am looking for some advice to avoid repeating location blocks and preserve functionality.
I used to have one react application react.mydomain.cc
On my Nginx configuration file I was proxing everything from / to react.mydomain.cc
location / {
try_files $uri #approute;
}
location #approute {
proxy_ssl_server_name on;
set $react "http://react.mydomain.cc";
proxy_pass $react$request_uri;
}
Now, I want to replace part of the old application with a new one without having to make changes to the old.
The logic would be.
If the users goes to www.mydomain.cc he should be proxied to the new app http://new-react.mydomain.cc
The same other paths like:
/about
/contact
/blog
/whoiam
/photos
and a few more
These pages are also active through the other subdomain http://react.mydomain.cc/about but not accessible through nginx domain, www.mydomain.cc
If the user goes to
/notes
/playground
/app/*
/internal/*
he should be proxied to the old app.
Example: the user goes to www.mydomain.cc/notes and he is proxied to http://react.mydomain.cc/notes. Then he click on the link /about and he is proxied to the new app http://new-react.mydomain.cc/about even when the old app has /about.
Can anyone help me to avoid having to repeat 20 times location blocks? I'm trying to achieve the same but in a cleaner way.
Please, let me know if edition is needed to clarify. Remember I am new.

nginx proxy all request through authentication service

Consider a dockerized environment containing the following containers:
Backend API
Front-end REACT App served using pushstate-server
Authentication Service
Nginx Container
My nginx.conf contains the following:
server {
listen 8080;
location / {
auth_request /auth;
proxy_pass http://frontend:5000;
}
location = /auth {
proxy_pass http://auth:6000;
}
error_page 403 = #error403;
location #error403 {
rewrite ^ /login$1;
proxy_pass http://frontend:5000;
}
}
When the auth_request /auth; line is commented out, everything works just fine and all frontend pages can be accessed.
As soon as I introduce the auth_request I can see the authentication service return a 403 however, it does not look like Nginx proxies to the login page.
What am I doing wrong?
There are two issues here:
Firstly, the authorization header is not forwarded to the authentication service. This was fixed with
location = /auth {
proxy_pass http://auth:6000;
proxy_pass_header Authorization;
}
Secondly, when a request is made to the frontend, nginx tries to authenticate with the auth container. As I am not authenticated, this fails and returns a 403. The nginx server then proxies to the login page on the REACT container, however, there are further request behind the scenes to retrieve css and js resources from the same container, for which the nginx gateway tries to authenticate. Again, as I am not authenticated retrieving these resources fails, so the page does not render.
A dirty solution was to add:
location /static/js/main.1e2389bc.js {
proxy_pass http://web:5000;
}
location /static/css/main.aa587518.css {
proxy_pass http://web:5000;
}
This retrieves the necessary files to render the login page with trying to authenticate. This is a bad solution as there may be other resources (favicon, other media etc.) so more blocks would need to be added. I am sure there is a simple solution using regex to sort this out in a simple way.
However, I ended up with a cleaner solution. Authenticate on requests to the backend API. This ensured that no sensitive information was displayed on the frontend without being authenticated and removed the hassle of hacking a solution to render the login page.

Redirecting old URLs to new URLs based on tags

We had a database corruption on our website, now we are building a new one.
However, we have thought off a different approach, we are migrating our old articles to a sub domain and building a new website with a better UI and architecture.
What I would like to do is redirect url from old website to the sub domain, with out in the format as this:
http://olddomain.com/foo/something
to
http://sub.olddomain.com/foo/something
and we want to keep the the olddomain to serve new content
http://oldomain.com/foo2/something
is this possible with Nginx
UPDATE
We have a set word based on which we want to redirect
we just want
http://olddomain/foo/extrainfo
to redirect
http://sub.olddomain/foo/extra
when using the rewrite rule
/abc/ redirect permanent
we are having an issues that is a URL has word foo it's getting redirected to the new domain.
we just want http://olddomain/foo/ to redirect to http://sub.olddomain./foo/extra
not http://olddomain/abc/foo to http://sub.olddomain
You'll need something within your URL to identify if it's an old URL or a new URL. If you have something, than it's easy and we can answer the question. Your given example could easily be solved with:
location ~ ^/[a-z]+/[a-z]+$ {
return 302 $scheme://sub.$server_name$request_uri;
}
location ~ ^/[a-z0-9]+/[a-z]$ {
// serve new stuff
}
But don't forget about search engines and other robots! If you plan to use the original URLs for the new content in the future don't redirect anything and simply deliver the pages at the same places.
Yes, this is simple with nginx. You just need to put a rewrite rule in the correct location/server blocks:
server {
listen 80;
server_name olddomain.com;
location ~/foo/ {
rewrite ^ http://sub.olddomain.com$request_uri? permanent;
}
location / {
#serve new content
}
}
server{
listen 80;
server_name sub.olddomain.com;
location / {
#serve old content
}
}
I would second the previous comment that you should make sure you take into account SEO.

Sending extra header in nginx rewrite

Right now, I am migrating the domain of my app from app.example.com to app.newexample.com using the following nginx config:
server {
server_name app.example.com;
location /app/ {
rewrite ^/app/(.*)$ http://app.newexample.com/$1;
}
}
I need to show-up a popup-banner to notify the user of the domain name migration.
And I want to this based upon the referrer or some-kind-of-other-header at app.newexample.com
But how can I attach an extra header on the above rewrite so that the javascript would detect that header and show the banner only when that header is present coz the user going directly at app.newexample.com should not see that popup-banner?
The thing is that, when you "rewrite" into URI having protocol and hostname (that is http://app.newexample.com/ in your case), Nginx issues fair HTTP redirect (I guess the code will be 301 aka "permanent redirect"). This leaves you only two mechanisms to transfer any information to the handler of new URL:
cookie
URL itself
Since you are redirecting users to the new domain, cookie is no-go. But even in the case of a common domain I would choose URL to transfer this kind of information, like
server_name app.example.com;
location /app/ {
rewrite ^/app/(.*)$ http://app.newexample.com/$1?from_old=yes;
}
This gives you the freedom to process at either Nginx or in a browser (using JavaScript). You may even do what you wanted intially, issuing a special HTTP header for JavaScript in new app server Nginx configuration:
server_name app.newexample.com;
location /app {
if ($arg_from_old) {
add_header X-From-Old-Site yes;
}
}
A similar problem was discussed here. You can try to use a third-party module HttpHeadersMore (I didn't try it myself). But even if it does not work at all, with the help of this module you can do absolutely everything. Example is here.
Your redirect is missing one thing, the redirect type/code, you should add permanent at the end of your rewrite line, I'm not sure what's the default redirect code if not explicitly mentioned.
rewrite ^/app/(.*)$ http://app.newexample.com/$1 permanent;
An even better way is using return
location /app {
return 301 $scheme://app.newexample.com$request_uri;
}
Adding a get parameter as mentioned above would also be a reliable way to do it, you can easily set a session ( flash ) and redirect again to the page it self but after removing the appended get parameter.
EDIT:
Redirecting doesn't send referrer header, if the old domain is still working you could put a simple php file that does the redirect with a header call.
header("Location: http://app.newexample.com")
One possible solution without any headers would be to check the document.referrer property:
if (document.referrer.indexOf("http://app.example.com") === 0) {
alert("We moved!");
}
Using a 301 will set the referrer to the old page. If the referrer doesn't start with the old page url, it was not directed by that page. Maybe a bit quick n dirty, but should work.

Resources