This page explains how to set up an Apache HTTP Server (httpd) in front of Tomcat on a local machine for development purposes. This page is not intended as a guide for a system administrator to set up a production environment.
At the end you can access the Magnolia contexts with different domains which both serve from root. This kind of setup may help testing multisite scenarios during local development to emulate a production environment scenario.
This page assumes that you are using a Mac or something similar. This is especially true concerning the paths to Apache configuration files. However, the information here should also apply to other OS.
Start with a Tomcat bundle of your choice, for a selection of bundles see list of preconfigured Magnolia bundles. If you want to test multisite scenarios, choose an EE pro bundle (such as magnolia-enterprise-pro-demo-bundle
).
If want to get rid of the demo modules to start with a virginal multisite module - remove the appropriate modules before you start the bundle for the first time. (On magnolia-enterprise-pro-demo-bundle delete the modules starting with magnolia-travel* from the folder magnolia-enterprise-x.y.z/apache-tomcat-8.5.5/webapps/magnoliaAuthor/WEB-INF/lib
).
Before following the steps explained below, start the bundle as usual, to make sure both webapps magnoliaAuthor and magnoliaPublic are installed and work properly.
Domains and /etc/hosts
This is an overview of the the multisite setup:
author instance | public instance | |
---|---|---|
comics | author.best-comics.net | www.best-comics.net |
vinyl | author.best-comics.net | www.best-vinyl.net |
Note that we use only one domain - a subdomain of the "main domain" - to access the author instance (which is recommended practice).
To enable this without DNS, add the following line to your /etc/hosts
file:
127.0.0.1 author.best-comics.net www.best-comics.net www.best-vinyl.net
Apache setup
Make sure you have a working Apache on your local machine.
Helpful Apache commands
Whenever you change Apache configuration files, you have to restart the httpd
process.
Restart the process
sudo apachectl restart
Check the configuration
apachectl configtest
Enable mod_proxy, proxy_ajp_module
Make sure your Apache has the modules following module mod_proxy
and proxy_ajp_module
enabled.
Check the /etc/apache2/httpd.conf
file and make sure the following lines are not commented:
LoadModule proxy_module libexec/apache2/mod_proxy.so # more line in between ... LoadModule proxy_ajp_module libexec/apache2/mod_proxy_ajp.so
On a different OS, the path and suffix of the module may be different.
If you edit the file, you must restart Apache.
Enable vhosts
We use virtual hosts configuration in this setup. You must make sure vhosts
are enabled. Check the /etc/apache2/httpd.conf
file and make sure the line with the include
directive is not commented:
# Virtual hosts Include /private/etc/apache2/extra/httpd-vhosts.conf
Define virtual hosts
We want to redirect requests from <distinct-domain>
to localhost:<port>
for at least one instance.
If vhosts
is properly enabled, edit the /etc/apache2/extra/httpd-vhosts.conf
file and add something similar to this:
<VirtualHost *:80> ServerName author.best-comics.net # ProxyPass / http://localhost:8080/ # ProxyPassReverse / http://localhost:8080/ ProxyPass / ajp://localhost:8009 ProxyPassReverse / ajp://localhost:8009 ErrorLog "/private/var/log/apache2/projekt.local-error_log" CustomLog "/private/var/log/apache2/projekt.local-access_log" common </VirtualHost>
Using ajp
See lines 3, 4 above: At first sight one may think that these ProxyPass
rules should be sufficient. However, it is not. Some things will work, but especially the multisite setup won't do what we expect.
You have to "connect" apache with Tomcat by using the ajp
protocoll. See lines 5,6. (Or alternatively you can use mod_jk
which requires a little bit more configuration, see apache documentation.)
Since we use ajp
- the ajp connector must be configured in the Tomcat server.xml
- which is the case in the default server.xml which is provided by a Magnolia bundle. Look for something like this in your Tomcat server.xml:<Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
Redirecting to Tomcat root
Redirecting to ajp://localhost:8009/magnoliaAuthor - would work, but again, only partially. (Try it out, if you want to have fun.) Tomcat would serve the pages from the context. Web resources would not load and redirections done by Magnolia would be incorrect.
So, yes, we redirect to tomcat on root context, which needs a few modifications on Tomcat too.
Tomcat adjustments to serve one context from root
We want to serve one instance from root to make sure the HTTP response body coming from Tomcat does not contain the context in the paths (etc. pp).
It works. The same can be done with the context magnoliaPublic
instead of magnoliaAuthor
.
Usage in a production environment
In a productive environment, you probably have 2 hosts / servers in different networks, in which one server contains one Tomcat serving a single instance. If this is true, the setup described above is feasible.
Use in a production environment at your own risk. This page is not intended as a guide for a System administrator.
Serve both contexts from root
Now we expand the setup above to make sure we can access the Magnolia instances with the following domains:
author instance | public instance |
---|---|
author.best-comics.net | www.best-comics.net www.best-vinyl.net |
Virtual hosts configuration
We add two more virtual hosts to Apache. Here is the httpd-vhosts.conf
with three virtual hosts, one for the author instance and two for the public instance:
<VirtualHost *:80> ServerName author.best-comics.net ProxyPass / http://localhost:8080/ ProxyPassReverse / http://localhost:8080/ </VirtualHost> <VirtualHost *:80> ServerName www.best-comics.net ProxyPass / http://localhost:8081/ ProxyPassReverse / http://localhost:8081/ </VirtualHost> <VirtualHost *:80> ServerName www.best-vinyl.net ProxyPass / http://localhost:8081/ ProxyPassReverse / http://localhost:8081/ </VirtualHost>
www.best-comics.net
and www.best-vinyl.net
are redirected to localhost on port 8081, whereas author.best-comics.net
redirects to localhost on port 8080.The lines configuring the log files of the virtual hosts have been removed to keep this configuration excerpt small.
Tomcat adjustments
As mentioned above, one Tomcat host cannot serve two contexts from root.
One solution is to have two running Tomcats, however, starting and stoping may be a bit time-consuming.
Instead, we can do the following:
- Define two
<Service>
sections in theserver.xml
. - Each
<Service>
:- Has a
<Connector>
with a distinct port. - Serves from its own
webapps
directory. - Defines one host which wraps exactly one context to be served from root.
- Has a
webapps
directory
We assume that the bundle has already been started once and that both webapps have been properly installed.
This is the adapted Tomcat directory structure:
├── bin ├── conf ├── lib ├── webapps │ ├── ROOT │ └── magnoliaAuthor └── webapps2 └── magnoliaPublic
- Create the folder
webapps2
. - Move the webapp
magnoliaPublic
towebapps2
.
server.xml
This is the server.xml
:
<?xml version="1.0" encoding="UTF-8"?> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <GlobalNamingResources> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" /> <Engine name="Catalina" defaultHost="localhost"> <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="magnoliaAuthor" /> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service> <Service name="Catalina2"> <Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8444" /> <Connector port="8010" enableLookups="false" redirectPort="8444" protocol="AJP/1.3" /> <Engine name="Catalina2" defaultHost="localhost"> <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps2" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="magnoliaPublic" /> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service> </Server>
- There are two
<Service>
sections, theirname
attributes have different values. - Every
<Service>
has its own<Connector>
- Each connector must have its own distinct ports on the attributes
port
andredirectPort
. - The
port
of the<Connector>
is the same port to which we redirect on the Apache virtual host configuration.
Final adjustments on the Magnolia instance
Adjust the subscriber for content activation
To ensure content activation still works, you have to adjust the property /server/activation/subscribers/magnoliaPublic8080@URL:
Node name | Value |
---|---|
server | |
activation | |
subscribers | |
magnoliaPublic8080 | |
subscriptions | |
URL | http://localhost:8081 |