25

I'm serving multiple angular apps from the same server block in Nginx. So in order to let the user browse directly to certain custom Angular routes I've declared without having to go through the home page (and avoid the 404 page), I'm forwarding these routes from nginx to each angular app's index.html, I've added a try_files to each location:

server {
    listen 80;
    server_name website.com;

    # project1
    location / {
        alias /home/hakim/project1/dist/;
        try_files $uri /index.html;
    }

    # project2
    location /project2/ {
        alias /home/hakim/project2/dist/;
        try_files $uri /index.html;
    }

    # project3
    location /project3/ {
        alias /home/hakim/project3/dist/;
        try_files $uri /index.html;
    }
}

This solution avoids the 404 error when going to an Angular route, but the problem is that when I browse to /project2/ or /project3/ it redirects to the /project1/. That's obviously not what is expected, since I want to have each location to forward to the /project-i/index.html of the adequate project.

3
  • You click on a link to project2 from inside project1. and that doesn't work, correct? Commented Jan 6, 2018 at 10:55
  • 1
    Exactly, but even if I browse directly to website/project2, it goes to project1. Commented Jan 6, 2018 at 11:00
  • 1
    You need to use base href maybe Commented Jan 6, 2018 at 11:05

7 Answers 7

19

Hope this helps someone

Step 1 - Build all your projects

ng build --prod --base-href /project1/
ng build --prod --base-href /project2/
ng build --prod --base-href /project3/

Step 2 - Configure your nginx, note the change added in try_files section

server {
    listen 80;
    server_name website.com;

    # project1
    location / {
        alias /home/hakim/project1/dist/;
        try_files $uri/ /project1/index.html;
    }

    # project2
    location /project2/ {
        alias /home/hakim/project2/dist/;
        try_files $uri/ /project2/index.html;
    }

    # project3
    location /project3/ {
        alias /home/hakim/project3/dist/;
        try_files $uri/ /project3/index.html;
    }
}

Step 3 - Reload nginx configuration

sudo service nginx reload
Sign up to request clarification or add additional context in comments.

1 Comment

can you share a link on this?
7
+50

It is generally a bad security practice to have multiple independent apps on a single domain.

However, I believe what you're facing here is the peculiarity of the way that try_files works -- according to http://nginx.org/r/try_files,

If none of the files were found, an internal redirect to the uri specified in the last parameter is made.

Effectively, this means that if there would have been an extra parameter after your /index.html specification (i.e., basically, anything at all), then your code would have worked as you expected; however, due to the lack of any such final parameter, what happens in each case is that everything gets redirected back to the / location, as if a GET /index.html HTTP/1.1 request was to have been made (except it's all done internally within nginx).

So, as a solution, you can either fix the path for the internal redirect to remain within the same location (e.g., /projectX/index.html), or leave the paths alone, but make the last parameter return an error code (e.g., =404, which should never be triggered as long as your file always exists).

  • E.g, try_files $uri /projectX/index.html;,

  • Or, try_files $uri /index.html =404;.

As in:

location /projectX/ {
    alias /home/projectX/dist/;
    try_files $uri /projectX/index.html; # last param is internal redirect
}

Or:

location /projectX/ {
    alias /home/projectX/dist/;
    try_files $uri /index.html =404;
}

In summary, note well that /projectX/index.html would only work as the last parameter, and /index.html would only work as a non-final one.

6 Comments

You answer was the closest to how I've solved it. I've actually left the location for project1 as it was, while in the try_files in project2 and project3 I had to add in their try_files's index.html, the prefix project-i. So it became as the following for project2 and project3: try_files $uri /project[2-3]/index.html
@h4k1m, great that it works! Regarding "the closest", TBH, I don't see how your solution is any different from what I wrote above. :-p (The other answers are obviously totally wrong -- I never suggested (nor meant to imply) doing any changes for project1.)
Could you please just mention that the modifications done on location /projectX/, should only be carried out on project2 and project3 (that's what I meant by closest, because when I read it I thought I had to change even the location of the first project).
Curious to know the security issue involved with multiple files in the same domain. Can you kindly explain?
@Nobody it has to do with Cookies, JavaScript and XSS (Cross-Site Scripting) attacks. If you use a single domain, the browser treats all apps as the same app, so, vulnerability in one app, makes all the rest of them vulnerable just as much.
|
2

This code works for me:

server {
    listen port_number;
    server_name ip_addreess_or_domain;

    location project-1 { // without forward slash the last of the location name
       alias /var/www/project-1/;
       try_files $uri $uri/ /project-1/index.html;
    }

    location project-2 { // without forward slash the last of the location name
       alias /var/www/project-2/;
       try_files $uri $uri/ /project-2/index.html;
    } 
}

Comments

1

Try building you apps using --base.href=/projectx/ for example:

ng build --base.href=/project1/
ng build --base.href=/project2/
ng build --base.href=/project3/

Comments

1

Try the solution for multilingual Angular application AOT builds that are basically different apps - OK its the same app multiple times, build with different languages in different bundles in different directories.

Comments

0

Try adding to project 2:

<base href="/project2">

3 Comments

I've changed href="/" to href="/project2" in project2/dist/index.html, but it doesn't seem to fix it.
Did anything change when you added that?
The behaviour is exactly the same (redirect to /project1).
0

Change the first location to:

# project1
location /project1/ {
    alias /home/hakim/project1/dist/;
    try_files $uri /index.html;
}

The current block matches all '/' and it's the first thing that matches the request.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.