Reverse Proxying an angular-cli SPA with Apache and Tomcat
It’s always beneficial to have your development environment closely mirror your production one, and thanks to tools like Docker it’s quite easy to set it up nowadays. In this post we will learn how to set up a dev environment for an Angular 4 application, backed by an api served with Tomcat fronted by Apache. If my production Angular app was served available at http://www.production.com , and the backing api at http://www.production.com/api, my goal would be to replicate the same set up for my local dev environment, so have my front-end
being served at http://www.production.dev/app and api
at http://www.production.dev/api. I would want to I will be making the following assumptions:
- an Apache-2.4 web server running on port 80, configured for the domain http://production.dev/, with the modules mod_proxy and mod_proxy_http enabled
- a Tomcat-8.5.27 api server running on port 8080 that is accessible on http://production.dev:8080/api.
- An angular-cli (v1.3.2) Angular 4 application running in dev with
ng serve
that is normally available by default at http://localhost:4200.
As a developer I wanted both my Angular and API application to be able to be accessible from a production.dev domain when developing locally. There are three separate areas to configure to make it happen.
Custom Domain
In order to be able to access the production.dev address, I set up a custom domain in my Mac’s etc/hosts
file. This maps my default localhost address to this custom domain:
127.0.0.1 production.dev
Apache
The first thing you will need is to configure Apache to reverse proxy both the Angular (app)and the Tomcat (api)applications. A representative httpd.conf
would look like:
<IfModule mod_proxy.c>
ProxyRequests Off
ProxyVia Off
ProxyPreserveHost On ProxyStatus On ProxyPass /api http://localhost:8090/api
ProxyPassReverse /api http://localhost:8090/api
ProxyPassReverseCookiePath /api /
ProxyPass /app http://localhost:4200/app/
ProxyPassReverse /app http://localhost:4200/app/
</IfModule>
This sets up Apache to forward requests from /api
to our Tomcat api app instance.
In your httpd.conf:
make sure to enable mod_proxy
....
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
...
LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
....
You can also set it up in the exact same way if you are using Virtual Hosts. You’ll notice that the Tomcat port is 8090
which is not the default Tomcat port, which leads me to the next configuration.
Tomcat
In my case I wanted my app to have the context path of api
since it would be served from the same domain as my front end app. So my server.xml
configuration was updated to contain a Context
entry. I will not add it here since it was done through configuring my IntelliJ configuration but my app was available after a local deploy at http://production.dev/api. You’ll need to create a new connector for your app for the proxying to work. A sample configuration would be :
<Connector port="8090"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="48"
minSpareThreads="10"
enableLookups="false"
acceptCount="10"
debug="0"
URIEncoding="UTF-8"
protocol="org.apache.coyote.http11.Http11NioProtocol"
proxyName="production.dev"
proxyPort="80"
scheme="http"/>
proxyPort
is the important configuration here, it allows you application to reflect the port being proxied (80) rather than the port it is running on (8090).
Angular
In order for this setup to work locally, I had to set up local proxying made enabled by the proxy feature of the webpack-dev-server that powers the angular-cli. I was getting 404s when using the http://production.dev/app
url to access my Angular app when it was served through ng serve — host production.dev.
In order to resolve this I had to add to add a proxy configuration for my app like this in a newproxy.conf.json
in my app’s root directory :
{"/app/**": {"target": "http://production.dev:4200/","secure":false,"logLevel":"debug","pathRewrite": { "^/app": "" }}}
With that configuration in place, i ran my ng serve as
ng serve --host production.dev --proxy-config proxy.conf.json --base-href /app/
The base-href
option is important in this case it allows us to specify the base url of the application which is app
in this case.
This completes the local setup of a development environment to try and mirror production domain wise using Angular, Apache and Tomcat. In the case of Angular you might need the deploy-url
option to be specified with the ng serve
to get this to work.