Angular (2+) supports two types of Routing Strategies – HashLocationStrategy and PathLocationStrategy. PathLocationStrategy is the default configuration when you build an application using the angular CLI. PathLocationStrategy is having lot of advantages over the HashLocationStrategy and is the recommended configuration which is discussed in the docs here. This post explains how to use PathLocationStrategy in angular application and deploy it on apache tomcat.

The drawback of PathLocationStrategy is that it needs specific configuration to be done at the server side. If this configuration is not done at the server end, then it leads to 404 when deep links are accessed directly. Also this configuration depends on which server is being used. The main idea is that whenever there is a request for deep links, the server has to return back (or redirect to) index.html of angular application. Then the index.html will request for angular javascript files and then angular will take over the routing to the specific component at the client side itself.

Setting this redirect rule (or fallback to index.html) for various servers like Apache, Nginx, IIS, GitHub pages and Firebase hosting is mentioned here in the angular docs. Unfortunately this doc does not cover the configuration for Apache Tomcat server. In this post we will cover setting the PathLocationStrategy for a demo angular application and its server side configuration for Apache Tomcat server.

Demo

For the demo purpose I have create a sample angular application using the CLI and have uploaded the code on github here.

This application consists of 2 components – HelloWorldComponent and HelloUniverseComponent which are linked to paths "world" and "universe" respectively. The PathLocationStrategy is the default configuration. Also by default <base href="/"> is set in index.html which we do not change. Below are the routing configurations and the index.html content –

~/src/app/app-routing.module.ts -

...
const routes: Routes = [
  { path: 'world', component: HelloWorldComponent },
  { path: 'universe', component: HelloUniverseComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

~/src/index.html -

...
<head>
  <meta charset="utf-8">
  <title>TomcatDeploymentDemo</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
...

These are the only setup needed (which is set by default by CLI) on the client side of the application. To build and deploy the demo application on tomcat in the context path – “hello“, make use of the --base-href option of ng build command as below –

ng build --base-href /hello/

This will generate the build under ~/dist/tomcat-deployment-demo directory. Copy all the files under this to the tomcat server location – ~/webapps/hello and start the tomcat server. I have my tomcat running on local machine on port 8080. The application can now be accessed with the URL – http://localhost:8080/hello as seen below –

sample application running on apache tomcat at context path - /hello/
sample application running on apache tomcat at context path – /hello/

Deep linking issue

Deep linking issue is when you hit the deep links inside the angular application (http://localhost:8080/hello/world and http://localhost:8080/hello/universe), but the server returns 404 instead of the angular application as seen below –

/hello/world is returning 404 - deep linking issue
/hello/world is returning 404 – deep linking issue
/hello/universe is returning 404 - deep linking issue
/hello/universe is returning 404 – deep linking issue

Solution

The solution for this is to setup the tomcat to redirect any deep links of the angular application (ie. http://localhost:8080/hello/*) to point to the index.html of the application (ie. http://localhost:8080/hello/index.html). This involves 2 steps –

  1. Configure the RewriteValve in server.xml
  2. Write the rewrite rule in rewrite.config
1. Configure the RewriteValve in server.xml

Edit the ~/conf/server.xml to add the below Valve inside the Host section as below –

...
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />

...
      </Host>
...
2. Write the rewrite rule in rewrite.config

Create directory structure – ~/conf/Catalina/localhost/ and create the rewrite.config file inside it with the below content –

RewriteCond %{REQUEST_PATH} !-f
RewriteRule ^/hello/(.*) /hello/index.html

After setting this up restart the tomcat server and you can hit the deep links of the application which will route to the correct components inside the angular application.

after rewrite rules are added, the deep link /hello/world is working and routing to correct component
after rewrite rules are added, the deep link /hello/world is working and routing to correct component
deep link /hello/universe is also working
deep link /hello/universe is also working

  • Sample application used in this demo is in – github
  • Tomcat config is tested for versions – 9.0.17 and 8.5.39
  • server.xml and rewrite.config files for various versions of tomcat are uploaded here for reference

19 thoughts on “Fixing deep linking issue – Deploying angular application on Tomcat server

  1. sushi by 7-11 says:

    Hey just wanted to give you a quick heads up. The text in your
    content seem to be running off the screen in Internet explorer.
    I’m not sure if this is a format issue or something to do with web browser compatibility
    but I figured I’d post to let you know. The style and design look great though!

    Hope you get the issue resolved soon. Kudos

    1. Thanks for letting me know. Will try to fix the IE issue.

  2. Rahul Raj says:

    Hi Nithin,
    Your solution is working but it is always redirecting to landing page of the angular application instead of requested url

    1. Hi Rahul, I cannot help without more information. But this may be because your application is not storing the session. So next time when you directly access the deep link, it thinks you are not logged in and is probably redirecting you to the login/landing page.

  3. Anonymous says:

    Awesome article.

  4. Situs says:

    Way cool! Some very valid points! I appreciate you penning this post and also the rest of the website is
    also really good.

  5. p7823 says:

    Thanks for your marvelous posting! I certainly enjoyed reading
    it, you are a great author. I will remember to bookmark your
    blog and will often come back sometime soon. I want to encourage
    you continue your great posts, have a nice day!

  6. Miniloco says:

    Hey very nice blog!

  7. p6101 says:

    Keep this going please, great job!

  8. Marvin says:

    I must thank you for the efforts you have put in penning this website.
    I really hope to check out the same high-grade content from you in the future as well.
    In truth, your creative writing abilities has inspired me
    to get my own, personal website now πŸ˜‰

  9. Pingback: vikasbgorle
  10. Thomas says:

    Great article! Thank you πŸ™‚

  11. Neetesh Vishwakarma says:

    Hi Nithin,

    I am using Tomcat 7.0.81. above solution doesn’t working for version 7.
    Could you please help me with this. My Angular version is 4

    Thanks in Advance.

    1. Hi Neetesh, you can try this out. I do not have a setup currently to verify it. Maybe you can try it and post your findings here.

  12. Dilip H says:

    Hey Nithin,
    Thanks a lot, your solution helped a lot in resolving this major problem and it is working on IE, Chrome very smoothly.
    Also it would be great help if you give some guidelines about how to use DOMAIN name to access website instead of localhost server ip as I am not getting any solution for this in angular app.

    1. If you want to use domain name on your local setup, then you can make appropriate host file entries for that.

  13. Lukman Arogundade says:

    Great article, many thanks.

  14. AntonioH says:

    Hi, thanks. Do you know how to deploy some angular apps in the same tomcat?

Leave a Reply

Your email address will not be published. Required fields are marked *